Unified · Split
| @@ -44,6 +44,18 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON) · 43 unmodified lines | |||
| 44 | # Instruct CMake to run moc automatically when needed. | 44 | # Instruct CMake to run moc automatically when needed. |
| 45 | set(CMAKE_AUTOMOC ON) | 45 | set(CMAKE_AUTOMOC ON) |
| 46 | 46 | ||
| 47 | set(HIFI_LIBRARY_DIR "${CMAKE_CURRENT_SOURCE_DIR}/libraries") | ||
| 48 | |||
| 49 | # setup for find modules | ||
| 50 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules/") | ||
| 51 | |||
| 52 | set(MACRO_DIR "${CMAKE_CURRENT_SOURCE_DIR}/cmake/macros") | ||
| 53 | |||
| 54 | file(GLOB HIFI_CUSTOM_MACROS "cmake/macros/*.cmake") | ||
| 55 | foreach(CUSTOM_MACRO ${HIFI_CUSTOM_MACROS}) | ||
| 56 | include(${CUSTOM_MACRO}) | ||
| 57 | endforeach() | ||
| 58 | |||
| 47 | # targets on all platforms | 59 | # targets on all platforms |
| 48 | add_subdirectory(assignment-client) | 60 | add_subdirectory(assignment-client) |
| 49 | add_subdirectory(domain-server) | 61 | add_subdirectory(domain-server) |
| @@ -1,47 +1,17 @@ | |||
| 1 | set(TARGET_NAME assignment-client) | 1 | set(TARGET_NAME assignment-client) |
| 2 | 2 | ||
| 3 | set(ROOT_DIR ..) | 3 | setup_hifi_project(Core Gui Network Script Widgets) |
| 4 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 5 | 4 | ||
| 6 | # setup for find modules | 5 | include_glm() |
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") | ||
| 8 | |||
| 9 | find_package(Qt5 COMPONENTS Network Script Widgets) | ||
| 10 | |||
| 11 | include("${MACRO_DIR}/SetupHifiProject.cmake") | ||
| 12 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 13 | |||
| 14 | # include glm | ||
| 15 | include("${MACRO_DIR}/IncludeGLM.cmake") | ||
| 16 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 17 | 6 | ||
| 18 | # link in the shared libraries | 7 | # link in the shared libraries |
| 19 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 8 | link_hifi_libraries( |
| 20 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | 9 | audio avatars octree voxels fbx particles entities metavoxels |
| 21 | link_hifi_library(audio ${TARGET_NAME} "${ROOT_DIR}") | 10 | networking animation shared script-engine embedded-webserver |
| 22 | link_hifi_library(avatars ${TARGET_NAME} "${ROOT_DIR}") | 11 | ) |
| 23 | link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") | ||
| 24 | link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 25 | link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") | ||
| 26 | link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}") | ||
| 27 | link_hifi_library(entities ${TARGET_NAME} "${ROOT_DIR}") | ||
| 28 | link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 29 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 30 | link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") | ||
| 31 | link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}") | ||
| 32 | link_hifi_library(embedded-webserver ${TARGET_NAME} "${ROOT_DIR}") | ||
| 33 | 12 | ||
| 34 | if (UNIX) | 13 | if (UNIX) |
| 35 | target_link_libraries(${TARGET_NAME} ${CMAKE_DL_LIBS}) | 14 | list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${CMAKE_DL_LIBS}) |
| 36 | endif (UNIX) | 15 | endif (UNIX) |
| 37 | 16 | ||
| 38 | IF (WIN32) | 17 | link_shared_dependencies() |
| 39 | target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 40 | ENDIF(WIN32) | ||
| 41 | |||
| 42 | target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) | ||
| 43 | |||
| 44 | # add a definition for ssize_t so that windows doesn't bail | ||
| 45 | if (WIN32) | ||
| 46 | add_definitions(-Dssize_t=long) | ||
| 47 | endif () | ||
| @@ -115,7 +115,7 @@ void Agent::readPendingDatagrams() { · 114 unmodified lines | |||
| 115 | sourceNode->setLastHeardMicrostamp(usecTimestampNow()); | 115 | sourceNode->setLastHeardMicrostamp(usecTimestampNow()); |
| 116 | 116 | ||
| 117 | QByteArray mutablePacket = receivedPacket; | 117 | QByteArray mutablePacket = receivedPacket; |
| 118 | ssize_t messageLength = mutablePacket.size(); | 118 | int messageLength = mutablePacket.size(); |
| 119 | 119 | ||
| 120 | if (datagramPacketType == PacketTypeOctreeStats) { | 120 | if (datagramPacketType == PacketTypeOctreeStats) { |
| 121 | 121 | ||
| @@ -37,6 +37,7 @@ · 36 unmodified lines | |||
| 37 | #include <QtCore/QJsonDocument> | 37 | #include <QtCore/QJsonDocument> |
| 38 | #include <QtCore/QJsonObject> | 38 | #include <QtCore/QJsonObject> |
| 39 | #include <QtCore/QJsonValue> | 39 | #include <QtCore/QJsonValue> |
| 40 | #include <QtCore/QThread> | ||
| 40 | #include <QtCore/QTimer> | 41 | #include <QtCore/QTimer> |
| 41 | #include <QtNetwork/QNetworkRequest> | 42 | #include <QtNetwork/QNetworkRequest> |
| 42 | #include <QtNetwork/QNetworkReply> | 43 | #include <QtNetwork/QNetworkReply> |
| @@ -52,6 +53,7 @@ · 9 unmodified lines | |||
| 52 | 53 | ||
| 53 | #include "AudioRingBuffer.h" | 54 | #include "AudioRingBuffer.h" |
| 54 | #include "AudioMixerClientData.h" | 55 | #include "AudioMixerClientData.h" |
| 56 | #include "AudioMixerDatagramProcessor.h" | ||
| 55 | #include "AvatarAudioStream.h" | 57 | #include "AvatarAudioStream.h" |
| 56 | #include "InjectedAudioStream.h" | 58 | #include "InjectedAudioStream.h" |
| 57 | 59 | ||
| @@ -71,6 +73,8 @@ bool AudioMixer::_useDynamicJitterBuffers = false; · 13 unmodified lines | |||
| 71 | int AudioMixer::_staticDesiredJitterBufferFrames = 0; | 73 | int AudioMixer::_staticDesiredJitterBufferFrames = 0; |
| 72 | int AudioMixer::_maxFramesOverDesired = 0; | 74 | int AudioMixer::_maxFramesOverDesired = 0; |
| 73 | 75 | ||
| 76 | bool AudioMixer::_printStreamStats = false; | ||
| 77 | |||
| 74 | AudioMixer::AudioMixer(const QByteArray& packet) : | 78 | AudioMixer::AudioMixer(const QByteArray& packet) : |
| 75 | ThreadedAssignment(packet), | 79 | ThreadedAssignment(packet), |
| 76 | _trailingSleepRatio(1.0f), | 80 | _trailingSleepRatio(1.0f), |
| @@ -295,38 +299,34 @@ void AudioMixer::prepareMixForListeningNode(Node* node) { · 218 unmodified lines | |||
| 295 | } | 299 | } |
| 296 | } | 300 | } |
| 297 | 301 | ||
| 298 | void AudioMixer::readPendingDatagrams() { | 302 | void AudioMixer::readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr) { |
| 299 | QByteArray receivedPacket; | ||
| 300 | HifiSockAddr senderSockAddr; | ||
| 301 | NodeList* nodeList = NodeList::getInstance(); | 303 | NodeList* nodeList = NodeList::getInstance(); |
| 302 | 304 | ||
| 303 | while (readAvailableDatagram(receivedPacket, senderSockAddr)) { | 305 | if (nodeList->packetVersionAndHashMatch(receivedPacket)) { |
| 304 | if (nodeList->packetVersionAndHashMatch(receivedPacket)) { | 306 | // pull any new audio data from nodes off of the network stack |
| 305 | // pull any new audio data from nodes off of the network stack | 307 | PacketType mixerPacketType = packetTypeForPacket(receivedPacket); |
| 306 | PacketType mixerPacketType = packetTypeForPacket(receivedPacket); | 308 | if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho |
| 307 | if (mixerPacketType == PacketTypeMicrophoneAudioNoEcho | 309 | || mixerPacketType == PacketTypeMicrophoneAudioWithEcho |
| 308 | || mixerPacketType == PacketTypeMicrophoneAudioWithEcho | 310 | || mixerPacketType == PacketTypeInjectAudio |
| 309 | || mixerPacketType == PacketTypeInjectAudio | 311 | || mixerPacketType == PacketTypeSilentAudioFrame |
| 310 | || mixerPacketType == PacketTypeSilentAudioFrame | 312 | || mixerPacketType == PacketTypeAudioStreamStats) { |
| 311 | || mixerPacketType == PacketTypeAudioStreamStats) { | 313 | |
| 312 | 314 | nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); | |
| 313 | nodeList->findNodeAndUpdateWithDataFromPacket(receivedPacket); | 315 | } else if (mixerPacketType == PacketTypeMuteEnvironment) { |
| 314 | } else if (mixerPacketType == PacketTypeMuteEnvironment) { | 316 | QByteArray packet = receivedPacket; |
| 315 | QByteArray packet = receivedPacket; | 317 | populatePacketHeader(packet, PacketTypeMuteEnvironment); |
| 316 | populatePacketHeader(packet, PacketTypeMuteEnvironment); | 318 | |
| 317 | 319 | foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { | |
| 318 | foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { | 320 | if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) { |
| 319 | if (node->getType() == NodeType::Agent && node->getActiveSocket() && node->getLinkedData() && node != nodeList->sendingNodeForPacket(receivedPacket)) { | 321 | nodeList->writeDatagram(packet, packet.size(), node); |
| 320 | nodeList->writeDatagram(packet, packet.size(), node); | ||
| 321 | } | ||
| 322 | } | 322 | } |
| 323 | |||
| 324 | } else { | ||
| 325 | // let processNodeData handle it. | ||
| 326 | nodeList->processNodeData(senderSockAddr, receivedPacket); | ||
| 327 | } | 323 | } |
| 324 | |||
| 325 | } else { | ||
| 326 | // let processNodeData handle it. | ||
| 327 | nodeList->processNodeData(senderSockAddr, receivedPacket); | ||
| 328 | } | 328 | } |
| 329 | } | 329 | } |
| 330 | } | 330 | } |
| 331 | 331 | ||
| 332 | void AudioMixer::sendStatsPacket() { | 332 | void AudioMixer::sendStatsPacket() { |
| @@ -390,7 +390,35 @@ void AudioMixer::run() { · 57 unmodified lines | |||
| 390 | ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer); | 390 | ThreadedAssignment::commonInit(AUDIO_MIXER_LOGGING_TARGET_NAME, NodeType::AudioMixer); |
| 391 | 391 | ||
| 392 | NodeList* nodeList = NodeList::getInstance(); | 392 | NodeList* nodeList = NodeList::getInstance(); |
| 393 | 393 | ||
| 394 | // we do not want this event loop to be the handler for UDP datagrams, so disconnect | ||
| 395 | disconnect(&nodeList->getNodeSocket(), 0, this, 0); | ||
| 396 | |||
| 397 | // setup a QThread with us as parent that will house the AudioMixerDatagramProcessor | ||
| 398 | _datagramProcessingThread = new QThread(this); | ||
| 399 | |||
| 400 | // create an AudioMixerDatagramProcessor and move it to that thread | ||
| 401 | AudioMixerDatagramProcessor* datagramProcessor = new AudioMixerDatagramProcessor(nodeList->getNodeSocket(), thread()); | ||
| 402 | datagramProcessor->moveToThread(_datagramProcessingThread); | ||
| 403 | |||
| 404 | // remove the NodeList as the parent of the node socket | ||
| 405 | nodeList->getNodeSocket().setParent(NULL); | ||
| 406 | nodeList->getNodeSocket().moveToThread(_datagramProcessingThread); | ||
| 407 | |||
| 408 | // let the datagram processor handle readyRead from node socket | ||
| 409 | connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, | ||
| 410 | datagramProcessor, &AudioMixerDatagramProcessor::readPendingDatagrams); | ||
| 411 | |||
| 412 | // connect to the datagram processing thread signal that tells us we have to handle a packet | ||
| 413 | connect(datagramProcessor, &AudioMixerDatagramProcessor::packetRequiresProcessing, this, &AudioMixer::readPendingDatagram); | ||
| 414 | |||
| 415 | // delete the datagram processor and the associated thread when the QThread quits | ||
| 416 | connect(_datagramProcessingThread, &QThread::finished, datagramProcessor, &QObject::deleteLater); | ||
| 417 | connect(datagramProcessor, &QObject::destroyed, _datagramProcessingThread, &QThread::deleteLater); | ||
| 418 | |||
| 419 | // start the datagram processing thread | ||
| 420 | _datagramProcessingThread->start(); | ||
| 421 | |||
| 394 | nodeList->addNodeTypeToInterestSet(NodeType::Agent); | 422 | nodeList->addNodeTypeToInterestSet(NodeType::Agent); |
| 395 | 423 | ||
| 396 | nodeList->linkedDataCreateCallback = attachNewNodeDataToNode; | 424 | nodeList->linkedDataCreateCallback = attachNewNodeDataToNode; |
| @@ -448,7 +476,11 @@ void AudioMixer::run() { · 51 unmodified lines | |||
| 448 | } | 476 | } |
| 449 | qDebug() << "Max frames over desired:" << _maxFramesOverDesired; | 477 | qDebug() << "Max frames over desired:" << _maxFramesOverDesired; |
| 450 | 478 | ||
| 451 | 479 | const QString PRINT_STREAM_STATS_JSON_KEY = "H-print-stream-stats"; | |
| 480 | _printStreamStats = audioGroupObject[PRINT_STREAM_STATS_JSON_KEY].toBool(); | ||
| 481 | if (_printStreamStats) { | ||
| 482 | qDebug() << "Stream stats will be printed to stdout"; | ||
| 483 | } | ||
| 452 | 484 | ||
| 453 | const QString UNATTENUATED_ZONE_KEY = "D-unattenuated-zone"; | 485 | const QString UNATTENUATED_ZONE_KEY = "D-unattenuated-zone"; |
| 454 | 486 | ||
| @@ -547,6 +579,7 @@ void AudioMixer::run() { · 92 unmodified lines | |||
| 547 | sendAudioStreamStats = true; | 579 | sendAudioStreamStats = true; |
| 548 | } | 580 | } |
| 549 | 581 | ||
| 582 | bool streamStatsPrinted = false; | ||
| 550 | foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { | 583 | foreach (const SharedNodePointer& node, nodeList->getNodeHash()) { |
| 551 | if (node->getLinkedData()) { | 584 | if (node->getLinkedData()) { |
| 552 | AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData(); | 585 | AudioMixerClientData* nodeData = (AudioMixerClientData*)node->getLinkedData(); |
| @@ -581,12 +614,21 @@ void AudioMixer::run() { · 28 unmodified lines | |||
| 581 | // send an audio stream stats packet if it's time | 614 | // send an audio stream stats packet if it's time |
| 582 | if (sendAudioStreamStats) { | 615 | if (sendAudioStreamStats) { |
| 583 | nodeData->sendAudioStreamStatsPackets(node); | 616 | nodeData->sendAudioStreamStatsPackets(node); |
| 617 | |||
| 618 | if (_printStreamStats) { | ||
| 619 | printf("\nStats for agent %s:\n", node->getUUID().toString().toLatin1().data()); | ||
| 620 | nodeData->printUpstreamDownstreamStats(); | ||
| 621 | streamStatsPrinted = true; | ||
| 622 | } | ||
| 584 | } | 623 | } |
| 585 | 624 | ||
| 586 | ++_sumListeners; | 625 | ++_sumListeners; |
| 587 | } | 626 | } |
| 588 | } | 627 | } |
| 589 | } | 628 | } |
| 629 | if (streamStatsPrinted) { | ||
| 630 | printf("\n----------------------------------------------------------------\n"); | ||
| 631 | } | ||
| 590 | 632 | ||
| 591 | ++_numStatFrames; | 633 | ++_numStatFrames; |
| 592 | 634 | ||
| @@ -33,7 +33,8 @@ public slots: · 32 unmodified lines | |||
| 33 | /// threaded run of assignment | 33 | /// threaded run of assignment |
| 34 | void run(); | 34 | void run(); |
| 35 | 35 | ||
| 36 | void readPendingDatagrams(); | 36 | void readPendingDatagrams() { }; // this will not be called since our datagram processing thread will handle |
| 37 | void readPendingDatagram(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); | ||
| 37 | 38 | ||
| 38 | void sendStatsPacket(); | 39 | void sendStatsPacket(); |
| 39 | 40 | ||
| @@ -66,6 +67,8 @@ private: · 26 unmodified lines | |||
| 66 | static int _staticDesiredJitterBufferFrames; | 67 | static int _staticDesiredJitterBufferFrames; |
| 67 | static int _maxFramesOverDesired; | 68 | static int _maxFramesOverDesired; |
| 68 | 69 | ||
| 70 | static bool _printStreamStats; | ||
| 71 | |||
| 69 | quint64 _lastSendAudioStreamStatsTime; | 72 | quint64 _lastSendAudioStreamStatsTime; |
| 70 | }; | 73 | }; |
| 71 | 74 | ||
| @@ -22,7 +22,8 @@ · 21 unmodified lines | |||
| 22 | 22 | ||
| 23 | AudioMixerClientData::AudioMixerClientData() : | 23 | AudioMixerClientData::AudioMixerClientData() : |
| 24 | _audioStreams(), | 24 | _audioStreams(), |
| 25 | _outgoingMixedAudioSequenceNumber(0) | 25 | _outgoingMixedAudioSequenceNumber(0), |
| 26 | _downstreamAudioStreamStats() | ||
| 26 | { | 27 | { |
| 27 | } | 28 | } |
| 28 | 29 | ||
| @@ -263,3 +264,45 @@ QString AudioMixerClientData::getAudioStreamStatsString() const { · 234 unmodified lines | |||
| 263 | } | 264 | } |
| 264 | return result; | 265 | return result; |
| 265 | } | 266 | } |
| 267 | |||
| 268 | void AudioMixerClientData::printUpstreamDownstreamStats() const { | ||
| 269 | // print the upstream (mic stream) stats if the mic stream exists | ||
| 270 | if (_audioStreams.contains(QUuid())) { | ||
| 271 | printf("Upstream:\n"); | ||
| 272 | printAudioStreamStats(_audioStreams.value(QUuid())->getAudioStreamStats()); | ||
| 273 | } | ||
| 274 | // print the downstream stats if they contain valid info | ||
| 275 | if (_downstreamAudioStreamStats._packetStreamStats._received > 0) { | ||
| 276 | printf("Downstream:\n"); | ||
| 277 | printAudioStreamStats(_downstreamAudioStreamStats); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | void AudioMixerClientData::printAudioStreamStats(const AudioStreamStats& streamStats) const { | ||
| 282 | printf(" Packet loss | overall: %5.2f%% (%d lost), last_30s: %5.2f%% (%d lost)\n", | ||
| 283 | streamStats._packetStreamStats.getLostRate() * 100.0f, | ||
| 284 | streamStats._packetStreamStats._lost, | ||
| 285 | streamStats._packetStreamWindowStats.getLostRate() * 100.0f, | ||
| 286 | streamStats._packetStreamWindowStats._lost); | ||
| 287 | |||
| 288 | printf(" Ringbuffer frames | desired: %u, avg_available(10s): %u, available: %u\n", | ||
| 289 | streamStats._desiredJitterBufferFrames, | ||
| 290 | streamStats._framesAvailableAverage, | ||
| 291 | streamStats._framesAvailable); | ||
| 292 | |||
| 293 | printf(" Ringbuffer stats | starves: %u, prev_starve_lasted: %u, frames_dropped: %u, overflows: %u\n", | ||
| 294 | streamStats._starveCount, | ||
| 295 | streamStats._consecutiveNotMixedCount, | ||
| 296 | streamStats._framesDropped, | ||
| 297 | streamStats._overflowCount); | ||
| 298 | |||
| 299 | printf(" Inter-packet timegaps (overall) | min: %9s, max: %9s, avg: %9s\n", | ||
| 300 | formatUsecTime(streamStats._timeGapMin).toLatin1().data(), | ||
| 301 | formatUsecTime(streamStats._timeGapMax).toLatin1().data(), | ||
| 302 | formatUsecTime(streamStats._timeGapAverage).toLatin1().data()); | ||
| 303 | |||
| 304 | printf(" Inter-packet timegaps (last 30s) | min: %9s, max: %9s, avg: %9s\n", | ||
| 305 | formatUsecTime(streamStats._timeGapWindowMin).toLatin1().data(), | ||
| 306 | formatUsecTime(streamStats._timeGapWindowMax).toLatin1().data(), | ||
| 307 | formatUsecTime(streamStats._timeGapWindowAverage).toLatin1().data()); | ||
| 308 | } | ||
| @@ -38,6 +38,11 @@ public: · 37 unmodified lines | |||
| 38 | void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; } | 38 | void incrementOutgoingMixedAudioSequenceNumber() { _outgoingMixedAudioSequenceNumber++; } |
| 39 | quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; } | 39 | quint16 getOutgoingSequenceNumber() const { return _outgoingMixedAudioSequenceNumber; } |
| 40 | 40 | ||
| 41 | void printUpstreamDownstreamStats() const; | ||
| 42 | |||
| 43 | private: | ||
| 44 | void printAudioStreamStats(const AudioStreamStats& streamStats) const; | ||
| 45 | |||
| 41 | private: | 46 | private: |
| 42 | QHash<QUuid, PositionalAudioStream*> _audioStreams; // mic stream stored under key of null UUID | 47 | QHash<QUuid, PositionalAudioStream*> _audioStreams; // mic stream stored under key of null UUID |
| 43 | 48 | ||
| @@ -0,0 +1,47 @@ | |||
| 1 | // | ||
| 2 | // AudioMixerDatagramProcessor.cpp | ||
| 3 | // assignment-client/src | ||
| 4 | // | ||
| 5 | // Created by Stephen Birarda on 2014-08-14. | ||
| 6 | // Copyright 2014 High Fidelity, Inc. | ||
| 7 | // | ||
| 8 | // Distributed under the Apache License, Version 2.0. | ||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | // | ||
| 11 | |||
| 12 | #include <QDebug> | ||
| 13 | |||
| 14 | #include <HifiSockAddr.h> | ||
| 15 | #include <NodeList.h> | ||
| 16 | |||
| 17 | #include "AudioMixerDatagramProcessor.h" | ||
| 18 | |||
| 19 | AudioMixerDatagramProcessor::AudioMixerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread) : | ||
| 20 | _nodeSocket(nodeSocket), | ||
| 21 | _previousNodeSocketThread(previousNodeSocketThread) | ||
| 22 | { | ||
| 23 | |||
| 24 | } | ||
| 25 | |||
| 26 | AudioMixerDatagramProcessor::~AudioMixerDatagramProcessor() { | ||
| 27 | // return the node socket to its previous thread | ||
| 28 | _nodeSocket.moveToThread(_previousNodeSocketThread); | ||
| 29 | } | ||
| 30 | |||
| 31 | void AudioMixerDatagramProcessor::readPendingDatagrams() { | ||
| 32 | |||
| 33 | HifiSockAddr senderSockAddr; | ||
| 34 | static QByteArray incomingPacket; | ||
| 35 | |||
| 36 | // read everything that is available | ||
| 37 | while (_nodeSocket.hasPendingDatagrams()) { | ||
| 38 | incomingPacket.resize(_nodeSocket.pendingDatagramSize()); | ||
| 39 | |||
| 40 | // just get this packet off the stack | ||
| 41 | _nodeSocket.readDatagram(incomingPacket.data(), incomingPacket.size(), | ||
| 42 | senderSockAddr.getAddressPointer(), senderSockAddr.getPortPointer()); | ||
| 43 | |||
| 44 | // emit the signal to tell AudioMixer it needs to process a packet | ||
| 45 | emit packetRequiresProcessing(incomingPacket, senderSockAddr); | ||
| 46 | } | ||
| 47 | } | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | // | ||
| 2 | // AudioMixerDatagramProcessor.h | ||
| 3 | // assignment-client/src | ||
| 4 | // | ||
| 5 | // Created by Stephen Birarda on 2014-08-14. | ||
| 6 | // Copyright 2014 High Fidelity, Inc. | ||
| 7 | // | ||
| 8 | // Distributed under the Apache License, Version 2.0. | ||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | // | ||
| 11 | |||
| 12 | #ifndef hifi_AudioMixerDatagramProcessor_h | ||
| 13 | #define hifi_AudioMixerDatagramProcessor_h | ||
| 14 | |||
| 15 | #include <qobject.h> | ||
| 16 | #include <qudpsocket.h> | ||
| 17 | |||
| 18 | class AudioMixerDatagramProcessor : public QObject { | ||
| 19 | Q_OBJECT | ||
| 20 | public: | ||
| 21 | AudioMixerDatagramProcessor(QUdpSocket& nodeSocket, QThread* previousNodeSocketThread); | ||
| 22 | ~AudioMixerDatagramProcessor(); | ||
| 23 | public slots: | ||
| 24 | void readPendingDatagrams(); | ||
| 25 | signals: | ||
| 26 | void packetRequiresProcessing(const QByteArray& receivedPacket, const HifiSockAddr& senderSockAddr); | ||
| 27 | private: | ||
| 28 | QUdpSocket& _nodeSocket; | ||
| 29 | QThread* _previousNodeSocketThread; | ||
| 30 | }; | ||
| 31 | |||
| 32 | #endif // hifi_AudioMixerDatagramProcessor_h | ||
| @@ -11,6 +11,8 @@ · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | #include <QThread> | 12 | #include <QThread> |
| 13 | 13 | ||
| 14 | #include <GLMHelpers.h> | ||
| 15 | |||
| 14 | #include "ScriptableAvatar.h" | 16 | #include "ScriptableAvatar.h" |
| 15 | 17 | ||
| 16 | ScriptableAvatar::ScriptableAvatar(ScriptEngine* scriptEngine) : _scriptEngine(scriptEngine), _animation(NULL) { | 18 | ScriptableAvatar::ScriptableAvatar(ScriptEngine* scriptEngine) : _scriptEngine(scriptEngine), _animation(NULL) { |
| @@ -8,8 +8,8 @@ · 7 unmodified lines | |||
| 8 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 8 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 9 | # | 9 | # |
| 10 | 10 | ||
| 11 | macro(AUTO_MTC TARGET ROOT_DIR) | 11 | macro(AUTO_MTC) |
| 12 | set(AUTOMTC_SRC ${TARGET}_automtc.cpp) | 12 | set(AUTOMTC_SRC ${TARGET_NAME}_automtc.cpp) |
| 13 | 13 | ||
| 14 | file(GLOB INCLUDE_FILES src/*.h) | 14 | file(GLOB INCLUDE_FILES src/*.h) |
| 15 | 15 | ||
| @@ -7,7 +7,7 @@ · 6 unmodified lines | |||
| 7 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 7 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 8 | # | 8 | # |
| 9 | 9 | ||
| 10 | macro(INCLUDE_GLM TARGET ROOT_DIR) | 10 | macro(INCLUDE_GLM) |
| 11 | 11 | ||
| 12 | find_package(GLM REQUIRED) | 12 | find_package(GLM REQUIRED) |
| 13 | include_directories("${GLM_INCLUDE_DIRS}") | 13 | include_directories("${GLM_INCLUDE_DIRS}") |
| @@ -16,4 +16,4 @@ macro(INCLUDE_GLM TARGET ROOT_DIR) · 2 unmodified lines | |||
| 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${GLM_INCLUDE_DIRS}") | 16 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${GLM_INCLUDE_DIRS}") |
| 17 | endif () | 17 | endif () |
| 18 | 18 | ||
| 19 | endmacro(INCLUDE_GLM _target _root_dir) | 19 | endmacro(INCLUDE_GLM) |
| @@ -0,0 +1,14 @@ | |||
| 1 | # | ||
| 2 | # IncludeHifiLibraryHeaders.cmake | ||
| 3 | # cmake/macros | ||
| 4 | # | ||
| 5 | # Copyright 2014 High Fidelity, Inc. | ||
| 6 | # Created by Stephen Birarda on August 8, 2014 | ||
| 7 | # | ||
| 8 | # Distributed under the Apache License, Version 2.0. | ||
| 9 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | # | ||
| 11 | |||
| 12 | macro(include_hifi_library_headers LIBRARY) | ||
| 13 | include_directories("${HIFI_LIBRARY_DIR}/${LIBRARY}/src") | ||
| 14 | endmacro(include_hifi_library_headers _library _root_dir) | ||
| @@ -0,0 +1,34 @@ | |||
| 1 | # | ||
| 2 | # LinkHifiLibrary.cmake | ||
| 3 | # | ||
| 4 | # Copyright 2013 High Fidelity, Inc. | ||
| 5 | # | ||
| 6 | # Distributed under the Apache License, Version 2.0. | ||
| 7 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 8 | # | ||
| 9 | |||
| 10 | macro(LINK_HIFI_LIBRARIES) | ||
| 11 | |||
| 12 | file(RELATIVE_PATH RELATIVE_LIBRARY_DIR_PATH ${CMAKE_CURRENT_SOURCE_DIR} "${HIFI_LIBRARY_DIR}") | ||
| 13 | |||
| 14 | set(LIBRARIES_TO_LINK ${ARGN}) | ||
| 15 | |||
| 16 | foreach(HIFI_LIBRARY ${LIBRARIES_TO_LINK}) | ||
| 17 | if (NOT TARGET ${HIFI_LIBRARY}) | ||
| 18 | add_subdirectory("${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}" "${RELATIVE_LIBRARY_DIR_PATH}/${HIFI_LIBRARY}") | ||
| 19 | endif () | ||
| 20 | |||
| 21 | include_directories("${HIFI_LIBRARY_DIR}/${HIFI_LIBRARY}/src") | ||
| 22 | |||
| 23 | add_dependencies(${TARGET_NAME} ${HIFI_LIBRARY}) | ||
| 24 | |||
| 25 | # link the actual library - it is static so don't bubble it up | ||
| 26 | target_link_libraries(${TARGET_NAME} ${HIFI_LIBRARY}) | ||
| 27 | |||
| 28 | # ask the library what its dynamic dependencies are and link them | ||
| 29 | get_target_property(LINKED_TARGET_DEPENDENCY_LIBRARIES ${HIFI_LIBRARY} DEPENDENCY_LIBRARIES) | ||
| 30 | list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK ${LINKED_TARGET_DEPENDENCY_LIBRARIES}) | ||
| 31 | |||
| 32 | endforeach() | ||
| 33 | |||
| 34 | endmacro(LINK_HIFI_LIBRARIES) | ||
| @@ -1,27 +0,0 @@ | |||
| 1 | # | ||
| 2 | # LinkHifiLibrary.cmake | ||
| 3 | # | ||
| 4 | # Copyright 2013 High Fidelity, Inc. | ||
| 5 | # | ||
| 6 | # Distributed under the Apache License, Version 2.0. | ||
| 7 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 8 | # | ||
| 9 | |||
| 10 | macro(LINK_HIFI_LIBRARY LIBRARY TARGET ROOT_DIR) | ||
| 11 | |||
| 12 | if (NOT TARGET ${LIBRARY}) | ||
| 13 | add_subdirectory("${ROOT_DIR}/libraries/${LIBRARY}" "${ROOT_DIR}/libraries/${LIBRARY}") | ||
| 14 | endif () | ||
| 15 | |||
| 16 | include_directories("${ROOT_DIR}/libraries/${LIBRARY}/src") | ||
| 17 | |||
| 18 | add_dependencies(${TARGET} ${LIBRARY}) | ||
| 19 | target_link_libraries(${TARGET} ${LIBRARY}) | ||
| 20 | |||
| 21 | if (APPLE) | ||
| 22 | # currently the "shared" library requires CoreServices | ||
| 23 | # link in required OS X framework | ||
| 24 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework CoreServices") | ||
| 25 | endif () | ||
| 26 | |||
| 27 | endmacro(LINK_HIFI_LIBRARY _library _target _root_dir) | ||
| @@ -0,0 +1,25 @@ | |||
| 1 | # | ||
| 2 | # LinkSharedDependencies.cmake | ||
| 3 | # cmake/macros | ||
| 4 | # | ||
| 5 | # Copyright 2014 High Fidelity, Inc. | ||
| 6 | # Created by Stephen Birarda on August 8, 2014 | ||
| 7 | # | ||
| 8 | # Distributed under the Apache License, Version 2.0. | ||
| 9 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | # | ||
| 11 | |||
| 12 | macro(LINK_SHARED_DEPENDENCIES) | ||
| 13 | if (${TARGET_NAME}_LIBRARIES_TO_LINK) | ||
| 14 | list(REMOVE_DUPLICATES ${TARGET_NAME}_LIBRARIES_TO_LINK) | ||
| 15 | |||
| 16 | # link these libraries to our target | ||
| 17 | target_link_libraries(${TARGET_NAME} ${${TARGET_NAME}_LIBRARIES_TO_LINK}) | ||
| 18 | endif () | ||
| 19 | |||
| 20 | # we've already linked our Qt modules, but we need to bubble them up to parents | ||
| 21 | list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${${TARGET}_QT_MODULES_TO_LINK}") | ||
| 22 | |||
| 23 | # set the property on this target so it can be retreived by targets linking to us | ||
| 24 | set_target_properties(${TARGET_NAME} PROPERTIES DEPENDENCY_LIBRARIES "${${TARGET}_LIBRARIES_TO_LINK}") | ||
| 25 | endmacro(LINK_SHARED_DEPENDENCIES) | ||
| @@ -7,20 +7,27 @@ · 6 unmodified lines | |||
| 7 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 7 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 8 | # | 8 | # |
| 9 | 9 | ||
| 10 | macro(SETUP_HIFI_LIBRARY TARGET) | 10 | macro(SETUP_HIFI_LIBRARY) |
| 11 | 11 | ||
| 12 | project(${TARGET}) | 12 | project(${TARGET_NAME}) |
| 13 | 13 | ||
| 14 | # grab the implemenation and header files | 14 | # grab the implemenation and header files |
| 15 | file(GLOB LIB_SRCS src/*.h src/*.cpp) | 15 | file(GLOB LIB_SRCS src/*.h src/*.cpp) |
| 16 | set(LIB_SRCS ${LIB_SRCS} ${WRAPPED_SRCS}) | 16 | set(LIB_SRCS ${LIB_SRCS}) |
| 17 | 17 | ||
| 18 | # create a library and set the property so it can be referenced later | 18 | # create a library and set the property so it can be referenced later |
| 19 | add_library(${TARGET} ${LIB_SRCS} ${ARGN}) | 19 | add_library(${TARGET_NAME} ${LIB_SRCS} ${AUTOMTC_SRC}) |
| 20 | 20 | ||
| 21 | find_package(Qt5Core REQUIRED) | 21 | set(QT_MODULES_TO_LINK ${ARGN}) |
| 22 | qt5_use_modules(${TARGET} Core) | 22 | list(APPEND QT_MODULES_TO_LINK Core) |
| 23 | 23 | ||
| 24 | target_link_libraries(${TARGET} ${QT_LIBRARIES}) | 24 | find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK} REQUIRED) |
| 25 | 25 | ||
| 26 | endmacro(SETUP_HIFI_LIBRARY _target) | 26 | foreach(QT_MODULE ${QT_MODULES_TO_LINK}) |
| 27 | get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION) | ||
| 28 | |||
| 29 | # add the actual path to the Qt module to our LIBRARIES_TO_LINK variable | ||
| 30 | target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) | ||
| 31 | list(APPEND ${TARGET_NAME}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION}) | ||
| 32 | endforeach() | ||
| 33 | endmacro(SETUP_HIFI_LIBRARY) | ||
| @@ -7,8 +7,8 @@ · 6 unmodified lines | |||
| 7 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 7 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 8 | # | 8 | # |
| 9 | 9 | ||
| 10 | macro(SETUP_HIFI_PROJECT TARGET INCLUDE_QT) | 10 | macro(SETUP_HIFI_PROJECT) |
| 11 | project(${TARGET}) | 11 | project(${TARGET_NAME}) |
| 12 | 12 | ||
| 13 | # grab the implemenation and header files | 13 | # grab the implemenation and header files |
| 14 | file(GLOB TARGET_SRCS src/*) | 14 | file(GLOB TARGET_SRCS src/*) |
| @@ -23,12 +23,19 @@ macro(SETUP_HIFI_PROJECT TARGET INCLUDE_QT) · 8 unmodified lines | |||
| 23 | endforeach() | 23 | endforeach() |
| 24 | 24 | ||
| 25 | # add the executable, include additional optional sources | 25 | # add the executable, include additional optional sources |
| 26 | add_executable(${TARGET} ${TARGET_SRCS} ${ARGN}) | 26 | add_executable(${TARGET_NAME} ${TARGET_SRCS} "${AUTOMTC_SRC}") |
| 27 | 27 | ||
| 28 | if (${INCLUDE_QT}) | 28 | set(QT_MODULES_TO_LINK ${ARGN}) |
| 29 | find_package(Qt5Core REQUIRED) | 29 | list(APPEND QT_MODULES_TO_LINK Core) |
| 30 | qt5_use_modules(${TARGET} Core) | 30 | |
| 31 | endif () | 31 | find_package(Qt5 COMPONENTS ${QT_MODULES_TO_LINK} REQUIRED) |
| 32 | |||
| 33 | foreach(QT_MODULE ${QT_MODULES_TO_LINK}) | ||
| 34 | target_link_libraries(${TARGET_NAME} Qt5::${QT_MODULE}) | ||
| 35 | |||
| 36 | # add the actual path to the Qt module to our LIBRARIES_TO_LINK variable | ||
| 37 | get_target_property(QT_LIBRARY_LOCATION Qt5::${QT_MODULE} LOCATION) | ||
| 38 | list(APPEND ${TARGET_NAME}_QT_MODULES_TO_LINK ${QT_LIBRARY_LOCATION}) | ||
| 39 | endforeach() | ||
| 32 | 40 | ||
| 33 | target_link_libraries(${TARGET} ${QT_LIBRARIES}) | ||
| 34 | endmacro() | 41 | endmacro() |
| @@ -0,0 +1,29 @@ | |||
| 1 | # | ||
| 2 | # FindATL.cmake | ||
| 3 | # | ||
| 4 | # Try to find the ATL library needed to use the LibOVR | ||
| 5 | # | ||
| 6 | # Once done this will define | ||
| 7 | # | ||
| 8 | # ATL_FOUND - system found ATL | ||
| 9 | # ATL_LIBRARIES - Link this to use ATL | ||
| 10 | # | ||
| 11 | # Created on 8/13/2013 by Stephen Birarda | ||
| 12 | # Copyright 2014 High Fidelity, Inc. | ||
| 13 | # | ||
| 14 | # Distributed under the Apache License, Version 2.0. | ||
| 15 | # See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 16 | # | ||
| 17 | |||
| 18 | if (WIN32) | ||
| 19 | find_library(ATL_LIBRARY_RELEASE atls PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") | ||
| 20 | find_library(ATL_LIBRARY_DEBUG atlsd PATH_SUFFIXES "7600.16385.1/lib/ATL/i386" HINTS "C:\\WinDDK") | ||
| 21 | |||
| 22 | include(SelectLibraryConfigurations) | ||
| 23 | select_library_configurations(ATL) | ||
| 24 | endif () | ||
| 25 | |||
| 26 | set(ATL_LIBRARIES "${ATL_LIBRARY}") | ||
| 27 | |||
| 28 | include(FindPackageHandleStandardArgs) | ||
| 29 | find_package_handle_standard_args(ATL DEFAULT_MSG ATL_LIBRARIES) | ||
| @@ -19,6 +19,6 @@ if (WIN32) · 18 unmodified lines | |||
| 19 | endif (WIN32) | 19 | endif (WIN32) |
| 20 | 20 | ||
| 21 | include(FindPackageHandleStandardArgs) | 21 | include(FindPackageHandleStandardArgs) |
| 22 | find_package_handle_standard_args(FACEPLUS DEFAULT_MSG FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES) | 22 | find_package_handle_standard_args(Faceplus DEFAULT_MSG FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES) |
| 23 | 23 | ||
| 24 | mark_as_advanced(FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES) | 24 | mark_as_advanced(FACEPLUS_INCLUDE_DIRS FACEPLUS_LIBRARIES) |
| @@ -40,6 +40,6 @@ select_library_configurations(FACESHIFT) · 39 unmodified lines | |||
| 40 | set(FACESHIFT_LIBRARIES ${FACESHIFT_LIBRARY}) | 40 | set(FACESHIFT_LIBRARIES ${FACESHIFT_LIBRARY}) |
| 41 | 41 | ||
| 42 | include(FindPackageHandleStandardArgs) | 42 | include(FindPackageHandleStandardArgs) |
| 43 | find_package_handle_standard_args(FACESHIFT DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES) | 43 | find_package_handle_standard_args(Faceshift DEFAULT_MSG FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES) |
| 44 | 44 | ||
| 45 | mark_as_advanced(FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES FACESHIFT_SEARCH_DIRS) | 45 | mark_as_advanced(FACESHIFT_INCLUDE_DIRS FACESHIFT_LIBRARIES FACESHIFT_SEARCH_DIRS) |
| @@ -30,6 +30,6 @@ select_library_configurations(LEAPMOTION) · 29 unmodified lines | |||
| 30 | set(LEAPMOTION_LIBRARIES "${LEAPMOTION_LIBRARY}") | 30 | set(LEAPMOTION_LIBRARIES "${LEAPMOTION_LIBRARY}") |
| 31 | 31 | ||
| 32 | include(FindPackageHandleStandardArgs) | 32 | include(FindPackageHandleStandardArgs) |
| 33 | find_package_handle_standard_args(LEAPMOTION DEFAULT_MSG LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES) | 33 | find_package_handle_standard_args(LeapMotion DEFAULT_MSG LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES) |
| 34 | 34 | ||
| 35 | mark_as_advanced(LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES LEAPMOTION_SEARCH_DIRS) | 35 | mark_as_advanced(LEAPMOTION_INCLUDE_DIRS LEAPMOTION_LIBRARIES LEAPMOTION_SEARCH_DIRS) |
| @@ -19,16 +19,18 @@ · 18 unmodified lines | |||
| 19 | # | 19 | # |
| 20 | 20 | ||
| 21 | include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") | 21 | include("${MACRO_DIR}/HifiLibrarySearchHints.cmake") |
| 22 | hifi_library_search_hints("oculus") | 22 | hifi_library_search_hints("libovr") |
| 23 | 23 | ||
| 24 | find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${OCULUS_SEARCH_DIRS}) | 24 | find_path(LIBOVR_INCLUDE_DIRS OVR.h PATH_SUFFIXES Include HINTS ${LIBOVR_SEARCH_DIRS}) |
| 25 | find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${OCULUS_SEARCH_DIRS}) | 25 | find_path(LIBOVR_SRC_DIR Util_Render_Stereo.h PATH_SUFFIXES Src/Util HINTS ${LIBOVR_SEARCH_DIRS}) |
| 26 | 26 | ||
| 27 | include(SelectLibraryConfigurations) | 27 | include(SelectLibraryConfigurations) |
| 28 | 28 | ||
| 29 | if (APPLE) | 29 | if (APPLE) |
| 30 | find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/MacOS/Debug HINTS ${OCULUS_SEARCH_DIRS}) | 30 | find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Mac/Debug HINTS ${LIBOVR_SEARCH_DIRS}) |
| 31 | find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/MacOS/Release HINTS ${OCULUS_SEARCH_DIRS}) | 31 | find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Mac/Release HINTS ${LIBOVR_SEARCH_DIRS}) |
| 32 | find_library(ApplicationServices ApplicationServices) | ||
| 33 | find_library(IOKit IOKit) | ||
| 32 | elseif (UNIX) | 34 | elseif (UNIX) |
| 33 | find_library(UDEV_LIBRARY_RELEASE udev /usr/lib/x86_64-linux-gnu/) | 35 | find_library(UDEV_LIBRARY_RELEASE udev /usr/lib/x86_64-linux-gnu/) |
| 34 | find_library(XINERAMA_LIBRARY_RELEASE Xinerama /usr/lib/x86_64-linux-gnu/) | 36 | find_library(XINERAMA_LIBRARY_RELEASE Xinerama /usr/lib/x86_64-linux-gnu/) |
| @@ -39,29 +41,36 @@ elseif (UNIX) · 4 unmodified lines | |||
| 39 | set(LINUX_ARCH_DIR "x86_64") | 41 | set(LINUX_ARCH_DIR "x86_64") |
| 40 | endif() | 42 | endif() |
| 41 | 43 | ||
| 42 | find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Linux/Debug/${LINUX_ARCH_DIR} HINTS ${OCULUS_SEARCH_DIRS}) | 44 | find_library(LIBOVR_LIBRARY_DEBUG NAMES ovr PATH_SUFFIXES Lib/Linux/Debug/${LINUX_ARCH_DIR} HINTS ${LIBOVR_SEARCH_DIRS}) |
| 43 | find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Linux/Release/${LINUX_ARCH_DIR} HINTS ${OCULUS_SEARCH_DIRS}) | 45 | find_library(LIBOVR_LIBRARY_RELEASE NAMES ovr PATH_SUFFIXES Lib/Linux/Release/${LINUX_ARCH_DIR} HINTS ${LIBOVR_SEARCH_DIRS}) |
| 44 | 46 | ||
| 45 | select_library_configurations(UDEV) | 47 | select_library_configurations(UDEV) |
| 46 | select_library_configurations(XINERAMA) | 48 | select_library_configurations(XINERAMA) |
| 47 | 49 | ||
| 48 | elseif (WIN32) | 50 | elseif (WIN32) |
| 49 | find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${OCULUS_SEARCH_DIRS}) | 51 | find_library(LIBOVR_LIBRARY_DEBUG NAMES libovrd PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS}) |
| 50 | find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${OCULUS_SEARCH_DIRS}) | 52 | find_library(LIBOVR_LIBRARY_RELEASE NAMES libovr PATH_SUFFIXES Lib/Win32/VS2010 HINTS ${LIBOVR_SEARCH_DIRS}) |
| 53 | find_package(ATL) | ||
| 51 | endif () | 54 | endif () |
| 52 | 55 | ||
| 53 | select_library_configurations(LIBOVR) | 56 | select_library_configurations(LIBOVR) |
| 54 | set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARY}") | 57 | set(LIBOVR_LIBRARIES ${LIBOVR_LIBRARY}) |
| 55 | 58 | ||
| 56 | if (UNIX AND NOT APPLE) | 59 | list(APPEND LIBOVR_ARGS_LIST LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARY) |
| 57 | set(LIBOVR_LIBRARIES "${LIBOVR_LIBRARIES}" "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}") | 60 | |
| 61 | if (APPLE) | ||
| 62 | list(APPEND LIBOVR_LIBRARIES ${IOKit} ${ApplicationServices}) | ||
| 63 | list(APPEND LIBOVR_ARGS_LIST IOKit ApplicationServices) | ||
| 64 | elseif (UNIX) | ||
| 65 | list(APPEND LIBOVR_LIBRARIES "${UDEV_LIBRARY}" "${XINERAMA_LIBRARY}") | ||
| 66 | list(APPEND LIBOVR_ARGS_LIST UDEV_LIBRARY XINERAMA_LIBRARY) | ||
| 67 | elseif (WIN32) | ||
| 68 | list(APPEND LIBOVR_LIBRARIES ${ATL_LIBRARIES}) | ||
| 69 | list(APPEND LIBOVR_ARGS_LIST ATL_LIBRARIES) | ||
| 58 | endif () | 70 | endif () |
| 59 | 71 | ||
| 60 | include(FindPackageHandleStandardArgs) | 72 | include(FindPackageHandleStandardArgs) |
| 61 | if (UNIX AND NOT APPLE) | ||
| 62 | find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES UDEV_LIBRARY XINERAMA_LIBRARY) | ||
| 63 | else () | ||
| 64 | find_package_handle_standard_args(LIBOVR DEFAULT_MSG LIBOVR_INCLUDE_DIRS LIBOVR_SRC_DIR LIBOVR_LIBRARIES) | ||
| 65 | endif () | ||
| 66 | 73 | ||
| 67 | mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES OCULUS_SEARCH_DIRS) | 74 | find_package_handle_standard_args(LibOVR DEFAULT_MSG ${LIBOVR_ARGS_LIST}) |
| 75 | |||
| 76 | mark_as_advanced(LIBOVR_INCLUDE_DIRS LIBOVR_LIBRARIES LIBOVR_SEARCH_DIRS) | ||
| @@ -19,6 +19,6 @@ if (WIN32) · 18 unmodified lines | |||
| 19 | endif (WIN32) | 19 | endif (WIN32) |
| 20 | 20 | ||
| 21 | include(FindPackageHandleStandardArgs) | 21 | include(FindPackageHandleStandardArgs) |
| 22 | find_package_handle_standard_args(PRIOVR DEFAULT_MSG PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES) | 22 | find_package_handle_standard_args(PrioVR DEFAULT_MSG PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES) |
| 23 | 23 | ||
| 24 | mark_as_advanced(PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES) | 24 | mark_as_advanced(PRIOVR_INCLUDE_DIRS PRIOVR_LIBRARIES) |
| @@ -26,12 +26,14 @@ find_path(QXMPP_INCLUDE_DIRS QXmppClient.h PATH_SUFFIXES include/qxmpp HINTS ${Q · 25 unmodified lines | |||
| 26 | find_library(QXMPP_LIBRARY_RELEASE NAMES qxmpp PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS}) | 26 | find_library(QXMPP_LIBRARY_RELEASE NAMES qxmpp PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS}) |
| 27 | find_library(QXMPP_LIBRARY_DEBUG NAMES qxmpp_d PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS}) | 27 | find_library(QXMPP_LIBRARY_DEBUG NAMES qxmpp_d PATH_SUFFIXES lib HINTS ${QXMPP_SEARCH_DIRS}) |
| 28 | 28 | ||
| 29 | find_package(Qt5 COMPONENTS Xml REQUIRED) | ||
| 30 | |||
| 29 | include(SelectLibraryConfigurations) | 31 | include(SelectLibraryConfigurations) |
| 30 | select_library_configurations(QXMPP) | 32 | select_library_configurations(QXMPP) |
| 31 | 33 | ||
| 32 | set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}") | 34 | set(QXMPP_LIBRARIES "${QXMPP_LIBRARY}" Qt5::Xml) |
| 33 | 35 | ||
| 34 | include(FindPackageHandleStandardArgs) | 36 | include(FindPackageHandleStandardArgs) |
| 35 | find_package_handle_standard_args(QXMPP DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES) | 37 | find_package_handle_standard_args(QXmpp DEFAULT_MSG QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_LIBRARY) |
| 36 | 38 | ||
| 37 | mark_as_advanced(QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_SEARCH_DIRS) | 39 | mark_as_advanced(QXMPP_INCLUDE_DIRS QXMPP_LIBRARIES QXMPP_SEARCH_DIRS) |
| @@ -25,6 +25,6 @@ find_path(RTMIDI_INCLUDE_DIRS RtMidi.h PATH_SUFFIXES include HINTS ${RTMIDI_SEAR · 24 unmodified lines | |||
| 25 | find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS}) | 25 | find_library(RTMIDI_LIBRARIES NAMES rtmidi PATH_SUFFIXES lib HINTS ${RTMIDI_SEARCH_DIRS}) |
| 26 | 26 | ||
| 27 | include(FindPackageHandleStandardArgs) | 27 | include(FindPackageHandleStandardArgs) |
| 28 | find_package_handle_standard_args(RTMIDI DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES) | 28 | find_package_handle_standard_args(RtMidi DEFAULT_MSG RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES) |
| 29 | 29 | ||
| 30 | mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES RTMIDI_SEARCH_DIRS) | 30 | mark_as_advanced(RTMIDI_INCLUDE_DIRS RTMIDI_LIBRARIES RTMIDI_SEARCH_DIRS) |
| @@ -40,6 +40,6 @@ select_library_configurations(SIXENSE) · 39 unmodified lines | |||
| 40 | set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}") | 40 | set(SIXENSE_LIBRARIES "${SIXENSE_LIBRARY}") |
| 41 | 41 | ||
| 42 | include(FindPackageHandleStandardArgs) | 42 | include(FindPackageHandleStandardArgs) |
| 43 | find_package_handle_standard_args(SIXENSE DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES) | 43 | find_package_handle_standard_args(Sixense DEFAULT_MSG SIXENSE_INCLUDE_DIRS SIXENSE_LIBRARIES) |
| 44 | 44 | ||
| 45 | mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS) | 45 | mark_as_advanced(SIXENSE_LIBRARIES SIXENSE_INCLUDE_DIRS SIXENSE_SEARCH_DIRS) |
| @@ -32,6 +32,9 @@ if (APPLE) · 31 unmodified lines | |||
| 32 | find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS}) | 32 | find_library(VISAGE_VISION_LIBRARY NAME vsvision PATH_SUFFIXES lib HINTS ${VISAGE_SEARCH_DIRS}) |
| 33 | find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib HINTS ${VISAGE_SEARCH_DIRS}) | 33 | find_library(VISAGE_OPENCV_LIBRARY NAME OpenCV PATH_SUFFIXES dependencies/OpenCV_MacOSX/lib HINTS ${VISAGE_SEARCH_DIRS}) |
| 34 | 34 | ||
| 35 | find_library(AppKit AppKit) | ||
| 36 | find_library(QuartzCore QuartzCore) | ||
| 37 | find_library(QTKit QTKit) | ||
| 35 | elseif (WIN32) | 38 | elseif (WIN32) |
| 36 | find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS}) | 39 | find_path(VISAGE_XML_INCLUDE_DIR libxml/xmlreader.h PATH_SUFFIXES dependencies/libxml2/include HINTS ${VISAGE_SEARCH_DIRS}) |
| 37 | find_path(VISAGE_OPENCV_INCLUDE_DIR opencv/cv.h PATH_SUFFIXES dependencies/OpenCV/include HINTS ${VISAGE_SEARCH_DIRS}) | 40 | find_path(VISAGE_OPENCV_INCLUDE_DIR opencv/cv.h PATH_SUFFIXES dependencies/OpenCV/include HINTS ${VISAGE_SEARCH_DIRS}) |
| @@ -43,16 +46,22 @@ elseif (WIN32) · 5 unmodified lines | |||
| 43 | endif () | 46 | endif () |
| 44 | 47 | ||
| 45 | include(FindPackageHandleStandardArgs) | 48 | include(FindPackageHandleStandardArgs) |
| 46 | find_package_handle_standard_args(VISAGE DEFAULT_MSG | 49 | |
| 47 | VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR | 50 | list(APPEND VISAGE_ARGS_LIST VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR |
| 48 | VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY | 51 | VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR |
| 49 | ) | 52 | VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY) |
| 53 | |||
| 54 | if (APPLE) | ||
| 55 | list(APPEND VISAGE_ARGS_LIST QuartzCore AppKit QTKit) | ||
| 56 | endif () | ||
| 57 | |||
| 58 | find_package_handle_standard_args(Visage DEFAULT_MSG ${VISAGE_ARGS_LIST}) | ||
| 50 | 59 | ||
| 51 | set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR}" "${VISAGE_OPENCV2_INCLUDE_DIR}" "${VISAGE_BASE_INCLUDE_DIR}") | 60 | set(VISAGE_INCLUDE_DIRS "${VISAGE_XML_INCLUDE_DIR}" "${VISAGE_OPENCV_INCLUDE_DIR}" "${VISAGE_OPENCV2_INCLUDE_DIR}" "${VISAGE_BASE_INCLUDE_DIR}") |
| 52 | set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}") | 61 | set(VISAGE_LIBRARIES "${VISAGE_CORE_LIBRARY}" "${VISAGE_VISION_LIBRARY}" "${VISAGE_OPENCV_LIBRARY}") |
| 53 | 62 | ||
| 54 | mark_as_advanced( | 63 | if (APPLE) |
| 55 | VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES | 64 | list(APPEND VISAGE_LIBRARIES ${QuartzCore} ${AppKit} ${QTKit}) |
| 56 | VISAGE_BASE_INCLUDE_DIR VISAGE_XML_INCLUDE_DIR VISAGE_OPENCV_INCLUDE_DIR VISAGE_OPENCV2_INCLUDE_DIR | 65 | endif () |
| 57 | VISAGE_CORE_LIBRARY VISAGE_VISION_LIBRARY VISAGE_OPENCV_LIBRARY VISAGE_SEARCH_DIRS | 66 | |
| 58 | ) | 67 | mark_as_advanced(VISAGE_INCLUDE_DIRS VISAGE_LIBRARIES) |
| @@ -1,24 +1,7 @@ | |||
| 1 | if (WIN32) | ||
| 2 | cmake_policy (SET CMP0020 NEW) | ||
| 3 | endif (WIN32) | ||
| 4 | |||
| 5 | set(TARGET_NAME domain-server) | 1 | set(TARGET_NAME domain-server) |
| 6 | 2 | ||
| 7 | set(ROOT_DIR ..) | 3 | # setup the project and link required Qt modules |
| 8 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | 4 | setup_hifi_project(Network) |
| 9 | |||
| 10 | # setup for find modules | ||
| 11 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") | ||
| 12 | |||
| 13 | # set up the external glm library | ||
| 14 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 15 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 16 | |||
| 17 | find_package(Qt5Network REQUIRED) | ||
| 18 | |||
| 19 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 20 | |||
| 21 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 22 | 5 | ||
| 23 | # remove and then copy the files for the webserver | 6 | # remove and then copy the files for the webserver |
| 24 | add_custom_command(TARGET ${TARGET_NAME} POST_BUILD | 7 | add_custom_command(TARGET ${TARGET_NAME} POST_BUILD |
| @@ -29,20 +12,7 @@ add_custom_command(TARGET ${TARGET_NAME} POST_BUILD · 4 unmodified lines | |||
| 29 | "${PROJECT_SOURCE_DIR}/resources/web" | 12 | "${PROJECT_SOURCE_DIR}/resources/web" |
| 30 | $<TARGET_FILE_DIR:${TARGET_NAME}>/resources/web) | 13 | $<TARGET_FILE_DIR:${TARGET_NAME}>/resources/web) |
| 31 | 14 | ||
| 32 | # link the shared hifi library | 15 | # link the shared hifi libraries |
| 33 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 16 | link_hifi_libraries(embedded-webserver networking shared) |
| 34 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 35 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 36 | link_hifi_library(embedded-webserver ${TARGET_NAME} "${ROOT_DIR}") | ||
| 37 | |||
| 38 | IF (WIN32) | ||
| 39 | target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 40 | ENDIF(WIN32) | ||
| 41 | |||
| 42 | # link QtNetwork | ||
| 43 | target_link_libraries(${TARGET_NAME} Qt5::Network) | ||
| 44 | 17 | ||
| 45 | # add a definition for ssize_t so that windows doesn't bail | 18 | link_shared_dependencies() |
| 46 | if (WIN32) | ||
| 47 | add_definitions(-Dssize_t=long) | ||
| 48 | endif () | ||
| @@ -21,6 +21,12 @@ · 20 unmodified lines | |||
| 21 | "placeholder": "10", | 21 | "placeholder": "10", |
| 22 | "default": "10" | 22 | "default": "10" |
| 23 | }, | 23 | }, |
| 24 | "H-print-stream-stats": { | ||
| 25 | "type": "checkbox", | ||
| 26 | "label": "Print Stream Stats:", | ||
| 27 | "help": "If enabled, audio upstream and downstream stats of each agent will be printed each second to stdout", | ||
| 28 | "default": false | ||
| 29 | }, | ||
| 24 | "D-unattenuated-zone": { | 30 | "D-unattenuated-zone": { |
| 25 | "label": "Unattenuated Zone", | 31 | "label": "Unattenuated Zone", |
| 26 | "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)", | 32 | "help": "Boxes for source and listener (corner x, corner y, corner z, size x, size y, size z, corner x, corner y, corner z, size x, size y, size z)", |
| @@ -24,6 +24,7 @@ function setupMenus() { · 23 unmodified lines | |||
| 24 | Menu.removeMenuItem("Edit", "Paste"); | 24 | Menu.removeMenuItem("Edit", "Paste"); |
| 25 | Menu.removeMenuItem("Edit", "Delete"); | 25 | Menu.removeMenuItem("Edit", "Delete"); |
| 26 | Menu.removeMenuItem("Edit", "Nudge"); | 26 | Menu.removeMenuItem("Edit", "Nudge"); |
| 27 | Menu.removeMenuItem("Edit", "Replace from File"); | ||
| 27 | Menu.removeMenuItem("File", "Export Voxels"); | 28 | Menu.removeMenuItem("File", "Export Voxels"); |
| 28 | Menu.removeMenuItem("File", "Import Voxels"); | 29 | Menu.removeMenuItem("File", "Import Voxels"); |
| 29 | 30 | ||
| @@ -32,6 +33,7 @@ function setupMenus() { · 2 unmodified lines | |||
| 32 | Menu.addMenuItem({ menuName: "Edit", menuItemName: "Copy", shortcutKey: "CTRL+C", afterItem: "Cut" }); | 33 | Menu.addMenuItem({ menuName: "Edit", menuItemName: "Copy", shortcutKey: "CTRL+C", afterItem: "Cut" }); |
| 33 | Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste", shortcutKey: "CTRL+V", afterItem: "Copy" }); | 34 | Menu.addMenuItem({ menuName: "Edit", menuItemName: "Paste", shortcutKey: "CTRL+V", afterItem: "Copy" }); |
| 34 | Menu.addMenuItem({ menuName: "Edit", menuItemName: "Nudge", shortcutKey: "CTRL+N", afterItem: "Paste" }); | 35 | Menu.addMenuItem({ menuName: "Edit", menuItemName: "Nudge", shortcutKey: "CTRL+N", afterItem: "Paste" }); |
| 36 | Menu.addMenuItem({ menuName: "Edit", menuItemName: "Replace from File", shortcutKey: "CTRL+R", afterItem: "Nudge" }); | ||
| 35 | Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Nudge" }); | 37 | Menu.addMenuItem({ menuName: "Edit", menuItemName: "Delete", shortcutKeyEvent: { text: "backspace" }, afterItem: "Nudge" }); |
| 36 | Menu.addMenuItem({ menuName: "File", menuItemName: "Export Voxels", shortcutKey: "CTRL+E", afterItem: "Voxels" }); | 38 | Menu.addMenuItem({ menuName: "File", menuItemName: "Export Voxels", shortcutKey: "CTRL+E", afterItem: "Voxels" }); |
| 37 | Menu.addMenuItem({ menuName: "File", menuItemName: "Import Voxels", shortcutKey: "CTRL+I", afterItem: "Export Voxels" }); | 39 | Menu.addMenuItem({ menuName: "File", menuItemName: "Import Voxels", shortcutKey: "CTRL+I", afterItem: "Export Voxels" }); |
| @@ -60,7 +62,6 @@ function menuItemEvent(menuItem) { · 22 unmodified lines | |||
| 60 | print("deleting..."); | 62 | print("deleting..."); |
| 61 | Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); | 63 | Clipboard.deleteVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); |
| 62 | } | 64 | } |
| 63 | |||
| 64 | if (menuItem == "Export Voxels") { | 65 | if (menuItem == "Export Voxels") { |
| 65 | print("export"); | 66 | print("export"); |
| 66 | Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); | 67 | Clipboard.exportVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s); |
| @@ -73,6 +74,12 @@ function menuItemEvent(menuItem) { · 6 unmodified lines | |||
| 73 | print("nudge"); | 74 | print("nudge"); |
| 74 | Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 }); | 75 | Clipboard.nudgeVoxel(selectedVoxel.x, selectedVoxel.y, selectedVoxel.z, selectedVoxel.s, { x: -1, y: 0, z: 0 }); |
| 75 | } | 76 | } |
| 77 | if (menuItem == "Replace from File") { | ||
| 78 | var filename = Window.browse("Select file to load replacement", "", "Voxel Files (*.png *.svo *.schematic)"); | ||
| 79 | if (filename) { | ||
| 80 | Clipboard.importVoxel(filename, selectedVoxel); | ||
| 81 | } | ||
| 82 | } | ||
| 76 | } | 83 | } |
| 77 | 84 | ||
| 78 | var selectCube = Overlays.addOverlay("cube", { | 85 | var selectCube = Overlays.addOverlay("cube", { |
| @@ -1,18 +1,13 @@ | |||
| 1 | set(ROOT_DIR ..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | set(TARGET_NAME interface) | 1 | set(TARGET_NAME interface) |
| 5 | project(${TARGET_NAME}) | 2 | project(${TARGET_NAME}) |
| 6 | 3 | ||
| 7 | # setup for find modules | ||
| 8 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") | ||
| 9 | |||
| 10 | # set a default root dir for each of our optional externals if it was not passed | 4 | # set a default root dir for each of our optional externals if it was not passed |
| 11 | set(OPTIONAL_EXTERNALS "faceplus" "faceshift" "oculus" "priovr" "sixense" "visage" "leapmotion" "rtmidi" "qxmpp") | 5 | set(OPTIONAL_EXTERNALS "Faceplus" "Faceshift" "LibOVR" "PrioVR" "Sixense" "Visage" "LeapMotion" "RtMidi" "Qxmpp") |
| 12 | foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) | 6 | foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) |
| 13 | string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL) | 7 | string(TOUPPER ${EXTERNAL} ${EXTERNAL}_UPPERCASE) |
| 14 | if (NOT ${UPPER_EXTERNAL}_ROOT_DIR) | 8 | if (NOT ${${EXTERNAL}_UPPERCASE}_ROOT_DIR) |
| 15 | set(${UPPER_EXTERNAL}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${EXTERNAL}") | 9 | string(TOLOWER ${EXTERNAL} ${EXTERNAL}_LOWERCASE) |
| 10 | set(${${EXTERNAL}_UPPERCASE}_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external/${${EXTERNAL}_LOWERCASE}") | ||
| 16 | endif () | 11 | endif () |
| 17 | endforeach() | 12 | endforeach() |
| 18 | 13 | ||
| @@ -38,8 +33,7 @@ elseif (WIN32) · 19 unmodified lines | |||
| 38 | endif () | 33 | endif () |
| 39 | 34 | ||
| 40 | # set up the external glm library | 35 | # set up the external glm library |
| 41 | include("${MACRO_DIR}/IncludeGLM.cmake") | 36 | include_glm() |
| 42 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 43 | 37 | ||
| 44 | # create the InterfaceConfig.h file based on GL_HEADERS above | 38 | # create the InterfaceConfig.h file based on GL_HEADERS above |
| 45 | configure_file(InterfaceConfig.h.in "${PROJECT_BINARY_DIR}/includes/InterfaceConfig.h") | 39 | 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 · 6 unmodified lines | |||
| 52 | set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}") | 46 | set(INTERFACE_SRCS ${INTERFACE_SRCS} "${SUBDIR_SRCS}") |
| 53 | endforeach(SUBDIR) | 47 | endforeach(SUBDIR) |
| 54 | 48 | ||
| 55 | find_package(Qt5 COMPONENTS Core Gui Multimedia Network OpenGL Script Svg WebKit WebKitWidgets Xml UiTools) | 49 | find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Script Svg WebKitWidgets) |
| 56 | 50 | ||
| 57 | # grab the ui files in resources/ui | 51 | # grab the ui files in resources/ui |
| 58 | file (GLOB_RECURSE QT_UI_FILES ui/*.ui) | 52 | file (GLOB_RECURSE QT_UI_FILES ui/*.ui) |
| @@ -97,60 +91,36 @@ endif() · 38 unmodified lines | |||
| 97 | # create the executable, make it a bundle on OS X | 91 | # create the executable, make it a bundle on OS X |
| 98 | add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) | 92 | add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS} ${QM}) |
| 99 | 93 | ||
| 100 | # link in the hifi shared library | ||
| 101 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | ||
| 102 | |||
| 103 | # link required hifi libraries | 94 | # link required hifi libraries |
| 104 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | 95 | link_hifi_libraries(shared octree voxels fbx metavoxels networking particles entities avatars audio animation script-engine) |
| 105 | link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") | ||
| 106 | link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 107 | link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") | ||
| 108 | link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 109 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 110 | link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}") | ||
| 111 | link_hifi_library(entities ${TARGET_NAME} "${ROOT_DIR}") | ||
| 112 | link_hifi_library(avatars ${TARGET_NAME} "${ROOT_DIR}") | ||
| 113 | link_hifi_library(audio ${TARGET_NAME} "${ROOT_DIR}") | ||
| 114 | link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") | ||
| 115 | link_hifi_library(script-engine ${TARGET_NAME} "${ROOT_DIR}") | ||
| 116 | 96 | ||
| 117 | # find any optional and required libraries | 97 | # find any optional and required libraries |
| 118 | find_package(Faceplus) | 98 | find_package(ZLIB REQUIRED) |
| 119 | find_package(Faceshift) | ||
| 120 | find_package(LibOVR) | ||
| 121 | find_package(PrioVR) | ||
| 122 | find_package(SDL) | ||
| 123 | find_package(Sixense) | ||
| 124 | find_package(Visage) | ||
| 125 | find_package(LeapMotion) | ||
| 126 | find_package(ZLIB) | ||
| 127 | find_package(Qxmpp) | ||
| 128 | find_package(RtMidi) | ||
| 129 | find_package(OpenSSL REQUIRED) | 99 | find_package(OpenSSL REQUIRED) |
| 130 | 100 | ||
| 131 | # perform standard include and linking for found externals | 101 | # perform standard include and linking for found externals |
| 132 | foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) | 102 | foreach(EXTERNAL ${OPTIONAL_EXTERNALS}) |
| 133 | string(TOUPPER ${EXTERNAL} UPPER_EXTERNAL) | ||
| 134 | 103 | ||
| 135 | if (${UPPER_EXTERNAL} MATCHES "OCULUS") | 104 | if (${${EXTERNAL}_UPPERCASE}_REQUIRED) |
| 136 | # the oculus directory is named OCULUS and not LIBOVR so hack to fix that here | 105 | find_package(${EXTERNAL} REQUIRED) |
| 137 | set(UPPER_EXTERNAL "LIBOVR") | 106 | else () |
| 107 | find_package(${EXTERNAL}) | ||
| 138 | endif () | 108 | endif () |
| 139 | 109 | ||
| 140 | if (${UPPER_EXTERNAL}_FOUND AND NOT DISABLE_${UPPER_EXTERNAL}) | 110 | if (${${EXTERNAL}_UPPERCASE}_FOUND AND NOT DISABLE_${${EXTERNAL}_UPPERCASE}) |
| 141 | add_definitions(-DHAVE_${UPPER_EXTERNAL}) | 111 | add_definitions(-DHAVE_${${EXTERNAL}_UPPERCASE}) |
| 142 | 112 | ||
| 143 | # include the library directories (ignoring warnings) | 113 | # include the library directories (ignoring warnings) |
| 144 | include_directories(SYSTEM ${${UPPER_EXTERNAL}_INCLUDE_DIRS}) | 114 | include_directories(SYSTEM ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS}) |
| 145 | 115 | ||
| 146 | # perform the system include hack for OS X to ignore warnings | 116 | # perform the system include hack for OS X to ignore warnings |
| 147 | if (APPLE) | 117 | if (APPLE) |
| 148 | foreach(EXTERNAL_INCLUDE_DIR ${${UPPER_EXTERNAL}_INCLUDE_DIRS}) | 118 | foreach(EXTERNAL_INCLUDE_DIR ${${${EXTERNAL}_UPPERCASE}_INCLUDE_DIRS}) |
| 149 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${EXTERNAL_INCLUDE_DIR}") | 119 | SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${EXTERNAL_INCLUDE_DIR}") |
| 150 | endforeach() | 120 | endforeach() |
| 151 | endif () | 121 | endif () |
| 152 | 122 | ||
| 153 | target_link_libraries(${TARGET_NAME} ${${UPPER_EXTERNAL}_LIBRARIES}) | 123 | target_link_libraries(${TARGET_NAME} ${${${EXTERNAL}_UPPERCASE}_LIBRARIES}) |
| 154 | 124 | ||
| 155 | endif () | 125 | endif () |
| 156 | endforeach() | 126 | endforeach() |
| @@ -179,17 +149,11 @@ endif () · 22 unmodified lines | |||
| 179 | 149 | ||
| 180 | # include headers for interface and InterfaceConfig. | 150 | # include headers for interface and InterfaceConfig. |
| 181 | include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") | 151 | include_directories("${PROJECT_SOURCE_DIR}/src" "${PROJECT_BINARY_DIR}/includes") |
| 182 | 152 | include_directories("${OPENSSL_INCLUDE_DIR}") | |
| 183 | # include external library headers | ||
| 184 | # use system flag so warnings are supressed | ||
| 185 | include_directories(SYSTEM "${OPENSSL_INCLUDE_DIR}") | ||
| 186 | 153 | ||
| 187 | target_link_libraries( | 154 | target_link_libraries( |
| 188 | ${TARGET_NAME} | 155 | ${TARGET_NAME} ${ZLIB_LIBRARIES} ${OPENSSL_LIBRARIES} |
| 189 | "${ZLIB_LIBRARIES}" | 156 | Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL Qt5::Script Qt5::Svg Qt5::WebKitWidgets |
| 190 | ${OPENSSL_LIBRARIES} | ||
| 191 | Qt5::Core Qt5::Gui Qt5::Multimedia Qt5::Network Qt5::OpenGL | ||
| 192 | Qt5::Script Qt5::Svg Qt5::WebKit Qt5::WebKitWidgets Qt5::Xml Qt5::UiTools | ||
| 193 | ) | 157 | ) |
| 194 | 158 | ||
| 195 | # assume we are using a Qt build without bearer management | 159 | # assume we are using a Qt build without bearer management |
| @@ -197,30 +161,12 @@ add_definitions(-DQT_NO_BEARERMANAGEMENT) · 1 unmodified line | |||
| 197 | 161 | ||
| 198 | if (APPLE) | 162 | if (APPLE) |
| 199 | # link in required OS X frameworks and include the right GL headers | 163 | # link in required OS X frameworks and include the right GL headers |
| 200 | find_library(AppKit AppKit) | ||
| 201 | find_library(CoreAudio CoreAudio) | 164 | find_library(CoreAudio CoreAudio) |
| 202 | find_library(CoreServices CoreServices) | 165 | find_library(CoreFoundation CoreFoundation) |
| 203 | find_library(Carbon Carbon) | ||
| 204 | find_library(Foundation Foundation) | ||
| 205 | find_library(GLUT GLUT) | 166 | find_library(GLUT GLUT) |
| 206 | find_library(OpenGL OpenGL) | 167 | find_library(OpenGL OpenGL) |
| 207 | find_library(IOKit IOKit) | ||
| 208 | find_library(QTKit QTKit) | ||
| 209 | find_library(QuartzCore QuartzCore) | ||
| 210 | 168 | ||
| 211 | target_link_libraries( | 169 | target_link_libraries(${TARGET_NAME} ${CoreAudio} ${CoreFoundation} ${GLUT} ${OpenGL}) |
| 212 | ${TARGET_NAME} | ||
| 213 | ${AppKit} | ||
| 214 | ${CoreAudio} | ||
| 215 | ${CoreServices} | ||
| 216 | ${Carbon} | ||
| 217 | ${Foundation} | ||
| 218 | ${GLUT} | ||
| 219 | ${OpenGL} | ||
| 220 | ${IOKit} | ||
| 221 | ${QTKit} | ||
| 222 | ${QuartzCore} | ||
| 223 | ) | ||
| 224 | 170 | ||
| 225 | # install command for OS X bundle | 171 | # install command for OS X bundle |
| 226 | INSTALL(TARGETS ${TARGET_NAME} | 172 | INSTALL(TARGETS ${TARGET_NAME} |
| @@ -254,9 +200,9 @@ else (APPLE) · 27 unmodified lines | |||
| 254 | # we're using static GLEW, so define GLEW_STATIC | 200 | # we're using static GLEW, so define GLEW_STATIC |
| 255 | add_definitions(-DGLEW_STATIC) | 201 | add_definitions(-DGLEW_STATIC) |
| 256 | 202 | ||
| 257 | # add a definition for ssize_t so that windows doesn't bail | ||
| 258 | add_definitions(-Dssize_t=long) | ||
| 259 | |||
| 260 | target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib) | 203 | target_link_libraries(${TARGET_NAME} "${GLEW_LIBRARIES}" wsock32.lib opengl32.lib) |
| 261 | endif() | 204 | endif() |
| 262 | endif (APPLE) | 205 | endif (APPLE) |
| 206 | |||
| 207 | # link any dependencies bubbled up from our linked dependencies | ||
| 208 | link_shared_dependencies() | ||
File renamed without changes.
| @@ -245,28 +245,28 @@ · 244 unmodified lines | |||
| 245 | <context> | 245 | <context> |
| 246 | <name>QObject</name> | 246 | <name>QObject</name> |
| 247 | <message> | 247 | <message> |
| 248 | <location filename="src/ui/ImportDialog.cpp" line="22"/> | 248 | <location filename="src/ui/VoxelImportDialog.cpp" line="22"/> |
| 249 | <location filename="src/ui/ImportDialog.cpp" line="23"/> | 249 | <location filename="src/ui/VoxelImportDialog.cpp" line="23"/> |
| 250 | <source>Import Voxels</source> | 250 | <source>Import Voxels</source> |
| 251 | <translation type="unfinished"></translation> | 251 | <translation type="unfinished"></translation> |
| 252 | </message> | 252 | </message> |
| 253 | <message> | 253 | <message> |
| 254 | <location filename="src/ui/ImportDialog.cpp" line="24"/> | 254 | <location filename="src/ui/VoxelImportDialog.cpp" line="24"/> |
| 255 | <source>Loading ...</source> | 255 | <source>Loading ...</source> |
| 256 | <translation type="unfinished"></translation> | 256 | <translation type="unfinished"></translation> |
| 257 | </message> | 257 | </message> |
| 258 | <message> | 258 | <message> |
| 259 | <location filename="src/ui/ImportDialog.cpp" line="25"/> | 259 | <location filename="src/ui/VoxelImportDialog.cpp" line="25"/> |
| 260 | <source>Place voxels</source> | 260 | <source>Place voxels</source> |
| 261 | <translation type="unfinished"></translation> | 261 | <translation type="unfinished"></translation> |
| 262 | </message> | 262 | </message> |
| 263 | <message> | 263 | <message> |
| 264 | <location filename="src/ui/ImportDialog.cpp" line="26"/> | 264 | <location filename="src/ui/VoxelImportDialog.cpp" line="26"/> |
| 265 | <source><b>Import</b> %1 as voxels</source> | 265 | <source><b>Import</b> %1 as voxels</source> |
| 266 | <translation type="unfinished"></translation> | 266 | <translation type="unfinished"></translation> |
| 267 | </message> | 267 | </message> |
| 268 | <message> | 268 | <message> |
| 269 | <location filename="src/ui/ImportDialog.cpp" line="27"/> | 269 | <location filename="src/ui/VoxelImportDialog.cpp" line="27"/> |
| 270 | <source>Cancel</source> | 270 | <source>Cancel</source> |
| 271 | <translation type="unfinished"></translation> | 271 | <translation type="unfinished"></translation> |
| 272 | </message> | 272 | </message> |
| @@ -17,6 +17,12 @@ uniform sampler2D heightMap; · 16 unmodified lines | |||
| 17 | // the distance between height points in texture space | 17 | // the distance between height points in texture space |
| 18 | uniform float heightScale; | 18 | uniform float heightScale; |
| 19 | 19 | ||
| 20 | // the scale between height and color textures | ||
| 21 | uniform float colorScale; | ||
| 22 | |||
| 23 | // the interpolated position | ||
| 24 | varying vec4 position; | ||
| 25 | |||
| 20 | // the interpolated normal | 26 | // the interpolated normal |
| 21 | varying vec4 normal; | 27 | varying vec4 normal; |
| 22 | 28 | ||
| @@ -29,13 +35,17 @@ void main(void) { · 6 unmodified lines | |||
| 29 | texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r; | 35 | texture2D(heightMap, heightCoord + vec2(0.0, heightScale)).r; |
| 30 | normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0)); | 36 | normal = normalize(gl_ModelViewMatrix * vec4(deltaX, heightScale, deltaZ, 0.0)); |
| 31 | 37 | ||
| 32 | // pass along the texture coordinates | ||
| 33 | gl_TexCoord[0] = gl_MultiTexCoord0; | ||
| 34 | |||
| 35 | // add the height to the position | 38 | // add the height to the position |
| 36 | float height = texture2D(heightMap, heightCoord).r; | 39 | float height = texture2D(heightMap, heightCoord).r; |
| 37 | gl_Position = gl_ModelViewProjectionMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); | 40 | position = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); |
| 41 | gl_Position = gl_ProjectionMatrix * position; | ||
| 38 | 42 | ||
| 39 | // the zero height should be invisible | 43 | // the zero height should be invisible |
| 40 | gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0)); | 44 | gl_FrontColor = vec4(1.0, 1.0, 1.0, step(height, 0.0)); |
| 45 | |||
| 46 | // pass along the scaled/offset texture coordinates | ||
| 47 | gl_TexCoord[0] = (gl_MultiTexCoord0 - vec4(heightScale, heightScale, 0.0, 0.0)) * colorScale; | ||
| 48 | |||
| 49 | // and the shadow texture coordinates | ||
| 50 | gl_TexCoord[1] = vec4(dot(gl_EyePlaneS[0], position), dot(gl_EyePlaneT[0], position), dot(gl_EyePlaneR[0], position), 1.0); | ||
| 41 | } | 51 | } |
| @@ -0,0 +1,48 @@ | |||
| 1 | #version 120 | ||
| 2 | |||
| 3 | // | ||
| 4 | // metavoxel_heightfield.frag | ||
| 5 | // fragment shader | ||
| 6 | // | ||
| 7 | // Created by Andrzej Kapolka on 7/28/14. | ||
| 8 | // Copyright 2014 High Fidelity, Inc. | ||
| 9 | // | ||
| 10 | // Distributed under the Apache License, Version 2.0. | ||
| 11 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 12 | // | ||
| 13 | |||
| 14 | // the diffuse texture | ||
| 15 | uniform sampler2D diffuseMap; | ||
| 16 | |||
| 17 | // the shadow texture | ||
| 18 | uniform sampler2DShadow shadowMap; | ||
| 19 | |||
| 20 | // the distances to the cascade sections | ||
| 21 | uniform vec3 shadowDistances; | ||
| 22 | |||
| 23 | // the inverse of the size of the shadow map | ||
| 24 | const float shadowScale = 1.0 / 2048.0; | ||
| 25 | |||
| 26 | // the interpolated position | ||
| 27 | varying vec4 position; | ||
| 28 | |||
| 29 | // the interpolated normal | ||
| 30 | varying vec4 normal; | ||
| 31 | |||
| 32 | void main(void) { | ||
| 33 | // compute the index of the cascade to use and the corresponding texture coordinates | ||
| 34 | int shadowIndex = int(dot(step(vec3(position.z), shadowDistances), vec3(1.0, 1.0, 1.0))); | ||
| 35 | vec3 shadowTexCoord = vec3(dot(gl_EyePlaneS[shadowIndex], position), dot(gl_EyePlaneT[shadowIndex], position), | ||
| 36 | dot(gl_EyePlaneR[shadowIndex], position)); | ||
| 37 | |||
| 38 | // compute the base color based on OpenGL lighting model | ||
| 39 | float diffuse = dot(normalize(normal), gl_LightSource[0].position); | ||
| 40 | float facingLight = step(0.0, diffuse) * 0.25 * | ||
| 41 | (shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, -shadowScale, 0.0)).r + | ||
| 42 | shadow2D(shadowMap, shadowTexCoord + vec3(-shadowScale, shadowScale, 0.0)).r + | ||
| 43 | shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, -shadowScale, 0.0)).r + | ||
| 44 | shadow2D(shadowMap, shadowTexCoord + vec3(shadowScale, shadowScale, 0.0)).r); | ||
| 45 | vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + | ||
| 46 | gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); | ||
| 47 | gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st); | ||
| 48 | } | ||
| @@ -0,0 +1,32 @@ | |||
| 1 | #version 120 | ||
| 2 | |||
| 3 | // | ||
| 4 | // metavoxel_heightfield_cursor.frag | ||
| 5 | // fragment shader | ||
| 6 | // | ||
| 7 | // Created by Andrzej Kapolka on 8/7/14. | ||
| 8 | // Copyright 2014 High Fidelity, Inc. | ||
| 9 | // | ||
| 10 | // Distributed under the Apache License, Version 2.0. | ||
| 11 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 12 | // | ||
| 13 | |||
| 14 | // the inner radius of the outline, squared | ||
| 15 | const float SQUARED_OUTLINE_INNER_RADIUS = 0.81; | ||
| 16 | |||
| 17 | // the outer radius of the outline, squared | ||
| 18 | const float SQUARED_OUTLINE_OUTER_RADIUS = 1.0; | ||
| 19 | |||
| 20 | // the inner radius of the inset, squared | ||
| 21 | const float SQUARED_INSET_INNER_RADIUS = 0.855625; | ||
| 22 | |||
| 23 | // the outer radius of the inset, squared | ||
| 24 | const float SQUARED_INSET_OUTER_RADIUS = 0.950625; | ||
| 25 | |||
| 26 | void main(void) { | ||
| 27 | // use the distance to compute the ring color, then multiply it by the varying color | ||
| 28 | float squaredDistance = dot(gl_TexCoord[0].st, gl_TexCoord[0].st); | ||
| 29 | float alpha = step(SQUARED_OUTLINE_INNER_RADIUS, squaredDistance) * step(squaredDistance, SQUARED_OUTLINE_OUTER_RADIUS); | ||
| 30 | float white = step(SQUARED_INSET_INNER_RADIUS, squaredDistance) * step(squaredDistance, SQUARED_INSET_OUTER_RADIUS); | ||
| 31 | gl_FragColor = gl_Color * vec4(white, white, white, alpha); | ||
| 32 | } | ||
| @@ -0,0 +1,28 @@ | |||
| 1 | #version 120 | ||
| 2 | |||
| 3 | // | ||
| 4 | // metavoxel_heighfield_cursor.vert | ||
| 5 | // vertex shader | ||
| 6 | // | ||
| 7 | // Created by Andrzej Kapolka on 8/7/14. | ||
| 8 | // Copyright 2014 High Fidelity, Inc. | ||
| 9 | // | ||
| 10 | // Distributed under the Apache License, Version 2.0. | ||
| 11 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 12 | // | ||
| 13 | |||
| 14 | // the height texture | ||
| 15 | uniform sampler2D heightMap; | ||
| 16 | |||
| 17 | void main(void) { | ||
| 18 | // compute the view space coordinates | ||
| 19 | float height = texture2D(heightMap, gl_MultiTexCoord0.st).r; | ||
| 20 | vec4 viewPosition = gl_ModelViewMatrix * (gl_Vertex + vec4(0.0, height, 0.0, 0.0)); | ||
| 21 | gl_Position = gl_ProjectionMatrix * viewPosition; | ||
| 22 | |||
| 23 | // generate the texture coordinates from the view position | ||
| 24 | gl_TexCoord[0] = vec4(dot(viewPosition, gl_EyePlaneS[4]), dot(viewPosition, gl_EyePlaneT[4]), 0.0, 1.0); | ||
| 25 | |||
| 26 | // the zero height should be invisible | ||
| 27 | gl_FrontColor = vec4(1.0, 1.0, 1.0, 1.0 - step(height, 0.0)); | ||
| 28 | } | ||
| @@ -0,0 +1,37 @@ | |||
| 1 | #version 120 | ||
| 2 | |||
| 3 | // | ||
| 4 | // metavoxel_heightfield.frag | ||
| 5 | // fragment shader | ||
| 6 | // | ||
| 7 | // Created by Andrzej Kapolka on 7/28/14. | ||
| 8 | // Copyright 2014 High Fidelity, Inc. | ||
| 9 | // | ||
| 10 | // Distributed under the Apache License, Version 2.0. | ||
| 11 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 12 | // | ||
| 13 | |||
| 14 | // the diffuse texture | ||
| 15 | uniform sampler2D diffuseMap; | ||
| 16 | |||
| 17 | // the shadow texture | ||
| 18 | uniform sampler2DShadow shadowMap; | ||
| 19 | |||
| 20 | // the inverse of the size of the shadow map | ||
| 21 | const float shadowScale = 1.0 / 2048.0; | ||
| 22 | |||
| 23 | // the interpolated normal | ||
| 24 | varying vec4 normal; | ||
| 25 | |||
| 26 | void main(void) { | ||
| 27 | // compute the base color based on OpenGL lighting model | ||
| 28 | float diffuse = dot(normalize(normal), gl_LightSource[0].position); | ||
| 29 | float facingLight = step(0.0, diffuse) * 0.25 * | ||
| 30 | (shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, -shadowScale, 0.0)).r + | ||
| 31 | shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(-shadowScale, shadowScale, 0.0)).r + | ||
| 32 | shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, -shadowScale, 0.0)).r + | ||
| 33 | shadow2D(shadowMap, gl_TexCoord[1].stp + vec3(shadowScale, shadowScale, 0.0)).r); | ||
| 34 | vec4 base = gl_Color * (gl_FrontLightModelProduct.sceneColor + gl_FrontLightProduct[0].ambient + | ||
| 35 | gl_FrontLightProduct[0].diffuse * (diffuse * facingLight)); | ||
| 36 | gl_FragColor = base * texture2D(diffuseMap, gl_TexCoord[0].st); | ||
| 37 | } | ||
| @@ -137,7 +137,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 136 unmodified lines | |||
| 137 | _frameCount(0), | 137 | _frameCount(0), |
| 138 | _fps(60.0f), | 138 | _fps(60.0f), |
| 139 | _justStarted(true), | 139 | _justStarted(true), |
| 140 | _voxelImporter(NULL), | 140 | _voxelImportDialog(NULL), |
| 141 | _voxelImporter(), | ||
| 141 | _importSucceded(false), | 142 | _importSucceded(false), |
| 142 | _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), | 143 | _sharedVoxelSystem(TREE_SCALE, DEFAULT_MAX_VOXELS_PER_SYSTEM, &_clipboard), |
| 143 | _entityClipboardRenderer(), | 144 | _entityClipboardRenderer(), |
| @@ -242,6 +243,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : · 98 unmodified lines | |||
| 242 | 243 | ||
| 243 | connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); | 244 | connect(&domainHandler, SIGNAL(hostnameChanged(const QString&)), SLOT(domainChanged(const QString&))); |
| 244 | connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); | 245 | connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(connectedToDomain(const QString&))); |
| 246 | connect(&domainHandler, SIGNAL(connectedToDomain(const QString&)), SLOT(updateWindowTitle())); | ||
| 247 | connect(&domainHandler, SIGNAL(disconnectedFromDomain()), SLOT(updateWindowTitle())); | ||
| 245 | connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived); | 248 | connect(&domainHandler, &DomainHandler::settingsReceived, this, &Application::domainSettingsReceived); |
| 246 | 249 | ||
| 247 | // hookup VoxelEditSender to PaymentManager so we can pay for octree edits | 250 | // hookup VoxelEditSender to PaymentManager so we can pay for octree edits |
| @@ -430,7 +433,7 @@ Application::~Application() { · 182 unmodified lines | |||
| 430 | delete idleTimer; | 433 | delete idleTimer; |
| 431 | 434 | ||
| 432 | _sharedVoxelSystem.changeTree(new VoxelTree); | 435 | _sharedVoxelSystem.changeTree(new VoxelTree); |
| 433 | delete _voxelImporter; | 436 | delete _voxelImportDialog; |
| 434 | 437 | ||
| 435 | // let the avatar mixer know we're out | 438 | // let the avatar mixer know we're out |
| 436 | MyAvatar::sendKillAvatar(); | 439 | MyAvatar::sendKillAvatar(); |
| @@ -465,8 +468,8 @@ void Application::saveSettings() { · 28 unmodified lines | |||
| 465 | Menu::getInstance()->saveSettings(); | 468 | Menu::getInstance()->saveSettings(); |
| 466 | _rearMirrorTools->saveSettings(_settings); | 469 | _rearMirrorTools->saveSettings(_settings); |
| 467 | 470 | ||
| 468 | if (_voxelImporter) { | 471 | if (_voxelImportDialog) { |
| 469 | _voxelImporter->saveSettings(_settings); | 472 | _voxelImportDialog->saveSettings(_settings); |
| 470 | } | 473 | } |
| 471 | _settings->sync(); | 474 | _settings->sync(); |
| 472 | _numChangedSettings = 0; | 475 | _numChangedSettings = 0; |
| @@ -599,7 +602,7 @@ void Application::paintGL() { · 126 unmodified lines | |||
| 599 | 602 | ||
| 600 | if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { | 603 | if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { |
| 601 | _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay | 604 | _myCamera.setTightness(0.0f); // In first person, camera follows (untweaked) head exactly without delay |
| 602 | _myCamera.setTargetPosition(_myAvatar->getHead()->getFilteredEyePosition()); | 605 | _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition()); |
| 603 | _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); | 606 | _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); |
| 604 | 607 | ||
| 605 | } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { | 608 | } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { |
| @@ -621,7 +624,7 @@ void Application::paintGL() { · 15 unmodified lines | |||
| 621 | _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0)); | 624 | _myCamera.setTargetPosition(_myAvatar->getHead()->getEyePosition() + glm::vec3(0, _raiseMirror * _myAvatar->getScale(), 0)); |
| 622 | } else { | 625 | } else { |
| 623 | _myCamera.setTightness(0.0f); | 626 | _myCamera.setTightness(0.0f); |
| 624 | glm::vec3 eyePosition = _myAvatar->getHead()->getFilteredEyePosition(); | 627 | glm::vec3 eyePosition = _myAvatar->getHead()->getEyePosition(); |
| 625 | float headHeight = eyePosition.y - _myAvatar->getPosition().y; | 628 | float headHeight = eyePosition.y - _myAvatar->getPosition().y; |
| 626 | _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); | 629 | _myCamera.setDistance(MIRROR_FULLSCREEN_DISTANCE * _scaleMirror); |
| 627 | _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0)); | 630 | _myCamera.setTargetPosition(_myAvatar->getPosition() + glm::vec3(0, headHeight + (_raiseMirror * _myAvatar->getScale()), 0)); |
| @@ -814,9 +817,8 @@ bool Application::event(QEvent* event) { · 186 unmodified lines | |||
| 814 | QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event); | 817 | QFileOpenEvent* fileEvent = static_cast<QFileOpenEvent*>(event); |
| 815 | bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME); | 818 | bool isHifiSchemeURL = !fileEvent->url().isEmpty() && fileEvent->url().toLocalFile().startsWith(CUSTOM_URL_SCHEME); |
| 816 | if (isHifiSchemeURL) { | 819 | if (isHifiSchemeURL) { |
| 817 | Menu::getInstance()->goTo(fileEvent->url().toString()); | 820 | Menu::getInstance()->goToURL(fileEvent->url().toLocalFile()); |
| 818 | } | 821 | } |
| 819 | |||
| 820 | return false; | 822 | return false; |
| 821 | } | 823 | } |
| 822 | return QApplication::event(event); | 824 | return QApplication::event(event); |
| @@ -1440,6 +1442,15 @@ void Application::setEnable3DTVMode(bool enable3DTVMode) { · 617 unmodified lines | |||
| 1440 | } | 1442 | } |
| 1441 | 1443 | ||
| 1442 | void Application::setEnableVRMode(bool enableVRMode) { | 1444 | void Application::setEnableVRMode(bool enableVRMode) { |
| 1445 | if (enableVRMode) { | ||
| 1446 | if (!OculusManager::isConnected()) { | ||
| 1447 | // attempt to reconnect the Oculus manager - it's possible this was a workaround | ||
| 1448 | // for the sixense crash | ||
| 1449 | OculusManager::disconnect(); | ||
| 1450 | OculusManager::connect(); | ||
| 1451 | } | ||
| 1452 | } | ||
| 1453 | |||
| 1443 | resizeGL(_glWidget->width(), _glWidget->height()); | 1454 | resizeGL(_glWidget->width(), _glWidget->height()); |
| 1444 | } | 1455 | } |
| 1445 | 1456 | ||
| @@ -1599,17 +1610,17 @@ void Application::exportVoxels(const VoxelDetail& sourceVoxel) { · 153 unmodified lines | |||
| 1599 | void Application::importVoxels() { | 1610 | void Application::importVoxels() { |
| 1600 | _importSucceded = false; | 1611 | _importSucceded = false; |
| 1601 | 1612 | ||
| 1602 | if (!_voxelImporter) { | 1613 | if (!_voxelImportDialog) { |
| 1603 | _voxelImporter = new VoxelImporter(_window); | 1614 | _voxelImportDialog = new VoxelImportDialog(_window); |
| 1604 | _voxelImporter->loadSettings(_settings); | 1615 | _voxelImportDialog->loadSettings(_settings); |
| 1605 | } | 1616 | } |
| 1606 | 1617 | ||
| 1607 | if (!_voxelImporter->exec()) { | 1618 | if (!_voxelImportDialog->exec()) { |
| 1608 | qDebug() << "Import succeeded." << endl; | 1619 | qDebug() << "Import succeeded." << endl; |
| 1609 | _importSucceded = true; | 1620 | _importSucceded = true; |
| 1610 | } else { | 1621 | } else { |
| 1611 | qDebug() << "Import failed." << endl; | 1622 | qDebug() << "Import failed." << endl; |
| 1612 | if (_sharedVoxelSystem.getTree() == _voxelImporter->getVoxelTree()) { | 1623 | if (_sharedVoxelSystem.getTree() == _voxelImporter.getVoxelTree()) { |
| 1613 | _sharedVoxelSystem.killLocalVoxels(); | 1624 | _sharedVoxelSystem.killLocalVoxels(); |
| 1614 | _sharedVoxelSystem.changeTree(&_clipboard); | 1625 | _sharedVoxelSystem.changeTree(&_clipboard); |
| 1615 | } | 1626 | } |
| @@ -1724,7 +1735,7 @@ void Application::init() { · 108 unmodified lines | |||
| 1724 | // Cleanup of the original shared tree | 1735 | // Cleanup of the original shared tree |
| 1725 | _sharedVoxelSystem.init(); | 1736 | _sharedVoxelSystem.init(); |
| 1726 | 1737 | ||
| 1727 | _voxelImporter = new VoxelImporter(_window); | 1738 | _voxelImportDialog = new VoxelImportDialog(_window); |
| 1728 | 1739 | ||
| 1729 | _environment.init(); | 1740 | _environment.init(); |
| 1730 | 1741 | ||
| @@ -3322,9 +3333,10 @@ void Application::updateWindowTitle(){ · 1591 unmodified lines | |||
| 3322 | QString buildVersion = " (build " + applicationVersion() + ")"; | 3333 | QString buildVersion = " (build " + applicationVersion() + ")"; |
| 3323 | NodeList* nodeList = NodeList::getInstance(); | 3334 | NodeList* nodeList = NodeList::getInstance(); |
| 3324 | 3335 | ||
| 3336 | QString connectionStatus = nodeList->getDomainHandler().isConnected() ? "" : " (NOT CONNECTED) "; | ||
| 3325 | QString username = AccountManager::getInstance().getAccountInfo().getUsername(); | 3337 | QString username = AccountManager::getInstance().getAccountInfo().getUsername(); |
| 3326 | QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) | 3338 | QString title = QString() + (!username.isEmpty() ? username + " @ " : QString()) |
| 3327 | + nodeList->getDomainHandler().getHostname() + buildVersion; | 3339 | + nodeList->getDomainHandler().getHostname() + connectionStatus + buildVersion; |
| 3328 | 3340 | ||
| 3329 | AccountManager& accountManager = AccountManager::getInstance(); | 3341 | AccountManager& accountManager = AccountManager::getInstance(); |
| 3330 | if (accountManager.getAccountInfo().hasBalance()) { | 3342 | if (accountManager.getAccountInfo().hasBalance()) { |
| @@ -87,6 +87,7 @@ · 86 unmodified lines | |||
| 87 | #include "ui/overlays/Overlays.h" | 87 | #include "ui/overlays/Overlays.h" |
| 88 | #include "ui/ApplicationOverlay.h" | 88 | #include "ui/ApplicationOverlay.h" |
| 89 | #include "ui/RunningScriptsWidget.h" | 89 | #include "ui/RunningScriptsWidget.h" |
| 90 | #include "ui/VoxelImportDialog.h" | ||
| 90 | #include "voxels/VoxelFade.h" | 91 | #include "voxels/VoxelFade.h" |
| 91 | #include "voxels/VoxelHideShowThread.h" | 92 | #include "voxels/VoxelHideShowThread.h" |
| 92 | #include "voxels/VoxelImporter.h" | 93 | #include "voxels/VoxelImporter.h" |
| @@ -193,6 +194,7 @@ public: · 100 unmodified lines | |||
| 193 | Camera* getCamera() { return &_myCamera; } | 194 | Camera* getCamera() { return &_myCamera; } |
| 194 | ViewFrustum* getViewFrustum() { return &_viewFrustum; } | 195 | ViewFrustum* getViewFrustum() { return &_viewFrustum; } |
| 195 | ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } | 196 | ViewFrustum* getShadowViewFrustum() { return &_shadowViewFrustum; } |
| 197 | VoxelImporter* getVoxelImporter() { return &_voxelImporter; } | ||
| 196 | VoxelSystem* getVoxels() { return &_voxels; } | 198 | VoxelSystem* getVoxels() { return &_voxels; } |
| 197 | VoxelTree* getVoxelTree() { return _voxels.getTree(); } | 199 | VoxelTree* getVoxelTree() { return _voxels.getTree(); } |
| 198 | const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; } | 200 | const OctreePacketProcessor& getOctreePacketProcessor() const { return _octreeProcessor; } |
| @@ -463,7 +465,8 @@ private: · 264 unmodified lines | |||
| 463 | 465 | ||
| 464 | VoxelSystem _voxels; | 466 | VoxelSystem _voxels; |
| 465 | VoxelTree _clipboard; // if I copy/paste | 467 | VoxelTree _clipboard; // if I copy/paste |
| 466 | VoxelImporter* _voxelImporter; | 468 | VoxelImportDialog* _voxelImportDialog; |
| 469 | VoxelImporter _voxelImporter; | ||
| 467 | bool _importSucceded; | 470 | bool _importSucceded; |
| 468 | VoxelSystem _sharedVoxelSystem; | 471 | VoxelSystem _sharedVoxelSystem; |
| 469 | ViewFrustum _sharedVoxelSystemViewFrustum; | 472 | ViewFrustum _sharedVoxelSystemViewFrustum; |
| @@ -56,7 +56,6 @@ static const int MUTE_ICON_SIZE = 24; · 55 unmodified lines | |||
| 56 | 56 | ||
| 57 | static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100; | 57 | static const int RECEIVED_AUDIO_STREAM_CAPACITY_FRAMES = 100; |
| 58 | 58 | ||
| 59 | |||
| 60 | Audio::Audio(QObject* parent) : | 59 | Audio::Audio(QObject* parent) : |
| 61 | AbstractAudioInterface(parent), | 60 | AbstractAudioInterface(parent), |
| 62 | _audioInput(NULL), | 61 | _audioInput(NULL), |
| @@ -83,6 +82,7 @@ Audio::Audio(QObject* parent) : · 20 unmodified lines | |||
| 83 | _noiseGateSampleCounter(0), | 82 | _noiseGateSampleCounter(0), |
| 84 | _noiseGateOpen(false), | 83 | _noiseGateOpen(false), |
| 85 | _noiseGateEnabled(true), | 84 | _noiseGateEnabled(true), |
| 85 | _peqEnabled(false), | ||
| 86 | _toneInjectionEnabled(false), | 86 | _toneInjectionEnabled(false), |
| 87 | _noiseGateFramesToClose(0), | 87 | _noiseGateFramesToClose(0), |
| 88 | _totalInputAudioSamples(0), | 88 | _totalInputAudioSamples(0), |
| @@ -132,6 +132,7 @@ void Audio::init(QGLWidget *parent) { · 43 unmodified lines | |||
| 132 | void Audio::reset() { | 132 | void Audio::reset() { |
| 133 | _receivedAudioStream.reset(); | 133 | _receivedAudioStream.reset(); |
| 134 | resetStats(); | 134 | resetStats(); |
| 135 | _peq.reset(); | ||
| 135 | } | 136 | } |
| 136 | 137 | ||
| 137 | void Audio::resetStats() { | 138 | void Audio::resetStats() { |
| @@ -418,9 +419,15 @@ void Audio::start() { · 280 unmodified lines | |||
| 418 | if (!outputFormatSupported) { | 419 | if (!outputFormatSupported) { |
| 419 | qDebug() << "Unable to set up audio output because of a problem with output format."; | 420 | qDebug() << "Unable to set up audio output because of a problem with output format."; |
| 420 | } | 421 | } |
| 422 | |||
| 423 | _peq.initialize( _inputFormat.sampleRate(), _audioInput->bufferSize() ); | ||
| 424 | |||
| 421 | } | 425 | } |
| 422 | 426 | ||
| 423 | void Audio::stop() { | 427 | void Audio::stop() { |
| 428 | |||
| 429 | _peq.finalize(); | ||
| 430 | |||
| 424 | // "switch" to invalid devices in order to shut down the state | 431 | // "switch" to invalid devices in order to shut down the state |
| 425 | switchInputToAudioDevice(QAudioDeviceInfo()); | 432 | switchInputToAudioDevice(QAudioDeviceInfo()); |
| 426 | switchOutputToAudioDevice(QAudioDeviceInfo()); | 433 | switchOutputToAudioDevice(QAudioDeviceInfo()); |
| @@ -462,7 +469,15 @@ void Audio::handleAudioInput() { · 35 unmodified lines | |||
| 462 | int inputSamplesRequired = (int)((float)NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio); | 469 | int inputSamplesRequired = (int)((float)NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL * inputToNetworkInputRatio); |
| 463 | 470 | ||
| 464 | QByteArray inputByteArray = _inputDevice->readAll(); | 471 | QByteArray inputByteArray = _inputDevice->readAll(); |
| 465 | 472 | ||
| 473 | if (_peqEnabled && !_muted) { | ||
| 474 | // we wish to pre-filter our captured input, prior to loopback | ||
| 475 | |||
| 476 | int16_t* ioBuffer = (int16_t*)inputByteArray.data(); | ||
| 477 | |||
| 478 | _peq.render( ioBuffer, ioBuffer, inputByteArray.size() / sizeof(int16_t) ); | ||
| 479 | } | ||
| 480 | |||
| 466 | if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) { | 481 | if (Menu::getInstance()->isOptionChecked(MenuOption::EchoLocalAudio) && !_muted && _audioOutput) { |
| 467 | // if this person wants local loopback add that to the locally injected audio | 482 | // if this person wants local loopback add that to the locally injected audio |
| 468 | 483 | ||
| @@ -1172,6 +1187,31 @@ void Audio::renderToolBox(int x, int y, bool boxed) { · 703 unmodified lines | |||
| 1172 | glDisable(GL_TEXTURE_2D); | 1187 | glDisable(GL_TEXTURE_2D); |
| 1173 | } | 1188 | } |
| 1174 | 1189 | ||
| 1190 | void Audio::toggleAudioFilter() { | ||
| 1191 | _peqEnabled = !_peqEnabled; | ||
| 1192 | } | ||
| 1193 | |||
| 1194 | void Audio::selectAudioFilterFlat() { | ||
| 1195 | if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterFlat)) { | ||
| 1196 | _peq.loadProfile(0); | ||
| 1197 | } | ||
| 1198 | } | ||
| 1199 | void Audio::selectAudioFilterTrebleCut() { | ||
| 1200 | if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterTrebleCut)) { | ||
| 1201 | _peq.loadProfile(1); | ||
| 1202 | } | ||
| 1203 | } | ||
| 1204 | void Audio::selectAudioFilterBassCut() { | ||
| 1205 | if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterBassCut)) { | ||
| 1206 | _peq.loadProfile(2); | ||
| 1207 | } | ||
| 1208 | } | ||
| 1209 | void Audio::selectAudioFilterSmiley() { | ||
| 1210 | if (Menu::getInstance()->isOptionChecked(MenuOption::AudioFilterSmiley)) { | ||
| 1211 | _peq.loadProfile(3); | ||
| 1212 | } | ||
| 1213 | } | ||
| 1214 | |||
| 1175 | void Audio::toggleScope() { | 1215 | void Audio::toggleScope() { |
| 1176 | _scopeEnabled = !_scopeEnabled; | 1216 | _scopeEnabled = !_scopeEnabled; |
| 1177 | if (_scopeEnabled) { | 1217 | if (_scopeEnabled) { |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | |||
| 19 | #include "AudioStreamStats.h" | 19 | #include "AudioStreamStats.h" |
| 20 | #include "RingBufferHistory.h" | 20 | #include "RingBufferHistory.h" |
| 21 | #include "MovingMinMaxAvg.h" | 21 | #include "MovingMinMaxAvg.h" |
| 22 | #include "AudioFilter.h" | ||
| 22 | 23 | ||
| 23 | #include <QAudio> | 24 | #include <QAudio> |
| 24 | #include <QAudioInput> | 25 | #include <QAudioInput> |
| @@ -125,7 +126,12 @@ public slots: · 100 unmodified lines | |||
| 125 | void selectAudioScopeFiveFrames(); | 126 | void selectAudioScopeFiveFrames(); |
| 126 | void selectAudioScopeTwentyFrames(); | 127 | void selectAudioScopeTwentyFrames(); |
| 127 | void selectAudioScopeFiftyFrames(); | 128 | void selectAudioScopeFiftyFrames(); |
| 128 | 129 | void toggleAudioFilter(); | |
| 130 | void selectAudioFilterFlat(); | ||
| 131 | void selectAudioFilterTrebleCut(); | ||
| 132 | void selectAudioFilterBassCut(); | ||
| 133 | void selectAudioFilterSmiley(); | ||
| 134 | |||
| 129 | virtual void handleAudioByteArray(const QByteArray& audioByteArray); | 135 | virtual void handleAudioByteArray(const QByteArray& audioByteArray); |
| 130 | 136 | ||
| 131 | void sendDownstreamAudioStatsPacket(); | 137 | void sendDownstreamAudioStatsPacket(); |
| @@ -252,12 +258,12 @@ private: · 120 unmodified lines | |||
| 252 | // Audio scope methods for rendering | 258 | // Audio scope methods for rendering |
| 253 | void renderBackground(const float* color, int x, int y, int width, int height); | 259 | void renderBackground(const float* color, int x, int y, int width, int height); |
| 254 | void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols); | 260 | void renderGrid(const float* color, int x, int y, int width, int height, int rows, int cols); |
| 255 | void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray); | 261 | void renderLineStrip(const float* color, int x, int y, int n, int offset, const QByteArray* byteArray); |
| 256 | 262 | ||
| 257 | // audio stats methods for rendering | 263 | // audio stats methods for rendering |
| 258 | void renderAudioStreamStats(const AudioStreamStats& streamStats, int horizontalOffset, int& verticalOffset, | 264 | void renderAudioStreamStats(const AudioStreamStats& streamStats, int horizontalOffset, int& verticalOffset, |
| 259 | float scale, float rotation, int font, const float* color, bool isDownstreamStats = false); | 265 | float scale, float rotation, int font, const float* color, bool isDownstreamStats = false); |
| 260 | 266 | ||
| 261 | // Audio scope data | 267 | // Audio scope data |
| 262 | static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; | 268 | static const unsigned int NETWORK_SAMPLES_PER_FRAME = NETWORK_BUFFER_LENGTH_SAMPLES_PER_CHANNEL; |
| 263 | static const unsigned int DEFAULT_FRAMES_PER_SCOPE = 5; | 269 | static const unsigned int DEFAULT_FRAMES_PER_SCOPE = 5; |
| @@ -270,6 +276,11 @@ private: · 6 unmodified lines | |||
| 270 | int _scopeOutputOffset; | 276 | int _scopeOutputOffset; |
| 271 | int _framesPerScope; | 277 | int _framesPerScope; |
| 272 | int _samplesPerScope; | 278 | int _samplesPerScope; |
| 279 | |||
| 280 | // Multi-band parametric EQ | ||
| 281 | bool _peqEnabled; | ||
| 282 | AudioFilterPEQ3 _peq; | ||
| 283 | |||
| 273 | QMutex _guard; | 284 | QMutex _guard; |
| 274 | QByteArray* _scopeInput; | 285 | QByteArray* _scopeInput; |
| 275 | QByteArray* _scopeOutputLeft; | 286 | QByteArray* _scopeOutputLeft; |
| @@ -486,6 +486,48 @@ Menu::Menu() : · 485 unmodified lines | |||
| 486 | true, | 486 | true, |
| 487 | appInstance->getAudio(), | 487 | appInstance->getAudio(), |
| 488 | SLOT(toggleAudioNoiseReduction())); | 488 | SLOT(toggleAudioNoiseReduction())); |
| 489 | |||
| 490 | addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::AudioFilter, | ||
| 491 | 0, | ||
| 492 | false, | ||
| 493 | appInstance->getAudio(), | ||
| 494 | SLOT(toggleAudioFilter())); | ||
| 495 | |||
| 496 | QMenu* audioFilterMenu = audioDebugMenu->addMenu("Audio Filter Options"); | ||
| 497 | addDisabledActionAndSeparator(audioFilterMenu, "Filter Response"); | ||
| 498 | { | ||
| 499 | QAction *flat = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterFlat, | ||
| 500 | 0, | ||
| 501 | true, | ||
| 502 | appInstance->getAudio(), | ||
| 503 | SLOT(selectAudioFilterFlat())); | ||
| 504 | |||
| 505 | QAction *trebleCut = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterTrebleCut, | ||
| 506 | 0, | ||
| 507 | false, | ||
| 508 | appInstance->getAudio(), | ||
| 509 | SLOT(selectAudioFilterTrebleCut())); | ||
| 510 | |||
| 511 | QAction *bassCut = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterBassCut, | ||
| 512 | 0, | ||
| 513 | false, | ||
| 514 | appInstance->getAudio(), | ||
| 515 | SLOT(selectAudioFilterBassCut())); | ||
| 516 | |||
| 517 | QAction *smiley = addCheckableActionToQMenuAndActionHash(audioFilterMenu, MenuOption::AudioFilterSmiley, | ||
| 518 | 0, | ||
| 519 | false, | ||
| 520 | appInstance->getAudio(), | ||
| 521 | SLOT(selectAudioFilterSmiley())); | ||
| 522 | |||
| 523 | |||
| 524 | QActionGroup* audioFilterGroup = new QActionGroup(audioFilterMenu); | ||
| 525 | audioFilterGroup->addAction(flat); | ||
| 526 | audioFilterGroup->addAction(trebleCut); | ||
| 527 | audioFilterGroup->addAction(bassCut); | ||
| 528 | audioFilterGroup->addAction(smiley); | ||
| 529 | } | ||
| 530 | |||
| 489 | addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio); | 531 | addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoServerAudio); |
| 490 | addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio); | 532 | addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::EchoLocalAudio); |
| 491 | addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false, | 533 | addCheckableActionToQMenuAndActionHash(audioDebugMenu, MenuOption::StereoAudio, 0, false, |
| @@ -1111,8 +1153,8 @@ void Menu::goTo() { · 619 unmodified lines | |||
| 1111 | } | 1153 | } |
| 1112 | 1154 | ||
| 1113 | bool Menu::goToURL(QString location) { | 1155 | bool Menu::goToURL(QString location) { |
| 1114 | if (location.startsWith(CUSTOM_URL_SCHEME + "//")) { | 1156 | if (location.startsWith(CUSTOM_URL_SCHEME + "/")) { |
| 1115 | QStringList urlParts = location.remove(0, CUSTOM_URL_SCHEME.length() + 2).split('/', QString::SkipEmptyParts); | 1157 | QStringList urlParts = location.remove(0, CUSTOM_URL_SCHEME.length()).split('/', QString::SkipEmptyParts); |
| 1116 | 1158 | ||
| 1117 | if (urlParts.count() > 1) { | 1159 | if (urlParts.count() > 1) { |
| 1118 | // if url has 2 or more parts, the first one is domain name | 1160 | // if url has 2 or more parts, the first one is domain name |
| @@ -311,6 +311,11 @@ namespace MenuOption { · 310 unmodified lines | |||
| 311 | const QString Animations = "Animations..."; | 311 | const QString Animations = "Animations..."; |
| 312 | const QString Atmosphere = "Atmosphere"; | 312 | const QString Atmosphere = "Atmosphere"; |
| 313 | const QString Attachments = "Attachments..."; | 313 | const QString Attachments = "Attachments..."; |
| 314 | const QString AudioFilter = "Audio Filter Bank"; | ||
| 315 | const QString AudioFilterFlat = "Flat Response"; | ||
| 316 | const QString AudioFilterTrebleCut= "Treble Cut"; | ||
| 317 | const QString AudioFilterBassCut = "Bass Cut"; | ||
| 318 | const QString AudioFilterSmiley = "Smiley Curve"; | ||
| 314 | const QString AudioNoiseReduction = "Audio Noise Reduction"; | 319 | const QString AudioNoiseReduction = "Audio Noise Reduction"; |
| 315 | const QString AudioScope = "Audio Scope"; | 320 | const QString AudioScope = "Audio Scope"; |
| 316 | const QString AudioScopeFiftyFrames = "Fifty"; | 321 | const QString AudioScopeFiftyFrames = "Fifty"; |
| @@ -37,6 +37,9 @@ void MetavoxelSystem::init() { · 36 unmodified lines | |||
| 37 | _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer")); | 37 | _pointBufferAttribute = AttributeRegistry::getInstance()->registerAttribute(new BufferDataAttribute("pointBuffer")); |
| 38 | _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute( | 38 | _heightfieldBufferAttribute = AttributeRegistry::getInstance()->registerAttribute( |
| 39 | new BufferDataAttribute("heightfieldBuffer")); | 39 | new BufferDataAttribute("heightfieldBuffer")); |
| 40 | |||
| 41 | _heightfieldBufferAttribute->setLODThresholdMultiplier( | ||
| 42 | AttributeRegistry::getInstance()->getHeightfieldAttribute()->getLODThresholdMultiplier()); | ||
| 40 | } | 43 | } |
| 41 | 44 | ||
| 42 | MetavoxelLOD MetavoxelSystem::getLOD() { | 45 | MetavoxelLOD MetavoxelSystem::getLOD() { |
| @@ -118,6 +121,334 @@ void MetavoxelSystem::render() { · 75 unmodified lines | |||
| 118 | guideToAugmented(renderVisitor); | 121 | guideToAugmented(renderVisitor); |
| 119 | } | 122 | } |
| 120 | 123 | ||
| 124 | class RayHeightfieldIntersectionVisitor : public RayIntersectionVisitor { | ||
| 125 | public: | ||
| 126 | |||
| 127 | float intersectionDistance; | ||
| 128 | |||
| 129 | RayHeightfieldIntersectionVisitor(const glm::vec3& origin, const glm::vec3& direction, const MetavoxelLOD& lod); | ||
| 130 | |||
| 131 | virtual int visit(MetavoxelInfo& info, float distance); | ||
| 132 | }; | ||
| 133 | |||
| 134 | RayHeightfieldIntersectionVisitor::RayHeightfieldIntersectionVisitor(const glm::vec3& origin, | ||
| 135 | const glm::vec3& direction, const MetavoxelLOD& lod) : | ||
| 136 | RayIntersectionVisitor(origin, direction, QVector<AttributePointer>() << | ||
| 137 | Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>(), lod), | ||
| 138 | intersectionDistance(FLT_MAX) { | ||
| 139 | } | ||
| 140 | |||
| 141 | static const float EIGHT_BIT_MAXIMUM_RECIPROCAL = 1.0f / 255.0f; | ||
| 142 | |||
| 143 | int RayHeightfieldIntersectionVisitor::visit(MetavoxelInfo& info, float distance) { | ||
| 144 | if (!info.isLeaf) { | ||
| 145 | return _order; | ||
| 146 | } | ||
| 147 | const HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>( | ||
| 148 | info.inputValues.at(0).getInlineValue<BufferDataPointer>().data()); | ||
| 149 | if (!buffer) { | ||
| 150 | return STOP_RECURSION; | ||
| 151 | } | ||
| 152 | const QByteArray& contents = buffer->getHeight(); | ||
| 153 | const uchar* src = (const uchar*)contents.constData(); | ||
| 154 | int size = glm::sqrt((float)contents.size()); | ||
| 155 | int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION; | ||
| 156 | int highest = HeightfieldBuffer::HEIGHT_BORDER + unextendedSize; | ||
| 157 | float heightScale = unextendedSize * EIGHT_BIT_MAXIMUM_RECIPROCAL; | ||
| 158 | |||
| 159 | // find the initial location in heightfield coordinates | ||
| 160 | glm::vec3 entry = (_origin + distance * _direction - info.minimum) * (float)unextendedSize / info.size; | ||
| 161 | entry.x += HeightfieldBuffer::HEIGHT_BORDER; | ||
| 162 | entry.z += HeightfieldBuffer::HEIGHT_BORDER; | ||
| 163 | glm::vec3 floors = glm::floor(entry); | ||
| 164 | glm::vec3 ceils = glm::ceil(entry); | ||
| 165 | if (floors.x == ceils.x) { | ||
| 166 | if (_direction.x > 0.0f) { | ||
| 167 | ceils.x += 1.0f; | ||
| 168 | } else { | ||
| 169 | floors.x -= 1.0f; | ||
| 170 | } | ||
| 171 | } | ||
| 172 | if (floors.z == ceils.z) { | ||
| 173 | if (_direction.z > 0.0f) { | ||
| 174 | ceils.z += 1.0f; | ||
| 175 | } else { | ||
| 176 | floors.z -= 1.0f; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | bool withinBounds = true; | ||
| 181 | float accumulatedDistance = 0.0f; | ||
| 182 | while (withinBounds) { | ||
| 183 | // find the heights at the corners of the current cell | ||
| 184 | int floorX = qMin(qMax((int)floors.x, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 185 | int floorZ = qMin(qMax((int)floors.z, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 186 | int ceilX = qMin(qMax((int)ceils.x, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 187 | int ceilZ = qMin(qMax((int)ceils.z, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 188 | float upperLeft = src[floorZ * size + floorX] * heightScale; | ||
| 189 | float upperRight = src[floorZ * size + ceilX] * heightScale; | ||
| 190 | float lowerLeft = src[ceilZ * size + floorX] * heightScale; | ||
| 191 | float lowerRight = src[ceilZ * size + ceilX] * heightScale; | ||
| 192 | |||
| 193 | // find the distance to the next x coordinate | ||
| 194 | float xDistance = FLT_MAX; | ||
| 195 | if (_direction.x > 0.0f) { | ||
| 196 | xDistance = (ceils.x - entry.x) / _direction.x; | ||
| 197 | } else if (_direction.x < 0.0f) { | ||
| 198 | xDistance = (floors.x - entry.x) / _direction.x; | ||
| 199 | } | ||
| 200 | |||
| 201 | // and the distance to the next z coordinate | ||
| 202 | float zDistance = FLT_MAX; | ||
| 203 | if (_direction.z > 0.0f) { | ||
| 204 | zDistance = (ceils.z - entry.z) / _direction.z; | ||
| 205 | } else if (_direction.z < 0.0f) { | ||
| 206 | zDistance = (floors.z - entry.z) / _direction.z; | ||
| 207 | } | ||
| 208 | |||
| 209 | // the exit distance is the lower of those two | ||
| 210 | float exitDistance = qMin(xDistance, zDistance); | ||
| 211 | glm::vec3 exit, nextFloors = floors, nextCeils = ceils; | ||
| 212 | if (exitDistance == FLT_MAX) { | ||
| 213 | if (_direction.y > 0.0f) { | ||
| 214 | return SHORT_CIRCUIT; // line points upwards; no collisions possible | ||
| 215 | } | ||
| 216 | withinBounds = false; // line points downwards; check this cell only | ||
| 217 | |||
| 218 | } else { | ||
| 219 | // find the exit point and the next cell, and determine whether it's still within the bounds | ||
| 220 | exit = entry + exitDistance * _direction; | ||
| 221 | withinBounds = (exit.y >= HeightfieldBuffer::HEIGHT_BORDER && exit.y <= highest); | ||
| 222 | if (exitDistance == xDistance) { | ||
| 223 | if (_direction.x > 0.0f) { | ||
| 224 | nextFloors.x += 1.0f; | ||
| 225 | withinBounds &= (nextCeils.x += 1.0f) <= highest; | ||
| 226 | } else { | ||
| 227 | withinBounds &= (nextFloors.x -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER; | ||
| 228 | nextCeils.x -= 1.0f; | ||
| 229 | } | ||
| 230 | } | ||
| 231 | if (exitDistance == zDistance) { | ||
| 232 | if (_direction.z > 0.0f) { | ||
| 233 | nextFloors.z += 1.0f; | ||
| 234 | withinBounds &= (nextCeils.z += 1.0f) <= highest; | ||
| 235 | } else { | ||
| 236 | withinBounds &= (nextFloors.z -= 1.0f) >= HeightfieldBuffer::HEIGHT_BORDER; | ||
| 237 | nextCeils.z -= 1.0f; | ||
| 238 | } | ||
| 239 | } | ||
| 240 | // check the vertical range of the ray against the ranges of the cell heights | ||
| 241 | if (qMin(entry.y, exit.y) > qMax(qMax(upperLeft, upperRight), qMax(lowerLeft, lowerRight)) || | ||
| 242 | qMax(entry.y, exit.y) < qMin(qMin(upperLeft, upperRight), qMin(lowerLeft, lowerRight))) { | ||
| 243 | entry = exit; | ||
| 244 | floors = nextFloors; | ||
| 245 | ceils = nextCeils; | ||
| 246 | accumulatedDistance += exitDistance; | ||
| 247 | continue; | ||
| 248 | } | ||
| 249 | } | ||
| 250 | // having passed the bounds check, we must check against the planes | ||
| 251 | glm::vec3 relativeEntry = entry - glm::vec3(floors.x, upperLeft, floors.z); | ||
| 252 | |||
| 253 | // first check the triangle including the Z+ segment | ||
| 254 | glm::vec3 lowerNormal(lowerLeft - lowerRight, 1.0f, upperLeft - lowerLeft); | ||
| 255 | float lowerProduct = glm::dot(lowerNormal, _direction); | ||
| 256 | if (lowerProduct < 0.0f) { | ||
| 257 | float planeDistance = -glm::dot(lowerNormal, relativeEntry) / lowerProduct; | ||
| 258 | glm::vec3 intersection = relativeEntry + planeDistance * _direction; | ||
| 259 | if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && | ||
| 260 | intersection.z >= intersection.x) { | ||
| 261 | intersectionDistance = qMin(intersectionDistance, distance + | ||
| 262 | (accumulatedDistance + planeDistance) * (info.size / unextendedSize)); | ||
| 263 | return SHORT_CIRCUIT; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | // then the one with the X+ segment | ||
| 268 | glm::vec3 upperNormal(upperLeft - upperRight, 1.0f, upperRight - lowerRight); | ||
| 269 | float upperProduct = glm::dot(upperNormal, _direction); | ||
| 270 | if (upperProduct < 0.0f) { | ||
| 271 | float planeDistance = -glm::dot(upperNormal, relativeEntry) / upperProduct; | ||
| 272 | glm::vec3 intersection = relativeEntry + planeDistance * _direction; | ||
| 273 | if (intersection.x >= 0.0f && intersection.x <= 1.0f && intersection.z >= 0.0f && intersection.z <= 1.0f && | ||
| 274 | intersection.x >= intersection.z) { | ||
| 275 | intersectionDistance = qMin(intersectionDistance, distance + | ||
| 276 | (accumulatedDistance + planeDistance) * (info.size / unextendedSize)); | ||
| 277 | return SHORT_CIRCUIT; | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | // no joy; continue on our way | ||
| 282 | entry = exit; | ||
| 283 | floors = nextFloors; | ||
| 284 | ceils = nextCeils; | ||
| 285 | accumulatedDistance += exitDistance; | ||
| 286 | } | ||
| 287 | |||
| 288 | return STOP_RECURSION; | ||
| 289 | } | ||
| 290 | |||
| 291 | bool MetavoxelSystem::findFirstRayHeightfieldIntersection(const glm::vec3& origin, | ||
| 292 | const glm::vec3& direction, float& distance) { | ||
| 293 | RayHeightfieldIntersectionVisitor visitor(origin, direction, getLOD()); | ||
| 294 | guideToAugmented(visitor); | ||
| 295 | if (visitor.intersectionDistance == FLT_MAX) { | ||
| 296 | return false; | ||
| 297 | } | ||
| 298 | distance = visitor.intersectionDistance; | ||
| 299 | return true; | ||
| 300 | } | ||
| 301 | |||
| 302 | class HeightfieldHeightVisitor : public MetavoxelVisitor { | ||
| 303 | public: | ||
| 304 | |||
| 305 | float height; | ||
| 306 | |||
| 307 | HeightfieldHeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location); | ||
| 308 | |||
| 309 | virtual int visit(MetavoxelInfo& info); | ||
| 310 | |||
| 311 | private: | ||
| 312 | |||
| 313 | glm::vec3 _location; | ||
| 314 | }; | ||
| 315 | |||
| 316 | HeightfieldHeightVisitor::HeightfieldHeightVisitor(const MetavoxelLOD& lod, const glm::vec3& location) : | ||
| 317 | MetavoxelVisitor(QVector<AttributePointer>() << | ||
| 318 | Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>(), lod), | ||
| 319 | height(-FLT_MAX), | ||
| 320 | _location(location) { | ||
| 321 | } | ||
| 322 | |||
| 323 | static const int REVERSE_ORDER = MetavoxelVisitor::encodeOrder(7, 6, 5, 4, 3, 2, 1, 0); | ||
| 324 | |||
| 325 | int HeightfieldHeightVisitor::visit(MetavoxelInfo& info) { | ||
| 326 | glm::vec3 relative = _location - info.minimum; | ||
| 327 | if (relative.x < 0.0f || relative.z < 0.0f || relative.x > info.size || relative.z > info.size || | ||
| 328 | height >= info.minimum.y + info.size) { | ||
| 329 | return STOP_RECURSION; | ||
| 330 | } | ||
| 331 | if (!info.isLeaf) { | ||
| 332 | return REVERSE_ORDER; | ||
| 333 | } | ||
| 334 | const HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>( | ||
| 335 | info.inputValues.at(0).getInlineValue<BufferDataPointer>().data()); | ||
| 336 | if (!buffer) { | ||
| 337 | return STOP_RECURSION; | ||
| 338 | } | ||
| 339 | const QByteArray& contents = buffer->getHeight(); | ||
| 340 | const uchar* src = (const uchar*)contents.constData(); | ||
| 341 | int size = glm::sqrt((float)contents.size()); | ||
| 342 | int unextendedSize = size - HeightfieldBuffer::HEIGHT_EXTENSION; | ||
| 343 | int highest = HeightfieldBuffer::HEIGHT_BORDER + unextendedSize; | ||
| 344 | relative *= unextendedSize / info.size; | ||
| 345 | relative.x += HeightfieldBuffer::HEIGHT_BORDER; | ||
| 346 | relative.z += HeightfieldBuffer::HEIGHT_BORDER; | ||
| 347 | |||
| 348 | // find the bounds of the cell containing the point and the shared vertex heights | ||
| 349 | glm::vec3 floors = glm::floor(relative); | ||
| 350 | glm::vec3 ceils = glm::ceil(relative); | ||
| 351 | glm::vec3 fracts = glm::fract(relative); | ||
| 352 | int floorX = qMin(qMax((int)floors.x, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 353 | int floorZ = qMin(qMax((int)floors.z, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 354 | int ceilX = qMin(qMax((int)ceils.x, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 355 | int ceilZ = qMin(qMax((int)ceils.z, HeightfieldBuffer::HEIGHT_BORDER), highest); | ||
| 356 | float upperLeft = src[floorZ * size + floorX]; | ||
| 357 | float lowerRight = src[ceilZ * size + ceilX]; | ||
| 358 | float interpolatedHeight = glm::mix(upperLeft, lowerRight, fracts.z); | ||
| 359 | |||
| 360 | // the final vertex (and thus which triangle we check) depends on which half we're on | ||
| 361 | if (fracts.x >= fracts.z) { | ||
| 362 | float upperRight = src[floorZ * size + ceilX]; | ||
| 363 | interpolatedHeight = glm::mix(interpolatedHeight, glm::mix(upperRight, lowerRight, fracts.z), | ||
| 364 | (fracts.x - fracts.z) / (1.0f - fracts.z)); | ||
| 365 | |||
| 366 | } else { | ||
| 367 | float lowerLeft = src[ceilZ * size + floorX]; | ||
| 368 | interpolatedHeight = glm::mix(glm::mix(upperLeft, lowerLeft, fracts.z), interpolatedHeight, fracts.x / fracts.z); | ||
| 369 | } | ||
| 370 | if (interpolatedHeight == 0.0f) { | ||
| 371 | return STOP_RECURSION; // ignore zero values | ||
| 372 | } | ||
| 373 | |||
| 374 | // convert the interpolated height into world space | ||
| 375 | height = qMax(height, info.minimum.y + interpolatedHeight * info.size * EIGHT_BIT_MAXIMUM_RECIPROCAL); | ||
| 376 | return SHORT_CIRCUIT; | ||
| 377 | } | ||
| 378 | |||
| 379 | float MetavoxelSystem::getHeightfieldHeight(const glm::vec3& location) { | ||
| 380 | HeightfieldHeightVisitor visitor(getLOD(), location); | ||
| 381 | guideToAugmented(visitor); | ||
| 382 | return visitor.height; | ||
| 383 | } | ||
| 384 | |||
| 385 | class HeightfieldCursorRenderVisitor : public MetavoxelVisitor { | ||
| 386 | public: | ||
| 387 | |||
| 388 | HeightfieldCursorRenderVisitor(const Box& bounds); | ||
| 389 | |||
| 390 | virtual int visit(MetavoxelInfo& info); | ||
| 391 | |||
| 392 | private: | ||
| 393 | |||
| 394 | Box _bounds; | ||
| 395 | }; | ||
| 396 | |||
| 397 | HeightfieldCursorRenderVisitor::HeightfieldCursorRenderVisitor(const Box& bounds) : | ||
| 398 | MetavoxelVisitor(QVector<AttributePointer>() << | ||
| 399 | Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()), | ||
| 400 | _bounds(bounds) { | ||
| 401 | } | ||
| 402 | |||
| 403 | int HeightfieldCursorRenderVisitor::visit(MetavoxelInfo& info) { | ||
| 404 | if (!info.getBounds().intersects(_bounds)) { | ||
| 405 | return STOP_RECURSION; | ||
| 406 | } | ||
| 407 | if (!info.isLeaf) { | ||
| 408 | return DEFAULT_ORDER; | ||
| 409 | } | ||
| 410 | BufferDataPointer buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>(); | ||
| 411 | if (buffer) { | ||
| 412 | buffer->render(true); | ||
| 413 | } | ||
| 414 | return STOP_RECURSION; | ||
| 415 | } | ||
| 416 | |||
| 417 | void MetavoxelSystem::renderHeightfieldCursor(const glm::vec3& position, float radius) { | ||
| 418 | glDepthFunc(GL_LEQUAL); | ||
| 419 | glEnable(GL_CULL_FACE); | ||
| 420 | glEnable(GL_POLYGON_OFFSET_FILL); | ||
| 421 | glPolygonOffset(-1.0f, -1.0f); | ||
| 422 | |||
| 423 | glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | ||
| 424 | |||
| 425 | glEnableClientState(GL_VERTEX_ARRAY); | ||
| 426 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | ||
| 427 | |||
| 428 | DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().bind(); | ||
| 429 | |||
| 430 | glActiveTexture(GL_TEXTURE4); | ||
| 431 | float scale = 1.0f / radius; | ||
| 432 | glm::vec4 sCoefficients(scale, 0.0f, 0.0f, -scale * position.x); | ||
| 433 | glm::vec4 tCoefficients(0.0f, 0.0f, scale, -scale * position.z); | ||
| 434 | glTexGenfv(GL_S, GL_EYE_PLANE, (const GLfloat*)&sCoefficients); | ||
| 435 | glTexGenfv(GL_T, GL_EYE_PLANE, (const GLfloat*)&tCoefficients); | ||
| 436 | glActiveTexture(GL_TEXTURE0); | ||
| 437 | |||
| 438 | glm::vec3 extents(radius, radius, radius); | ||
| 439 | HeightfieldCursorRenderVisitor visitor(Box(position - extents, position + extents)); | ||
| 440 | guideToAugmented(visitor); | ||
| 441 | |||
| 442 | DefaultMetavoxelRendererImplementation::getHeightfieldCursorProgram().release(); | ||
| 443 | |||
| 444 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | ||
| 445 | glDisableClientState(GL_VERTEX_ARRAY); | ||
| 446 | |||
| 447 | glDisable(GL_POLYGON_OFFSET_FILL); | ||
| 448 | glDisable(GL_CULL_FACE); | ||
| 449 | glDepthFunc(GL_LESS); | ||
| 450 | } | ||
| 451 | |||
| 121 | void MetavoxelSystem::deleteTextures(int heightID, int colorID) { | 452 | void MetavoxelSystem::deleteTextures(int heightID, int colorID) { |
| 122 | glDeleteTextures(1, (GLuint*)&heightID); | 453 | glDeleteTextures(1, (GLuint*)&heightID); |
| 123 | glDeleteTextures(1, (GLuint*)&colorID); | 454 | glDeleteTextures(1, (GLuint*)&colorID); |
| @@ -239,7 +570,7 @@ PointBuffer::PointBuffer(const BufferPointVector& points) : · 115 unmodified lines | |||
| 239 | _points(points) { | 570 | _points(points) { |
| 240 | } | 571 | } |
| 241 | 572 | ||
| 242 | void PointBuffer::render() { | 573 | void PointBuffer::render(bool cursor) { |
| 243 | // initialize buffer, etc. on first render | 574 | // initialize buffer, etc. on first render |
| 244 | if (!_buffer.isCreated()) { | 575 | if (!_buffer.isCreated()) { |
| 245 | _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); | 576 | _buffer.setUsagePattern(QOpenGLBuffer::StaticDraw); |
| @@ -265,16 +596,32 @@ void PointBuffer::render() { · 19 unmodified lines | |||
| 265 | _buffer.release(); | 596 | _buffer.release(); |
| 266 | } | 597 | } |
| 267 | 598 | ||
| 599 | const int HeightfieldBuffer::HEIGHT_BORDER = 1; | ||
| 600 | const int HeightfieldBuffer::SHARED_EDGE = 1; | ||
| 601 | const int HeightfieldBuffer::HEIGHT_EXTENSION = 2 * HeightfieldBuffer::HEIGHT_BORDER + HeightfieldBuffer::SHARED_EDGE; | ||
| 602 | |||
| 268 | HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, | 603 | HeightfieldBuffer::HeightfieldBuffer(const glm::vec3& translation, float scale, |
| 269 | const QByteArray& height, const QByteArray& color, bool clearAfterLoading) : | 604 | const QByteArray& height, const QByteArray& color) : |
| 270 | _translation(translation), | 605 | _translation(translation), |
| 271 | _scale(scale), | 606 | _scale(scale), |
| 607 | _heightBounds(translation, translation + glm::vec3(scale, scale, scale)), | ||
| 608 | _colorBounds(_heightBounds), | ||
| 272 | _height(height), | 609 | _height(height), |
| 273 | _color(color), | 610 | _color(color), |
| 274 | _clearAfterLoading(clearAfterLoading), | ||
| 275 | _heightTextureID(0), | 611 | _heightTextureID(0), |
| 276 | _colorTextureID(0), | 612 | _colorTextureID(0), |
| 277 | _heightSize(glm::sqrt(height.size())) { | 613 | _heightSize(glm::sqrt(height.size())), |
| 614 | _heightIncrement(scale / (_heightSize - HEIGHT_EXTENSION)), | ||
| 615 | _colorSize(glm::sqrt(color.size() / HeightfieldData::COLOR_BYTES)), | ||
| 616 | _colorIncrement(scale / (_colorSize - SHARED_EDGE)) { | ||
| 617 | |||
| 618 | _heightBounds.minimum.x -= _heightIncrement * HEIGHT_BORDER; | ||
| 619 | _heightBounds.minimum.z -= _heightIncrement * HEIGHT_BORDER; | ||
| 620 | _heightBounds.maximum.x += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER); | ||
| 621 | _heightBounds.maximum.z += _heightIncrement * (SHARED_EDGE + HEIGHT_BORDER); | ||
| 622 | |||
| 623 | _colorBounds.maximum.x += _colorIncrement * SHARED_EDGE; | ||
| 624 | _colorBounds.maximum.z += _colorIncrement * SHARED_EDGE; | ||
| 278 | } | 625 | } |
| 279 | 626 | ||
| 280 | HeightfieldBuffer::~HeightfieldBuffer() { | 627 | HeightfieldBuffer::~HeightfieldBuffer() { |
| @@ -288,25 +635,49 @@ HeightfieldBuffer::~HeightfieldBuffer() { · 7 unmodified lines | |||
| 288 | } | 635 | } |
| 289 | } | 636 | } |
| 290 | 637 | ||
| 638 | QByteArray HeightfieldBuffer::getUnextendedHeight() const { | ||
| 639 | int srcSize = glm::sqrt(_height.size()); | ||
| 640 | int destSize = srcSize - 3; | ||
| 641 | QByteArray unextended(destSize * destSize, 0); | ||
| 642 | const char* src = _height.constData() + srcSize + 1; | ||
| 643 | char* dest = unextended.data(); | ||
| 644 | for (int z = 0; z < destSize; z++, src += srcSize, dest += destSize) { | ||
| 645 | memcpy(dest, src, destSize); | ||
| 646 | } | ||
| 647 | return unextended; | ||
| 648 | } | ||
| 649 | |||
| 650 | QByteArray HeightfieldBuffer::getUnextendedColor() const { | ||
| 651 | int srcSize = glm::sqrt(_color.size() / HeightfieldData::COLOR_BYTES); | ||
| 652 | int destSize = srcSize - 1; | ||
| 653 | QByteArray unextended(destSize * destSize * HeightfieldData::COLOR_BYTES, 0); | ||
| 654 | const char* src = _color.constData(); | ||
| 655 | int srcStride = srcSize * HeightfieldData::COLOR_BYTES; | ||
| 656 | char* dest = unextended.data(); | ||
| 657 | int destStride = destSize * HeightfieldData::COLOR_BYTES; | ||
| 658 | for (int z = 0; z < destSize; z++, src += srcStride, dest += destStride) { | ||
| 659 | memcpy(dest, src, destStride); | ||
| 660 | } | ||
| 661 | return unextended; | ||
| 662 | } | ||
| 663 | |||
| 291 | class HeightfieldPoint { | 664 | class HeightfieldPoint { |
| 292 | public: | 665 | public: |
| 293 | glm::vec2 textureCoord; | 666 | glm::vec2 textureCoord; |
| 294 | glm::vec3 vertex; | 667 | glm::vec3 vertex; |
| 295 | }; | 668 | }; |
| 296 | 669 | ||
| 297 | void HeightfieldBuffer::render() { | 670 | void HeightfieldBuffer::render(bool cursor) { |
| 298 | // initialize textures, etc. on first render | 671 | // initialize textures, etc. on first render |
| 299 | if (_heightTextureID == 0) { | 672 | if (_heightTextureID == 0) { |
| 300 | glGenTextures(1, &_heightTextureID); | 673 | glGenTextures(1, &_heightTextureID); |
| 301 | glBindTexture(GL_TEXTURE_2D, _heightTextureID); | 674 | glBindTexture(GL_TEXTURE_2D, _heightTextureID); |
| 675 | glPixelStorei(GL_UNPACK_ALIGNMENT, 1); | ||
| 302 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); | 676 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); |
| 303 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); | 677 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); |
| 304 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); | 678 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); |
| 305 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, _heightSize, _heightSize, 0, | 679 | glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, _heightSize, _heightSize, 0, |
| 306 | GL_LUMINANCE, GL_UNSIGNED_BYTE, _height.constData()); | 680 | GL_LUMINANCE, GL_UNSIGNED_BYTE, _height.constData()); |
| 307 | if (_clearAfterLoading) { | ||
| 308 | _height.clear(); | ||
| 309 | } | ||
| 310 | 681 | ||
| 311 | glGenTextures(1, &_colorTextureID); | 682 | glGenTextures(1, &_colorTextureID); |
| 312 | glBindTexture(GL_TEXTURE_2D, _colorTextureID); | 683 | glBindTexture(GL_TEXTURE_2D, _colorTextureID); |
| @@ -318,32 +689,32 @@ void HeightfieldBuffer::render() { · 5 unmodified lines | |||
| 318 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR); | 689 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, WHITE_COLOR); |
| 319 | 690 | ||
| 320 | } else { | 691 | } else { |
| 321 | int colorSize = glm::sqrt(_color.size() / 3); | 692 | int colorSize = glm::sqrt(_color.size() / HeightfieldData::COLOR_BYTES); |
| 322 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData()); | 693 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, colorSize, colorSize, 0, GL_RGB, GL_UNSIGNED_BYTE, _color.constData()); |
| 323 | if (_clearAfterLoading) { | ||
| 324 | _color.clear(); | ||
| 325 | } | ||
| 326 | } | 694 | } |
| 327 | } | 695 | } |
| 328 | // create the buffer objects lazily | 696 | // create the buffer objects lazily |
| 329 | int sizeWithSkirt = _heightSize + 2; | 697 | int innerSize = _heightSize - 2 * HeightfieldBuffer::HEIGHT_BORDER; |
| 330 | int vertexCount = sizeWithSkirt * sizeWithSkirt; | 698 | int vertexCount = _heightSize * _heightSize; |
| 331 | int rows = sizeWithSkirt - 1; | 699 | int rows = _heightSize - 1; |
| 332 | int indexCount = rows * rows * 4; | 700 | int indexCount = rows * rows * 3 * 2; |
| 333 | BufferPair& bufferPair = _bufferPairs[_heightSize]; | 701 | BufferPair& bufferPair = _bufferPairs[_heightSize]; |
| 334 | if (!bufferPair.first.isCreated()) { | 702 | if (!bufferPair.first.isCreated()) { |
| 335 | QVector<HeightfieldPoint> vertices(vertexCount); | 703 | QVector<HeightfieldPoint> vertices(vertexCount); |
| 336 | HeightfieldPoint* point = vertices.data(); | 704 | HeightfieldPoint* point = vertices.data(); |
| 337 | 705 | ||
| 338 | float step = 1.0f / (_heightSize - 1); | 706 | float vertexStep = 1.0f / (innerSize - 1); |
| 339 | float z = -step; | 707 | float z = -vertexStep; |
| 340 | for (int i = 0; i < sizeWithSkirt; i++, z += step) { | 708 | float textureStep = 1.0f / _heightSize; |
| 341 | float x = -step; | 709 | float t = textureStep / 2.0f; |
| 710 | for (int i = 0; i < _heightSize; i++, z += vertexStep, t += textureStep) { | ||
| 711 | float x = -vertexStep; | ||
| 712 | float s = textureStep / 2.0f; | ||
| 342 | const float SKIRT_LENGTH = 0.25f; | 713 | const float SKIRT_LENGTH = 0.25f; |
| 343 | float baseY = (i == 0 || i == sizeWithSkirt - 1) ? -SKIRT_LENGTH : 0.0f; | 714 | float baseY = (i == 0 || i == _heightSize - 1) ? -SKIRT_LENGTH : 0.0f; |
| 344 | for (int j = 0; j < sizeWithSkirt; j++, point++, x += step) { | 715 | for (int j = 0; j < _heightSize; j++, point++, x += vertexStep, s += textureStep) { |
| 345 | point->vertex = glm::vec3(x, (j == 0 || j == sizeWithSkirt - 1) ? -SKIRT_LENGTH : baseY, z); | 716 | point->vertex = glm::vec3(x, (j == 0 || j == _heightSize - 1) ? -SKIRT_LENGTH : baseY, z); |
| 346 | point->textureCoord = glm::vec2(x, z); | 717 | point->textureCoord = glm::vec2(s, t); |
| 347 | } | 718 | } |
| 348 | } | 719 | } |
| 349 | 720 | ||
| @@ -355,13 +726,16 @@ void HeightfieldBuffer::render() { · 5 unmodified lines | |||
| 355 | QVector<int> indices(indexCount); | 726 | QVector<int> indices(indexCount); |
| 356 | int* index = indices.data(); | 727 | int* index = indices.data(); |
| 357 | for (int i = 0; i < rows; i++) { | 728 | for (int i = 0; i < rows; i++) { |
| 358 | int lineIndex = i * sizeWithSkirt; | 729 | int lineIndex = i * _heightSize; |
| 359 | int nextLineIndex = (i + 1) * sizeWithSkirt; | 730 | int nextLineIndex = (i + 1) * _heightSize; |
| 360 | for (int j = 0; j < rows; j++) { | 731 | for (int j = 0; j < rows; j++) { |
| 361 | *index++ = lineIndex + j; | 732 | *index++ = lineIndex + j; |
| 362 | *index++ = nextLineIndex + j; | 733 | *index++ = nextLineIndex + j; |
| 734 | *index++ = nextLineIndex + j + 1; | ||
| 735 | |||
| 363 | *index++ = nextLineIndex + j + 1; | 736 | *index++ = nextLineIndex + j + 1; |
| 364 | *index++ = lineIndex + j + 1; | 737 | *index++ = lineIndex + j + 1; |
| 738 | *index++ = lineIndex + j; | ||
| 365 | } | 739 | } |
| 366 | } | 740 | } |
| 367 | 741 | ||
| @@ -385,17 +759,33 @@ void HeightfieldBuffer::render() { · 17 unmodified lines | |||
| 385 | 759 | ||
| 386 | glBindTexture(GL_TEXTURE_2D, _heightTextureID); | 760 | glBindTexture(GL_TEXTURE_2D, _heightTextureID); |
| 387 | 761 | ||
| 388 | glActiveTexture(GL_TEXTURE1); | 762 | if (!cursor) { |
| 389 | glBindTexture(GL_TEXTURE_2D, _colorTextureID); | 763 | int heightScaleLocation = DefaultMetavoxelRendererImplementation::getHeightScaleLocation(); |
| 764 | int colorScaleLocation = DefaultMetavoxelRendererImplementation::getColorScaleLocation(); | ||
| 765 | ProgramObject* program = &DefaultMetavoxelRendererImplementation::getHeightfieldProgram(); | ||
| 766 | if (Menu::getInstance()->isOptionChecked(MenuOption::SimpleShadows)) { | ||
| 767 | heightScaleLocation = DefaultMetavoxelRendererImplementation::getShadowMapHeightScaleLocation(); | ||
| 768 | colorScaleLocation = DefaultMetavoxelRendererImplementation::getShadowMapColorScaleLocation(); | ||
| 769 | program = &DefaultMetavoxelRendererImplementation::getShadowMapHeightfieldProgram(); | ||
| 770 | |||
| 771 | } else if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { | ||
| 772 | heightScaleLocation = DefaultMetavoxelRendererImplementation::getCascadedShadowMapHeightScaleLocation(); | ||
| 773 | colorScaleLocation = DefaultMetavoxelRendererImplementation::getCascadedShadowMapColorScaleLocation(); | ||
| 774 | program = &DefaultMetavoxelRendererImplementation::getCascadedShadowMapHeightfieldProgram(); | ||
| 775 | } | ||
| 776 | program->setUniformValue(heightScaleLocation, 1.0f / _heightSize); | ||
| 777 | program->setUniformValue(colorScaleLocation, (float)_heightSize / innerSize); | ||
| 778 | glActiveTexture(GL_TEXTURE1); | ||
| 779 | glBindTexture(GL_TEXTURE_2D, _colorTextureID); | ||
| 780 | } | ||
| 390 | 781 | ||
| 391 | DefaultMetavoxelRendererImplementation::getHeightfieldProgram().setUniformValue( | 782 | glDrawRangeElements(GL_TRIANGLES, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); |
| 392 | DefaultMetavoxelRendererImplementation::getHeightScaleLocation(), 1.0f / _heightSize); | ||
| 393 | |||
| 394 | glDrawRangeElements(GL_QUADS, 0, vertexCount - 1, indexCount, GL_UNSIGNED_INT, 0); | ||
| 395 | 783 | ||
| 396 | glBindTexture(GL_TEXTURE_2D, 0); | 784 | if (!cursor) { |
| 785 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 786 | glActiveTexture(GL_TEXTURE0); | ||
| 787 | } | ||
| 397 | 788 | ||
| 398 | glActiveTexture(GL_TEXTURE0); | ||
| 399 | glBindTexture(GL_TEXTURE_2D, 0); | 789 | glBindTexture(GL_TEXTURE_2D, 0); |
| 400 | 790 | ||
| 401 | glPopMatrix(); | 791 | glPopMatrix(); |
| @@ -444,17 +834,19 @@ BufferDataAttribute::BufferDataAttribute(const QString& name) : · 42 unmodified lines | |||
| 444 | } | 834 | } |
| 445 | 835 | ||
| 446 | bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const { | 836 | bool BufferDataAttribute::merge(void*& parent, void* children[], bool postRead) const { |
| 447 | BufferDataPointer firstChild = decodeInline<BufferDataPointer>(children[0]); | 837 | *(BufferDataPointer*)&parent = _defaultValue; |
| 448 | for (int i = 1; i < MERGE_COUNT; i++) { | 838 | for (int i = 0; i < MERGE_COUNT; i++) { |
| 449 | if (firstChild != decodeInline<BufferDataPointer>(children[i])) { | 839 | if (decodeInline<BufferDataPointer>(children[i])) { |
| 450 | *(BufferDataPointer*)&parent = _defaultValue; | ||
| 451 | return false; | 840 | return false; |
| 452 | } | 841 | } |
| 453 | } | 842 | } |
| 454 | *(BufferDataPointer*)&parent = firstChild; | ||
| 455 | return true; | 843 | return true; |
| 456 | } | 844 | } |
| 457 | 845 | ||
| 846 | AttributeValue BufferDataAttribute::inherit(const AttributeValue& parentValue) const { | ||
| 847 | return AttributeValue(parentValue.getAttribute()); | ||
| 848 | } | ||
| 849 | |||
| 458 | void DefaultMetavoxelRendererImplementation::init() { | 850 | void DefaultMetavoxelRendererImplementation::init() { |
| 459 | if (!_pointProgram.isLinked()) { | 851 | if (!_pointProgram.isLinked()) { |
| 460 | _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); | 852 | _pointProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + "shaders/metavoxel_point.vert"); |
| @@ -474,7 +866,47 @@ void DefaultMetavoxelRendererImplementation::init() { · 13 unmodified lines | |||
| 474 | _heightfieldProgram.setUniformValue("heightMap", 0); | 866 | _heightfieldProgram.setUniformValue("heightMap", 0); |
| 475 | _heightfieldProgram.setUniformValue("diffuseMap", 1); | 867 | _heightfieldProgram.setUniformValue("diffuseMap", 1); |
| 476 | _heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale"); | 868 | _heightScaleLocation = _heightfieldProgram.uniformLocation("heightScale"); |
| 869 | _colorScaleLocation = _heightfieldProgram.uniformLocation("colorScale"); | ||
| 477 | _heightfieldProgram.release(); | 870 | _heightfieldProgram.release(); |
| 871 | |||
| 872 | _shadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + | ||
| 873 | "shaders/metavoxel_heightfield.vert"); | ||
| 874 | _shadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + | ||
| 875 | "shaders/metavoxel_heightfield_shadow_map.frag"); | ||
| 876 | _shadowMapHeightfieldProgram.link(); | ||
| 877 | |||
| 878 | _shadowMapHeightfieldProgram.bind(); | ||
| 879 | _shadowMapHeightfieldProgram.setUniformValue("heightMap", 0); | ||
| 880 | _shadowMapHeightfieldProgram.setUniformValue("diffuseMap", 1); | ||
| 881 | _shadowMapHeightfieldProgram.setUniformValue("shadowMap", 2); | ||
| 882 | _shadowMapHeightScaleLocation = _shadowMapHeightfieldProgram.uniformLocation("heightScale"); | ||
| 883 | _shadowMapColorScaleLocation = _shadowMapHeightfieldProgram.uniformLocation("colorScale"); | ||
| 884 | _shadowMapHeightfieldProgram.release(); | ||
| 885 | |||
| 886 | _cascadedShadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + | ||
| 887 | "shaders/metavoxel_heightfield.vert"); | ||
| 888 | _cascadedShadowMapHeightfieldProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + | ||
| 889 | "shaders/metavoxel_heightfield_cascaded_shadow_map.frag"); | ||
| 890 | _cascadedShadowMapHeightfieldProgram.link(); | ||
| 891 | |||
| 892 | _cascadedShadowMapHeightfieldProgram.bind(); | ||
| 893 | _cascadedShadowMapHeightfieldProgram.setUniformValue("heightMap", 0); | ||
| 894 | _cascadedShadowMapHeightfieldProgram.setUniformValue("diffuseMap", 1); | ||
| 895 | _cascadedShadowMapHeightfieldProgram.setUniformValue("shadowMap", 2); | ||
| 896 | _cascadedShadowMapHeightScaleLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("heightScale"); | ||
| 897 | _cascadedShadowMapColorScaleLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("colorScale"); | ||
| 898 | _shadowDistancesLocation = _cascadedShadowMapHeightfieldProgram.uniformLocation("shadowDistances"); | ||
| 899 | _cascadedShadowMapHeightfieldProgram.release(); | ||
| 900 | |||
| 901 | _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Vertex, Application::resourcesPath() + | ||
| 902 | "shaders/metavoxel_heightfield_cursor.vert"); | ||
| 903 | _heightfieldCursorProgram.addShaderFromSourceFile(QGLShader::Fragment, Application::resourcesPath() + | ||
| 904 | "shaders/metavoxel_heightfield_cursor.frag"); | ||
| 905 | _heightfieldCursorProgram.link(); | ||
| 906 | |||
| 907 | _heightfieldCursorProgram.bind(); | ||
| 908 | _heightfieldCursorProgram.setUniformValue("heightMap", 0); | ||
| 909 | _heightfieldCursorProgram.release(); | ||
| 478 | } | 910 | } |
| 479 | } | 911 | } |
| 480 | 912 | ||
| @@ -549,33 +981,279 @@ bool PointAugmentVisitor::postVisit(MetavoxelInfo& info) { · 68 unmodified lines | |||
| 549 | return true; | 981 | return true; |
| 550 | } | 982 | } |
| 551 | 983 | ||
| 552 | class HeightfieldAugmentVisitor : public MetavoxelVisitor { | 984 | class HeightfieldFetchVisitor : public MetavoxelVisitor { |
| 553 | public: | 985 | public: |
| 986 | |||
| 987 | HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections); | ||
| 988 | |||
| 989 | void init(HeightfieldBuffer* buffer) { _buffer = buffer; } | ||
| 990 | |||
| 991 | virtual int visit(MetavoxelInfo& info); | ||
| 554 | 992 | ||
| 555 | HeightfieldAugmentVisitor(const MetavoxelLOD& lod); | 993 | private: |
| 994 | |||
| 995 | const QVector<Box>& _intersections; | ||
| 996 | HeightfieldBuffer* _buffer; | ||
| 997 | }; | ||
| 998 | |||
| 999 | HeightfieldFetchVisitor::HeightfieldFetchVisitor(const MetavoxelLOD& lod, const QVector<Box>& intersections) : | ||
| 1000 | MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << | ||
| 1001 | AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector<AttributePointer>(), lod), | ||
| 1002 | _intersections(intersections) { | ||
| 1003 | } | ||
| 1004 | |||
| 1005 | int HeightfieldFetchVisitor::visit(MetavoxelInfo& info) { | ||
| 1006 | Box bounds = info.getBounds(); | ||
| 1007 | const Box& heightBounds = _buffer->getHeightBounds(); | ||
| 1008 | if (!bounds.intersects(heightBounds)) { | ||
| 1009 | return STOP_RECURSION; | ||
| 1010 | } | ||
| 1011 | if (!info.isLeaf && info.size > _buffer->getScale()) { | ||
| 1012 | return DEFAULT_ORDER; | ||
| 1013 | } | ||
| 1014 | HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>(); | ||
| 1015 | if (!height) { | ||
| 1016 | return STOP_RECURSION; | ||
| 1017 | } | ||
| 1018 | foreach (const Box& intersection, _intersections) { | ||
| 1019 | Box overlap = intersection.getIntersection(bounds); | ||
| 1020 | if (overlap.isEmpty()) { | ||
| 1021 | continue; | ||
| 1022 | } | ||
| 1023 | float heightIncrement = _buffer->getHeightIncrement(); | ||
| 1024 | int destX = (overlap.minimum.x - heightBounds.minimum.x) / heightIncrement; | ||
| 1025 | int destY = (overlap.minimum.z - heightBounds.minimum.z) / heightIncrement; | ||
| 1026 | int destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / heightIncrement); | ||
| 1027 | int destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / heightIncrement); | ||
| 1028 | int heightSize = _buffer->getHeightSize(); | ||
| 1029 | char* dest = _buffer->getHeight().data() + destY * heightSize + destX; | ||
| 1030 | |||
| 1031 | const QByteArray& srcHeight = height->getContents(); | ||
| 1032 | int srcSize = glm::sqrt(srcHeight.size()); | ||
| 1033 | float srcIncrement = info.size / srcSize; | ||
| 1034 | |||
| 1035 | if (info.size == _buffer->getScale() && srcSize == (heightSize - HeightfieldBuffer::HEIGHT_EXTENSION)) { | ||
| 1036 | // easy case: same resolution | ||
| 1037 | int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; | ||
| 1038 | int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; | ||
| 1039 | |||
| 1040 | const char* src = srcHeight.constData() + srcY * srcSize + srcX; | ||
| 1041 | for (int y = 0; y < destHeight; y++, src += srcSize, dest += heightSize) { | ||
| 1042 | memcpy(dest, src, destWidth); | ||
| 1043 | } | ||
| 1044 | } else { | ||
| 1045 | // more difficult: different resolutions | ||
| 1046 | float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; | ||
| 1047 | float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; | ||
| 1048 | float srcAdvance = heightIncrement / srcIncrement; | ||
| 1049 | int shift = 0; | ||
| 1050 | float size = _buffer->getScale(); | ||
| 1051 | while (size < info.size) { | ||
| 1052 | shift++; | ||
| 1053 | size *= 2.0f; | ||
| 1054 | } | ||
| 1055 | const int EIGHT_BIT_MAXIMUM = 255; | ||
| 1056 | int subtract = (_buffer->getTranslation().y - info.minimum.y) * EIGHT_BIT_MAXIMUM / _buffer->getScale(); | ||
| 1057 | for (int y = 0; y < destHeight; y++, dest += heightSize, srcY += srcAdvance) { | ||
| 1058 | const uchar* src = (const uchar*)srcHeight.constData() + (int)srcY * srcSize; | ||
| 1059 | float lineSrcX = srcX; | ||
| 1060 | for (char* lineDest = dest, *end = dest + destWidth; lineDest != end; lineDest++, lineSrcX += srcAdvance) { | ||
| 1061 | *lineDest = qMin(qMax(0, (src[(int)lineSrcX] << shift) - subtract), EIGHT_BIT_MAXIMUM); | ||
| 1062 | } | ||
| 1063 | } | ||
| 1064 | } | ||
| 1065 | |||
| 1066 | int colorSize = _buffer->getColorSize(); | ||
| 1067 | if (colorSize == 0) { | ||
| 1068 | return STOP_RECURSION; | ||
| 1069 | } | ||
| 1070 | HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>(); | ||
| 1071 | if (!color) { | ||
| 1072 | return STOP_RECURSION; | ||
| 1073 | } | ||
| 1074 | const Box& colorBounds = _buffer->getColorBounds(); | ||
| 1075 | overlap = colorBounds.getIntersection(overlap); | ||
| 1076 | float colorIncrement = _buffer->getColorIncrement(); | ||
| 1077 | destX = (overlap.minimum.x - colorBounds.minimum.x) / colorIncrement; | ||
| 1078 | destY = (overlap.minimum.z - colorBounds.minimum.z) / colorIncrement; | ||
| 1079 | destWidth = glm::ceil((overlap.maximum.x - overlap.minimum.x) / colorIncrement); | ||
| 1080 | destHeight = glm::ceil((overlap.maximum.z - overlap.minimum.z) / colorIncrement); | ||
| 1081 | dest = _buffer->getColor().data() + (destY * colorSize + destX) * HeightfieldData::COLOR_BYTES; | ||
| 1082 | int destStride = colorSize * HeightfieldData::COLOR_BYTES; | ||
| 1083 | int destBytes = destWidth * HeightfieldData::COLOR_BYTES; | ||
| 1084 | |||
| 1085 | const QByteArray& srcColor = color->getContents(); | ||
| 1086 | srcSize = glm::sqrt(srcColor.size() / HeightfieldData::COLOR_BYTES); | ||
| 1087 | int srcStride = srcSize * HeightfieldData::COLOR_BYTES; | ||
| 1088 | srcIncrement = info.size / srcSize; | ||
| 1089 | |||
| 1090 | if (srcIncrement == colorIncrement) { | ||
| 1091 | // easy case: same resolution | ||
| 1092 | int srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; | ||
| 1093 | int srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; | ||
| 1094 | |||
| 1095 | const char* src = srcColor.constData() + (srcY * srcSize + srcX) * HeightfieldData::COLOR_BYTES; | ||
| 1096 | for (int y = 0; y < destHeight; y++, src += srcStride, dest += destStride) { | ||
| 1097 | memcpy(dest, src, destBytes); | ||
| 1098 | } | ||
| 1099 | } else { | ||
| 1100 | // more difficult: different resolutions | ||
| 1101 | float srcX = (overlap.minimum.x - info.minimum.x) / srcIncrement; | ||
| 1102 | float srcY = (overlap.minimum.z - info.minimum.z) / srcIncrement; | ||
| 1103 | float srcAdvance = colorIncrement / srcIncrement; | ||
| 1104 | for (int y = 0; y < destHeight; y++, dest += destStride, srcY += srcAdvance) { | ||
| 1105 | const char* src = srcColor.constData() + (int)srcY * srcStride; | ||
| 1106 | float lineSrcX = srcX; | ||
| 1107 | for (char* lineDest = dest, *end = dest + destBytes; lineDest != end; lineDest += HeightfieldData::COLOR_BYTES, | ||
| 1108 | lineSrcX += srcAdvance) { | ||
| 1109 | const char* lineSrc = src + (int)lineSrcX * HeightfieldData::COLOR_BYTES; | ||
| 1110 | lineDest[0] = lineSrc[0]; | ||
| 1111 | lineDest[1] = lineSrc[1]; | ||
| 1112 | lineDest[2] = lineSrc[2]; | ||
| 1113 | } | ||
| 1114 | } | ||
| 1115 | } | ||
| 1116 | } | ||
| 1117 | return STOP_RECURSION; | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | class HeightfieldRegionVisitor : public MetavoxelVisitor { | ||
| 1121 | public: | ||
| 1122 | |||
| 1123 | QVector<Box> regions; | ||
| 1124 | Box regionBounds; | ||
| 1125 | |||
| 1126 | HeightfieldRegionVisitor(const MetavoxelLOD& lod); | ||
| 556 | 1127 | ||
| 557 | virtual int visit(MetavoxelInfo& info); | 1128 | virtual int visit(MetavoxelInfo& info); |
| 1129 | |||
| 1130 | private: | ||
| 1131 | |||
| 1132 | void addRegion(const Box& unextended, const Box& extended); | ||
| 1133 | |||
| 1134 | QVector<Box> _intersections; | ||
| 1135 | HeightfieldFetchVisitor _fetchVisitor; | ||
| 558 | }; | 1136 | }; |
| 559 | 1137 | ||
| 560 | HeightfieldAugmentVisitor::HeightfieldAugmentVisitor(const MetavoxelLOD& lod) : | 1138 | HeightfieldRegionVisitor::HeightfieldRegionVisitor(const MetavoxelLOD& lod) : |
| 561 | MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << | 1139 | MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute() << |
| 562 | AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), QVector<AttributePointer>() << | 1140 | AttributeRegistry::getInstance()->getHeightfieldColorAttribute() << |
| 563 | Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod) { | 1141 | Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() << |
| 564 | } | 1142 | Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod), |
| 565 | 1143 | regionBounds(glm::vec3(FLT_MAX, FLT_MAX, FLT_MAX), glm::vec3(-FLT_MAX, -FLT_MAX, -FLT_MAX)), | |
| 566 | int HeightfieldAugmentVisitor::visit(MetavoxelInfo& info) { | 1144 | _fetchVisitor(lod, _intersections) { |
| 567 | if (info.isLeaf) { | 1145 | } |
| 568 | HeightfieldBuffer* buffer = NULL; | 1146 | |
| 569 | HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>(); | 1147 | int HeightfieldRegionVisitor::visit(MetavoxelInfo& info) { |
| 570 | if (height) { | 1148 | if (!info.isLeaf) { |
| 571 | HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>(); | 1149 | return DEFAULT_ORDER; |
| 572 | buffer = new HeightfieldBuffer(info.minimum, info.size, height->getContents(), | 1150 | } |
| 573 | color ? color->getContents() : QByteArray()); | 1151 | HeightfieldBuffer* buffer = NULL; |
| 1152 | HeightfieldDataPointer height = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>(); | ||
| 1153 | if (height) { | ||
| 1154 | const QByteArray& heightContents = height->getContents(); | ||
| 1155 | int size = glm::sqrt(heightContents.size()); | ||
| 1156 | int extendedSize = size + HeightfieldBuffer::HEIGHT_EXTENSION; | ||
| 1157 | int heightContentsSize = extendedSize * extendedSize; | ||
| 1158 | |||
| 1159 | HeightfieldDataPointer color = info.inputValues.at(1).getInlineValue<HeightfieldDataPointer>(); | ||
| 1160 | int colorContentsSize = 0; | ||
| 1161 | if (color) { | ||
| 1162 | const QByteArray& colorContents = color->getContents(); | ||
| 1163 | int colorSize = glm::sqrt(colorContents.size() / HeightfieldData::COLOR_BYTES); | ||
| 1164 | int extendedColorSize = colorSize + HeightfieldBuffer::SHARED_EDGE; | ||
| 1165 | colorContentsSize = extendedColorSize * extendedColorSize * HeightfieldData::COLOR_BYTES; | ||
| 574 | } | 1166 | } |
| 575 | info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); | 1167 | |
| 1168 | const HeightfieldBuffer* existingBuffer = static_cast<const HeightfieldBuffer*>( | ||
| 1169 | info.inputValues.at(2).getInlineValue<BufferDataPointer>().data()); | ||
| 1170 | Box bounds = info.getBounds(); | ||
| 1171 | if (existingBuffer && existingBuffer->getHeight().size() == heightContentsSize && | ||
| 1172 | existingBuffer->getColor().size() == colorContentsSize) { | ||
| 1173 | // we already have a buffer of the correct resolution | ||
| 1174 | addRegion(bounds, existingBuffer->getHeightBounds()); | ||
| 1175 | return STOP_RECURSION; | ||
| 1176 | } | ||
| 1177 | // we must create a new buffer and update its borders | ||
| 1178 | buffer = new HeightfieldBuffer(info.minimum, info.size, QByteArray(heightContentsSize, 0), | ||
| 1179 | QByteArray(colorContentsSize, 0)); | ||
| 1180 | const Box& heightBounds = buffer->getHeightBounds(); | ||
| 1181 | addRegion(bounds, heightBounds); | ||
| 1182 | |||
| 1183 | _intersections.clear(); | ||
| 1184 | _intersections.append(Box(heightBounds.minimum, | ||
| 1185 | glm::vec3(bounds.maximum.x, heightBounds.maximum.y, bounds.minimum.z))); | ||
| 1186 | _intersections.append(Box(glm::vec3(bounds.maximum.x, heightBounds.minimum.y, heightBounds.minimum.z), | ||
| 1187 | glm::vec3(heightBounds.maximum.x, heightBounds.maximum.y, bounds.maximum.z))); | ||
| 1188 | _intersections.append(Box(glm::vec3(bounds.minimum.x, heightBounds.minimum.y, bounds.maximum.z), | ||
| 1189 | heightBounds.maximum)); | ||
| 1190 | _intersections.append(Box(glm::vec3(heightBounds.minimum.x, heightBounds.minimum.y, bounds.minimum.z), | ||
| 1191 | glm::vec3(bounds.minimum.x, heightBounds.maximum.y, heightBounds.maximum.z))); | ||
| 1192 | |||
| 1193 | _fetchVisitor.init(buffer); | ||
| 1194 | _data->guide(_fetchVisitor); | ||
| 1195 | } | ||
| 1196 | info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(buffer))); | ||
| 1197 | return STOP_RECURSION; | ||
| 1198 | } | ||
| 1199 | |||
| 1200 | void HeightfieldRegionVisitor::addRegion(const Box& unextended, const Box& extended) { | ||
| 1201 | regions.append(unextended); | ||
| 1202 | regionBounds.add(extended); | ||
| 1203 | } | ||
| 1204 | |||
| 1205 | class HeightfieldUpdateVisitor : public MetavoxelVisitor { | ||
| 1206 | public: | ||
| 1207 | |||
| 1208 | HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector<Box>& regions, const Box& regionBounds); | ||
| 1209 | |||
| 1210 | virtual int visit(MetavoxelInfo& info); | ||
| 1211 | |||
| 1212 | private: | ||
| 1213 | |||
| 1214 | const QVector<Box>& _regions; | ||
| 1215 | const Box& _regionBounds; | ||
| 1216 | QVector<Box> _intersections; | ||
| 1217 | HeightfieldFetchVisitor _fetchVisitor; | ||
| 1218 | }; | ||
| 1219 | |||
| 1220 | HeightfieldUpdateVisitor::HeightfieldUpdateVisitor(const MetavoxelLOD& lod, const QVector<Box>& regions, | ||
| 1221 | const Box& regionBounds) : | ||
| 1222 | MetavoxelVisitor(QVector<AttributePointer>() << | ||
| 1223 | Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), QVector<AttributePointer>() << | ||
| 1224 | Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), lod), | ||
| 1225 | _regions(regions), | ||
| 1226 | _regionBounds(regionBounds), | ||
| 1227 | _fetchVisitor(lod, _intersections) { | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | int HeightfieldUpdateVisitor::visit(MetavoxelInfo& info) { | ||
| 1231 | if (!info.getBounds().intersects(_regionBounds)) { | ||
| 1232 | return STOP_RECURSION; | ||
| 1233 | } | ||
| 1234 | if (!info.isLeaf) { | ||
| 1235 | return DEFAULT_ORDER; | ||
| 1236 | } | ||
| 1237 | const HeightfieldBuffer* buffer = static_cast<const HeightfieldBuffer*>( | ||
| 1238 | info.inputValues.at(0).getInlineValue<BufferDataPointer>().data()); | ||
| 1239 | if (!buffer) { | ||
| 1240 | return STOP_RECURSION; | ||
| 1241 | } | ||
| 1242 | _intersections.clear(); | ||
| 1243 | foreach (const Box& region, _regions) { | ||
| 1244 | if (region.intersects(buffer->getHeightBounds())) { | ||
| 1245 | _intersections.append(region.getIntersection(buffer->getHeightBounds())); | ||
| 1246 | } | ||
| 1247 | } | ||
| 1248 | if (_intersections.isEmpty()) { | ||
| 576 | return STOP_RECURSION; | 1249 | return STOP_RECURSION; |
| 577 | } | 1250 | } |
| 578 | return DEFAULT_ORDER; | 1251 | HeightfieldBuffer* newBuffer = new HeightfieldBuffer(info.minimum, info.size, |
| 1252 | buffer->getHeight(), buffer->getColor()); | ||
| 1253 | _fetchVisitor.init(newBuffer); | ||
| 1254 | _data->guide(_fetchVisitor); | ||
| 1255 | info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline(BufferDataPointer(newBuffer))); | ||
| 1256 | return STOP_RECURSION; | ||
| 579 | } | 1257 | } |
| 580 | 1258 | ||
| 581 | void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, | 1259 | void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const MetavoxelData& previous, |
| @@ -602,8 +1280,12 @@ void DefaultMetavoxelRendererImplementation::augment(MetavoxelData& data, const · 20 unmodified lines | |||
| 602 | PointAugmentVisitor pointAugmentVisitor(lod); | 1280 | PointAugmentVisitor pointAugmentVisitor(lod); |
| 603 | data.guideToDifferent(expandedPrevious, pointAugmentVisitor); | 1281 | data.guideToDifferent(expandedPrevious, pointAugmentVisitor); |
| 604 | 1282 | ||
| 605 | HeightfieldAugmentVisitor heightfieldAugmentVisitor(lod); | 1283 | HeightfieldRegionVisitor heightfieldRegionVisitor(lod); |
| 606 | data.guideToDifferent(expandedPrevious, heightfieldAugmentVisitor); | 1284 | data.guideToDifferent(expandedPrevious, heightfieldRegionVisitor); |
| 1285 | |||
| 1286 | HeightfieldUpdateVisitor heightfieldUpdateVisitor(lod, heightfieldRegionVisitor.regions, | ||
| 1287 | heightfieldRegionVisitor.regionBounds); | ||
| 1288 | data.guide(heightfieldUpdateVisitor); | ||
| 607 | } | 1289 | } |
| 608 | 1290 | ||
| 609 | class SpannerSimulateVisitor : public SpannerVisitor { | 1291 | class SpannerSimulateVisitor : public SpannerVisitor { |
| @@ -675,7 +1357,7 @@ bool SpannerRenderVisitor::visit(Spanner* spanner, const glm::vec3& clipMinimum, · 65 unmodified lines | |||
| 675 | class BufferRenderVisitor : public MetavoxelVisitor { | 1357 | class BufferRenderVisitor : public MetavoxelVisitor { |
| 676 | public: | 1358 | public: |
| 677 | 1359 | ||
| 678 | BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod); | 1360 | BufferRenderVisitor(const AttributePointer& attribute); |
| 679 | 1361 | ||
| 680 | virtual int visit(MetavoxelInfo& info); | 1362 | virtual int visit(MetavoxelInfo& info); |
| 681 | 1363 | ||
| @@ -685,8 +1367,8 @@ private: · 3 unmodified lines | |||
| 685 | int _containmentDepth; | 1367 | int _containmentDepth; |
| 686 | }; | 1368 | }; |
| 687 | 1369 | ||
| 688 | BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute, const MetavoxelLOD& lod) : | 1370 | BufferRenderVisitor::BufferRenderVisitor(const AttributePointer& attribute) : |
| 689 | MetavoxelVisitor(QVector<AttributePointer>() << attribute, QVector<AttributePointer>(), lod), | 1371 | MetavoxelVisitor(QVector<AttributePointer>() << attribute), |
| 690 | _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), | 1372 | _order(encodeOrder(Application::getInstance()->getViewFrustum()->getDirection())), |
| 691 | _containmentDepth(INT_MAX) { | 1373 | _containmentDepth(INT_MAX) { |
| 692 | } | 1374 | } |
| @@ -700,11 +1382,14 @@ int BufferRenderVisitor::visit(MetavoxelInfo& info) { · 7 unmodified lines | |||
| 700 | } | 1382 | } |
| 701 | _containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX; | 1383 | _containmentDepth = (intersection == Frustum::CONTAINS_INTERSECTION) ? _depth : INT_MAX; |
| 702 | } | 1384 | } |
| 1385 | if (!info.isLeaf) { | ||
| 1386 | return _order; | ||
| 1387 | } | ||
| 703 | BufferDataPointer buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>(); | 1388 | BufferDataPointer buffer = info.inputValues.at(0).getInlineValue<BufferDataPointer>(); |
| 704 | if (buffer) { | 1389 | if (buffer) { |
| 705 | buffer->render(); | 1390 | buffer->render(); |
| 706 | } | 1391 | } |
| 707 | return info.isLeaf ? STOP_RECURSION : _order; | 1392 | return STOP_RECURSION; |
| 708 | } | 1393 | } |
| 709 | 1394 | ||
| 710 | void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) { | 1395 | void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, MetavoxelInfo& info, const MetavoxelLOD& lod) { |
| @@ -733,7 +1418,7 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox · 22 unmodified lines | |||
| 733 | 1418 | ||
| 734 | glDisable(GL_BLEND); | 1419 | glDisable(GL_BLEND); |
| 735 | 1420 | ||
| 736 | BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute(), lod); | 1421 | BufferRenderVisitor pointRenderVisitor(Application::getInstance()->getMetavoxels()->getPointBufferAttribute()); |
| 737 | data.guide(pointRenderVisitor); | 1422 | data.guide(pointRenderVisitor); |
| 738 | 1423 | ||
| 739 | glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); | 1424 | glDisable(GL_VERTEX_PROGRAM_POINT_SIZE_ARB); |
| @@ -749,16 +1434,34 @@ void DefaultMetavoxelRendererImplementation::render(MetavoxelData& data, Metavox · 9 unmodified lines | |||
| 749 | 1434 | ||
| 750 | glColor4f(1.0f, 1.0f, 1.0f, 1.0f); | 1435 | glColor4f(1.0f, 1.0f, 1.0f, 1.0f); |
| 751 | 1436 | ||
| 752 | _heightfieldProgram.bind(); | 1437 | ProgramObject* program = &_heightfieldProgram; |
| 1438 | if (Menu::getInstance()->getShadowsEnabled()) { | ||
| 1439 | if (Menu::getInstance()->isOptionChecked(MenuOption::CascadedShadows)) { | ||
| 1440 | program = &_cascadedShadowMapHeightfieldProgram; | ||
| 1441 | program->bind(); | ||
| 1442 | program->setUniform(_shadowDistancesLocation, Application::getInstance()->getShadowDistances()); | ||
| 1443 | |||
| 1444 | } else { | ||
| 1445 | program = &_shadowMapHeightfieldProgram; | ||
| 1446 | } | ||
| 1447 | glActiveTexture(GL_TEXTURE2); | ||
| 1448 | glBindTexture(GL_TEXTURE_2D, Application::getInstance()->getTextureCache()->getShadowDepthTextureID()); | ||
| 1449 | glActiveTexture(GL_TEXTURE0); | ||
| 1450 | } | ||
| 1451 | |||
| 1452 | program->bind(); | ||
| 753 | 1453 | ||
| 754 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); | 1454 | glEnableClientState(GL_TEXTURE_COORD_ARRAY); |
| 755 | 1455 | ||
| 756 | BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute(), | 1456 | BufferRenderVisitor heightfieldRenderVisitor(Application::getInstance()->getMetavoxels()->getHeightfieldBufferAttribute()); |
| 757 | lod); | ||
| 758 | data.guide(heightfieldRenderVisitor); | 1457 | data.guide(heightfieldRenderVisitor); |
| 759 | 1458 | ||
| 760 | _heightfieldProgram.release(); | 1459 | program->release(); |
| 761 | 1460 | ||
| 1461 | glActiveTexture(GL_TEXTURE2); | ||
| 1462 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 1463 | glActiveTexture(GL_TEXTURE0); | ||
| 1464 | |||
| 762 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); | 1465 | glDisableClientState(GL_TEXTURE_COORD_ARRAY); |
| 763 | glDisableClientState(GL_VERTEX_ARRAY); | 1466 | glDisableClientState(GL_VERTEX_ARRAY); |
| 764 | 1467 | ||
| @@ -771,6 +1474,15 @@ ProgramObject DefaultMetavoxelRendererImplementation::_pointProgram; · 6 unmodified lines | |||
| 771 | int DefaultMetavoxelRendererImplementation::_pointScaleLocation; | 1474 | int DefaultMetavoxelRendererImplementation::_pointScaleLocation; |
| 772 | ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram; | 1475 | ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldProgram; |
| 773 | int DefaultMetavoxelRendererImplementation::_heightScaleLocation; | 1476 | int DefaultMetavoxelRendererImplementation::_heightScaleLocation; |
| 1477 | int DefaultMetavoxelRendererImplementation::_colorScaleLocation; | ||
| 1478 | ProgramObject DefaultMetavoxelRendererImplementation::_shadowMapHeightfieldProgram; | ||
| 1479 | int DefaultMetavoxelRendererImplementation::_shadowMapHeightScaleLocation; | ||
| 1480 | int DefaultMetavoxelRendererImplementation::_shadowMapColorScaleLocation; | ||
| 1481 | ProgramObject DefaultMetavoxelRendererImplementation::_cascadedShadowMapHeightfieldProgram; | ||
| 1482 | int DefaultMetavoxelRendererImplementation::_cascadedShadowMapHeightScaleLocation; | ||
| 1483 | int DefaultMetavoxelRendererImplementation::_cascadedShadowMapColorScaleLocation; | ||
| 1484 | int DefaultMetavoxelRendererImplementation::_shadowDistancesLocation; | ||
| 1485 | ProgramObject DefaultMetavoxelRendererImplementation::_heightfieldCursorProgram; | ||
| 774 | 1486 | ||
| 775 | static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { | 1487 | static void enableClipPlane(GLenum plane, float x, float y, float z, float w) { |
| 776 | GLdouble coefficients[] = { x, y, z, w }; | 1488 | GLdouble coefficients[] = { x, y, z, w }; |
| @@ -43,6 +43,12 @@ public: · 42 unmodified lines | |||
| 43 | void simulate(float deltaTime); | 43 | void simulate(float deltaTime); |
| 44 | void render(); | 44 | void render(); |
| 45 | 45 | ||
| 46 | void renderHeightfieldCursor(const glm::vec3& position, float radius); | ||
| 47 | |||
| 48 | bool findFirstRayHeightfieldIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance); | ||
| 49 | |||
| 50 | Q_INVOKABLE float getHeightfieldHeight(const glm::vec3& location); | ||
| 51 | |||
| 46 | Q_INVOKABLE void deleteTextures(int heightID, int colorID); | 52 | Q_INVOKABLE void deleteTextures(int heightID, int colorID); |
| 47 | 53 | ||
| 48 | protected: | 54 | protected: |
| @@ -105,7 +111,7 @@ public: · 56 unmodified lines | |||
| 105 | 111 | ||
| 106 | virtual ~BufferData(); | 112 | virtual ~BufferData(); |
| 107 | 113 | ||
| 108 | virtual void render() = 0; | 114 | virtual void render(bool cursor = false) = 0; |
| 109 | }; | 115 | }; |
| 110 | 116 | ||
| 111 | typedef QExplicitlySharedDataPointer<BufferData> BufferDataPointer; | 117 | typedef QExplicitlySharedDataPointer<BufferData> BufferDataPointer; |
| @@ -116,7 +122,7 @@ public: · 4 unmodified lines | |||
| 116 | 122 | ||
| 117 | PointBuffer(const BufferPointVector& points); | 123 | PointBuffer(const BufferPointVector& points); |
| 118 | 124 | ||
| 119 | virtual void render(); | 125 | virtual void render(bool cursor = false); |
| 120 | 126 | ||
| 121 | private: | 127 | private: |
| 122 | 128 | ||
| @@ -129,29 +135,50 @@ private: · 6 unmodified lines | |||
| 129 | class HeightfieldBuffer : public BufferData { | 135 | class HeightfieldBuffer : public BufferData { |
| 130 | public: | 136 | public: |
| 131 | 137 | ||
| 132 | /// Creates a new heightfield buffer. | 138 | static const int HEIGHT_BORDER; |
| 133 | /// \param clearAfterLoading if true, clear the data arrays after we load them into textures in order to reclaim the space | 139 | static const int SHARED_EDGE; |
| 134 | HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color, | 140 | static const int HEIGHT_EXTENSION; |
| 135 | bool clearAfterLoading = true); | 141 | |
| 142 | HeightfieldBuffer(const glm::vec3& translation, float scale, const QByteArray& height, const QByteArray& color); | ||
| 136 | ~HeightfieldBuffer(); | 143 | ~HeightfieldBuffer(); |
| 137 | 144 | ||
| 138 | const glm::vec3& getTranslation() const { return _translation; } | 145 | const glm::vec3& getTranslation() const { return _translation; } |
| 146 | float getScale() const { return _scale; } | ||
| 147 | |||
| 148 | const Box& getHeightBounds() const { return _heightBounds; } | ||
| 149 | const Box& getColorBounds() const { return _colorBounds; } | ||
| 139 | 150 | ||
| 151 | QByteArray& getHeight() { return _height; } | ||
| 140 | const QByteArray& getHeight() const { return _height; } | 152 | const QByteArray& getHeight() const { return _height; } |
| 153 | |||
| 154 | QByteArray& getColor() { return _color; } | ||
| 141 | const QByteArray& getColor() const { return _color; } | 155 | const QByteArray& getColor() const { return _color; } |
| 142 | 156 | ||
| 143 | virtual void render(); | 157 | QByteArray getUnextendedHeight() const; |
| 158 | QByteArray getUnextendedColor() const; | ||
| 159 | |||
| 160 | int getHeightSize() const { return _heightSize; } | ||
| 161 | float getHeightIncrement() const { return _heightIncrement; } | ||
| 162 | |||
| 163 | int getColorSize() const { return _colorSize; } | ||
| 164 | float getColorIncrement() const { return _colorIncrement; } | ||
| 165 | |||
| 166 | virtual void render(bool cursor = false); | ||
| 144 | 167 | ||
| 145 | private: | 168 | private: |
| 146 | 169 | ||
| 147 | glm::vec3 _translation; | 170 | glm::vec3 _translation; |
| 148 | float _scale; | 171 | float _scale; |
| 172 | Box _heightBounds; | ||
| 173 | Box _colorBounds; | ||
| 149 | QByteArray _height; | 174 | QByteArray _height; |
| 150 | QByteArray _color; | 175 | QByteArray _color; |
| 151 | bool _clearAfterLoading; | ||
| 152 | GLuint _heightTextureID; | 176 | GLuint _heightTextureID; |
| 153 | GLuint _colorTextureID; | 177 | GLuint _colorTextureID; |
| 154 | int _heightSize; | 178 | int _heightSize; |
| 179 | float _heightIncrement; | ||
| 180 | int _colorSize; | ||
| 181 | float _colorIncrement; | ||
| 155 | 182 | ||
| 156 | typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair; | 183 | typedef QPair<QOpenGLBuffer, QOpenGLBuffer> BufferPair; |
| 157 | static QHash<int, BufferPair> _bufferPairs; | 184 | static QHash<int, BufferPair> _bufferPairs; |
| @@ -180,6 +207,8 @@ public: · 22 unmodified lines | |||
| 180 | Q_INVOKABLE BufferDataAttribute(const QString& name = QString()); | 207 | Q_INVOKABLE BufferDataAttribute(const QString& name = QString()); |
| 181 | 208 | ||
| 182 | virtual bool merge(void*& parent, void* children[], bool postRead = false) const; | 209 | virtual bool merge(void*& parent, void* children[], bool postRead = false) const; |
| 210 | |||
| 211 | virtual AttributeValue inherit(const AttributeValue& parentValue) const; | ||
| 183 | }; | 212 | }; |
| 184 | 213 | ||
| 185 | /// Renders metavoxels as points. | 214 | /// Renders metavoxels as points. |
| @@ -192,7 +221,18 @@ public: · 6 unmodified lines | |||
| 192 | 221 | ||
| 193 | static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; } | 222 | static ProgramObject& getHeightfieldProgram() { return _heightfieldProgram; } |
| 194 | static int getHeightScaleLocation() { return _heightScaleLocation; } | 223 | static int getHeightScaleLocation() { return _heightScaleLocation; } |
| 195 | 224 | static int getColorScaleLocation() { return _colorScaleLocation; } | |
| 225 | |||
| 226 | static ProgramObject& getShadowMapHeightfieldProgram() { return _shadowMapHeightfieldProgram; } | ||
| 227 | static int getShadowMapHeightScaleLocation() { return _shadowMapHeightScaleLocation; } | ||
| 228 | static int getShadowMapColorScaleLocation() { return _shadowMapColorScaleLocation; } | ||
| 229 | |||
| 230 | static ProgramObject& getCascadedShadowMapHeightfieldProgram() { return _cascadedShadowMapHeightfieldProgram; } | ||
| 231 | static int getCascadedShadowMapHeightScaleLocation() { return _cascadedShadowMapHeightScaleLocation; } | ||
| 232 | static int getCascadedShadowMapColorScaleLocation() { return _cascadedShadowMapColorScaleLocation; } | ||
| 233 | |||
| 234 | static ProgramObject& getHeightfieldCursorProgram() { return _heightfieldCursorProgram; } | ||
| 235 | |||
| 196 | Q_INVOKABLE DefaultMetavoxelRendererImplementation(); | 236 | Q_INVOKABLE DefaultMetavoxelRendererImplementation(); |
| 197 | 237 | ||
| 198 | virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod); | 238 | virtual void augment(MetavoxelData& data, const MetavoxelData& previous, MetavoxelInfo& info, const MetavoxelLOD& lod); |
| @@ -206,6 +246,18 @@ private: · 7 unmodified lines | |||
| 206 | 246 | ||
| 207 | static ProgramObject _heightfieldProgram; | 247 | static ProgramObject _heightfieldProgram; |
| 208 | static int _heightScaleLocation; | 248 | static int _heightScaleLocation; |
| 249 | static int _colorScaleLocation; | ||
| 250 | |||
| 251 | static ProgramObject _shadowMapHeightfieldProgram; | ||
| 252 | static int _shadowMapHeightScaleLocation; | ||
| 253 | static int _shadowMapColorScaleLocation; | ||
| 254 | |||
| 255 | static ProgramObject _cascadedShadowMapHeightfieldProgram; | ||
| 256 | static int _cascadedShadowMapHeightScaleLocation; | ||
| 257 | static int _cascadedShadowMapColorScaleLocation; | ||
| 258 | static int _shadowDistancesLocation; | ||
| 259 | |||
| 260 | static ProgramObject _heightfieldCursorProgram; | ||
| 209 | }; | 261 | }; |
| 210 | 262 | ||
| 211 | /// Base class for spanner renderers; provides clipping. | 263 | /// Base class for spanner renderers; provides clipping. |
| @@ -163,9 +163,6 @@ void Head::simulate(float deltaTime, bool isMine, bool billboard) { · 162 unmodified lines | |||
| 163 | } | 163 | } |
| 164 | _eyePosition = calculateAverageEyePosition(); | 164 | _eyePosition = calculateAverageEyePosition(); |
| 165 | 165 | ||
| 166 | float velocityFilter = glm::clamp(1.0f - glm::length(_filteredEyePosition - _eyePosition), 0.0f, 1.0f); | ||
| 167 | _filteredEyePosition = velocityFilter * _filteredEyePosition + (1.0f - velocityFilter) * _eyePosition; | ||
| 168 | |||
| 169 | } | 166 | } |
| 170 | 167 | ||
| 171 | void Head::relaxLean(float deltaTime) { | 168 | void Head::relaxLean(float deltaTime) { |
| @@ -88,7 +88,6 @@ public: · 87 unmodified lines | |||
| 88 | 88 | ||
| 89 | const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) | 89 | const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) |
| 90 | float getAverageLoudness() const { return _averageLoudness; } | 90 | float getAverageLoudness() const { return _averageLoudness; } |
| 91 | glm::vec3 getFilteredEyePosition() const { return _filteredEyePosition; } | ||
| 92 | /// \return the point about which scaling occurs. | 91 | /// \return the point about which scaling occurs. |
| 93 | glm::vec3 getScalePivot() const; | 92 | glm::vec3 getScalePivot() const; |
| 94 | 93 | ||
| @@ -121,7 +120,6 @@ private: · 26 unmodified lines | |||
| 121 | glm::vec3 _leftEyePosition; | 120 | glm::vec3 _leftEyePosition; |
| 122 | glm::vec3 _rightEyePosition; | 121 | glm::vec3 _rightEyePosition; |
| 123 | glm::vec3 _eyePosition; | 122 | glm::vec3 _eyePosition; |
| 124 | glm::vec3 _filteredEyePosition; // velocity filtered world space eye position | ||
| 125 | 123 | ||
| 126 | float _scale; | 124 | float _scale; |
| 127 | float _lastLoudness; | 125 | float _lastLoudness; |
| @@ -83,10 +83,11 @@ MyAvatar::MyAvatar() : · 82 unmodified lines | |||
| 83 | for (int i = 0; i < MAX_DRIVE_KEYS; i++) { | 83 | for (int i = 0; i < MAX_DRIVE_KEYS; i++) { |
| 84 | _driveKeys[i] = 0.0f; | 84 | _driveKeys[i] = 0.0f; |
| 85 | } | 85 | } |
| 86 | _skeletonModel.setEnableShapes(true); | ||
| 87 | // The skeleton is both a PhysicsEntity and Ragdoll, so we add it to the simulation once for each type. | ||
| 88 | _physicsSimulation.setEntity(&_skeletonModel); | 86 | _physicsSimulation.setEntity(&_skeletonModel); |
| 89 | _physicsSimulation.setRagdoll(&_skeletonModel); | 87 | |
| 88 | _skeletonModel.setEnableShapes(true); | ||
| 89 | Ragdoll* ragdoll = _skeletonModel.buildRagdoll(); | ||
| 90 | _physicsSimulation.setRagdoll(ragdoll); | ||
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | MyAvatar::~MyAvatar() { | 93 | MyAvatar::~MyAvatar() { |
| @@ -206,9 +207,9 @@ void MyAvatar::simulate(float deltaTime) { · 113 unmodified lines | |||
| 206 | { | 207 | { |
| 207 | PerformanceTimer perfTimer("ragdoll"); | 208 | PerformanceTimer perfTimer("ragdoll"); |
| 208 | if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { | 209 | if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { |
| 209 | const float minError = 0.01f; | 210 | const float minError = 0.00001f; |
| 210 | const float maxIterations = 10; | 211 | const float maxIterations = 3; |
| 211 | const quint64 maxUsec = 2000; | 212 | const quint64 maxUsec = 4000; |
| 212 | _physicsSimulation.setTranslation(_position); | 213 | _physicsSimulation.setTranslation(_position); |
| 213 | _physicsSimulation.stepForward(deltaTime, minError, maxIterations, maxUsec); | 214 | _physicsSimulation.stepForward(deltaTime, minError, maxIterations, maxUsec); |
| 214 | } else { | 215 | } else { |
| @@ -255,6 +256,12 @@ void MyAvatar::updateFromTrackers(float deltaTime) { · 40 unmodified lines | |||
| 255 | estimatedRotation.x *= -1.0f; | 256 | estimatedRotation.x *= -1.0f; |
| 256 | estimatedRotation.z *= -1.0f; | 257 | estimatedRotation.z *= -1.0f; |
| 257 | 258 | ||
| 259 | } else if (OculusManager::isConnected()) { | ||
| 260 | estimatedPosition = OculusManager::getRelativePosition(); | ||
| 261 | estimatedPosition.x *= -1.0f; | ||
| 262 | |||
| 263 | const float OCULUS_LEAN_SCALE = 0.05f; | ||
| 264 | estimatedPosition /= OCULUS_LEAN_SCALE; | ||
| 258 | } else { | 265 | } else { |
| 259 | FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker(); | 266 | FaceTracker* tracker = Application::getInstance()->getActiveFaceTracker(); |
| 260 | if (tracker) { | 267 | if (tracker) { |
| @@ -1598,10 +1605,10 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { · 1337 unmodified lines | |||
| 1598 | if (simulation != &(_physicsSimulation)) { | 1605 | if (simulation != &(_physicsSimulation)) { |
| 1599 | skeleton->setEnableShapes(true); | 1606 | skeleton->setEnableShapes(true); |
| 1600 | _physicsSimulation.addEntity(skeleton); | 1607 | _physicsSimulation.addEntity(skeleton); |
| 1601 | _physicsSimulation.addRagdoll(skeleton); | 1608 | _physicsSimulation.addRagdoll(skeleton->getRagdoll()); |
| 1602 | } | 1609 | } |
| 1603 | } else if (simulation == &(_physicsSimulation)) { | 1610 | } else if (simulation == &(_physicsSimulation)) { |
| 1604 | _physicsSimulation.removeRagdoll(skeleton); | 1611 | _physicsSimulation.removeRagdoll(skeleton->getRagdoll()); |
| 1605 | _physicsSimulation.removeEntity(skeleton); | 1612 | _physicsSimulation.removeEntity(skeleton); |
| 1606 | skeleton->setEnableShapes(false); | 1613 | skeleton->setEnableShapes(false); |
| 1607 | } | 1614 | } |
| @@ -23,13 +23,19 @@ · 22 unmodified lines | |||
| 23 | #include "Menu.h" | 23 | #include "Menu.h" |
| 24 | #include "MuscleConstraint.h" | 24 | #include "MuscleConstraint.h" |
| 25 | #include "SkeletonModel.h" | 25 | #include "SkeletonModel.h" |
| 26 | #include "SkeletonRagdoll.h" | ||
| 26 | 27 | ||
| 27 | SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : | 28 | SkeletonModel::SkeletonModel(Avatar* owningAvatar, QObject* parent) : |
| 28 | Model(parent), | 29 | Model(parent), |
| 29 | Ragdoll(), | ||
| 30 | _owningAvatar(owningAvatar), | 30 | _owningAvatar(owningAvatar), |
| 31 | _boundingShape(), | 31 | _boundingShape(), |
| 32 | _boundingShapeLocalOffset(0.0f) { | 32 | _boundingShapeLocalOffset(0.0f), |
| 33 | _ragdoll(NULL) { | ||
| 34 | } | ||
| 35 | |||
| 36 | SkeletonModel::~SkeletonModel() { | ||
| 37 | delete _ragdoll; | ||
| 38 | _ragdoll = NULL; | ||
| 33 | } | 39 | } |
| 34 | 40 | ||
| 35 | void SkeletonModel::setJointStates(QVector<JointState> states) { | 41 | void SkeletonModel::setJointStates(QVector<JointState> states) { |
| @@ -155,9 +161,6 @@ void SkeletonModel::getBodyShapes(QVector<const Shape*>& shapes) const { · 119 unmodified lines | |||
| 155 | void SkeletonModel::renderIKConstraints() { | 161 | void SkeletonModel::renderIKConstraints() { |
| 156 | renderJointConstraints(getRightHandJointIndex()); | 162 | renderJointConstraints(getRightHandJointIndex()); |
| 157 | renderJointConstraints(getLeftHandJointIndex()); | 163 | renderJointConstraints(getLeftHandJointIndex()); |
| 158 | //if (isActive() && _owningAvatar->isMyAvatar()) { | ||
| 159 | // renderRagdoll(); | ||
| 160 | //} | ||
| 161 | } | 164 | } |
| 162 | 165 | ||
| 163 | class IndexValue { | 166 | class IndexValue { |
| @@ -432,6 +435,10 @@ bool SkeletonModel::getHeadPosition(glm::vec3& headPosition) const { · 268 unmodified lines | |||
| 432 | } | 435 | } |
| 433 | 436 | ||
| 434 | bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const { | 437 | bool SkeletonModel::getNeckPosition(glm::vec3& neckPosition) const { |
| 438 | if (_owningAvatar->isMyAvatar() && | ||
| 439 | Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { | ||
| 440 | return isActive() && getVisibleJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); | ||
| 441 | } | ||
| 435 | return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); | 442 | return isActive() && getJointPositionInWorldFrame(_geometry->getFBXGeometry().neckJointIndex, neckPosition); |
| 436 | } | 443 | } |
| 437 | 444 | ||
| @@ -445,11 +452,16 @@ bool SkeletonModel::getNeckParentRotationFromDefaultOrientation(glm::quat& neckP · 7 unmodified lines | |||
| 445 | } | 452 | } |
| 446 | int parentIndex = geometry.joints.at(geometry.neckJointIndex).parentIndex; | 453 | int parentIndex = geometry.joints.at(geometry.neckJointIndex).parentIndex; |
| 447 | glm::quat worldFrameRotation; | 454 | glm::quat worldFrameRotation; |
| 448 | if (getJointRotationInWorldFrame(parentIndex, worldFrameRotation)) { | 455 | bool success = false; |
| 456 | if (Menu::getInstance()->isOptionChecked(MenuOption::CollideAsRagdoll)) { | ||
| 457 | success = getVisibleJointRotationInWorldFrame(parentIndex, worldFrameRotation); | ||
| 458 | } else { | ||
| 459 | success = getJointRotationInWorldFrame(parentIndex, worldFrameRotation); | ||
| 460 | } | ||
| 461 | if (success) { | ||
| 449 | neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation; | 462 | neckParentRotation = worldFrameRotation * _jointStates[parentIndex].getFBXJoint().inverseDefaultRotation; |
| 450 | return true; | ||
| 451 | } | 463 | } |
| 452 | return false; | 464 | return success; |
| 453 | } | 465 | } |
| 454 | 466 | ||
| 455 | bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { | 467 | bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { |
| @@ -480,21 +492,25 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco · 24 unmodified lines | |||
| 480 | } | 492 | } |
| 481 | 493 | ||
| 482 | void SkeletonModel::renderRagdoll() { | 494 | void SkeletonModel::renderRagdoll() { |
| 495 | if (!_ragdoll) { | ||
| 496 | return; | ||
| 497 | } | ||
| 498 | const QVector<VerletPoint>& points = _ragdoll->getPoints(); | ||
| 483 | const int BALL_SUBDIVISIONS = 6; | 499 | const int BALL_SUBDIVISIONS = 6; |
| 484 | glDisable(GL_DEPTH_TEST); | 500 | glDisable(GL_DEPTH_TEST); |
| 485 | glDisable(GL_LIGHTING); | 501 | glDisable(GL_LIGHTING); |
| 486 | glPushMatrix(); | 502 | glPushMatrix(); |
| 487 | 503 | ||
| 488 | Application::getInstance()->loadTranslatedViewMatrix(_translation); | 504 | Application::getInstance()->loadTranslatedViewMatrix(_translation); |
| 489 | int numPoints = _ragdollPoints.size(); | 505 | int numPoints = points.size(); |
| 490 | float alpha = 0.3f; | 506 | float alpha = 0.3f; |
| 491 | float radius1 = 0.008f; | 507 | float radius1 = 0.008f; |
| 492 | float radius2 = 0.01f; | 508 | float radius2 = 0.01f; |
| 493 | glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); | 509 | glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); |
| 494 | for (int i = 0; i < numPoints; ++i) { | 510 | for (int i = 0; i < numPoints; ++i) { |
| 495 | glPushMatrix(); | 511 | glPushMatrix(); |
| 496 | // NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative | 512 | // NOTE: ragdollPoints are in simulation-frame but we want them to be model-relative |
| 497 | glm::vec3 position = _ragdollPoints[i]._position - simulationTranslation; | 513 | glm::vec3 position = points[i]._position - simulationTranslation; |
| 498 | glTranslatef(position.x, position.y, position.z); | 514 | glTranslatef(position.x, position.y, position.z); |
| 499 | // draw each point as a yellow hexagon with black border | 515 | // draw each point as a yellow hexagon with black border |
| 500 | glColor4f(0.0f, 0.0f, 0.0f, alpha); | 516 | glColor4f(0.0f, 0.0f, 0.0f, alpha); |
| @@ -508,109 +524,18 @@ void SkeletonModel::renderRagdoll() { · 7 unmodified lines | |||
| 508 | glEnable(GL_LIGHTING); | 524 | glEnable(GL_LIGHTING); |
| 509 | } | 525 | } |
| 510 | 526 | ||
| 511 | // virtual | ||
| 512 | void SkeletonModel::initRagdollPoints() { | ||
| 513 | clearRagdollConstraintsAndPoints(); | ||
| 514 | _muscleConstraints.clear(); | ||
| 515 | |||
| 516 | initRagdollTransform(); | ||
| 517 | // one point for each joint | ||
| 518 | int numStates = _jointStates.size(); | ||
| 519 | _ragdollPoints.fill(VerletPoint(), numStates); | ||
| 520 | for (int i = 0; i < numStates; ++i) { | ||
| 521 | const JointState& state = _jointStates.at(i); | ||
| 522 | // _ragdollPoints start in model-frame | ||
| 523 | _ragdollPoints[i].initPosition(state.getPosition()); | ||
| 524 | } | ||
| 525 | } | ||
| 526 | |||
| 527 | void SkeletonModel::buildRagdollConstraints() { | ||
| 528 | // NOTE: the length of DistanceConstraints is computed and locked in at this time | ||
| 529 | // so make sure the ragdoll positions are in a normal configuration before here. | ||
| 530 | const int numPoints = _ragdollPoints.size(); | ||
| 531 | assert(numPoints == _jointStates.size()); | ||
| 532 | |||
| 533 | float minBone = FLT_MAX; | ||
| 534 | float maxBone = -FLT_MAX; | ||
| 535 | QMultiMap<int, int> families; | ||
| 536 | for (int i = 0; i < numPoints; ++i) { | ||
| 537 | const JointState& state = _jointStates.at(i); | ||
| 538 | int parentIndex = state.getParentIndex(); | ||
| 539 | if (parentIndex == -1) { | ||
| 540 | FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_ragdollPoints[i])); | ||
| 541 | _fixedConstraints.push_back(anchor); | ||
| 542 | } else { | ||
| 543 | DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[i]), &(_ragdollPoints[parentIndex])); | ||
| 544 | bone->setDistance(state.getDistanceToParent()); | ||
| 545 | _boneConstraints.push_back(bone); | ||
| 546 | families.insert(parentIndex, i); | ||
| 547 | } | ||
| 548 | float boneLength = glm::length(state.getPositionInParentFrame()); | ||
| 549 | if (boneLength > maxBone) { | ||
| 550 | maxBone = boneLength; | ||
| 551 | } else if (boneLength < minBone) { | ||
| 552 | minBone = boneLength; | ||
| 553 | } | ||
| 554 | } | ||
| 555 | // Joints that have multiple children effectively have rigid constraints between the children | ||
| 556 | // in the parent frame, so we add DistanceConstraints between children in the same family. | ||
| 557 | QMultiMap<int, int>::iterator itr = families.begin(); | ||
| 558 | while (itr != families.end()) { | ||
| 559 | QList<int> children = families.values(itr.key()); | ||
| 560 | int numChildren = children.size(); | ||
| 561 | if (numChildren > 1) { | ||
| 562 | for (int i = 1; i < numChildren; ++i) { | ||
| 563 | DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[i-1]]), &(_ragdollPoints[children[i]])); | ||
| 564 | _boneConstraints.push_back(bone); | ||
| 565 | } | ||
| 566 | if (numChildren > 2) { | ||
| 567 | DistanceConstraint* bone = new DistanceConstraint(&(_ragdollPoints[children[numChildren-1]]), &(_ragdollPoints[children[0]])); | ||
| 568 | _boneConstraints.push_back(bone); | ||
| 569 | } | ||
| 570 | } | ||
| 571 | ++itr; | ||
| 572 | } | ||
| 573 | |||
| 574 | float MAX_STRENGTH = 0.6f; | ||
| 575 | float MIN_STRENGTH = 0.05f; | ||
| 576 | // each joint gets a MuscleConstraint to its parent | ||
| 577 | for (int i = 1; i < numPoints; ++i) { | ||
| 578 | const JointState& state = _jointStates.at(i); | ||
| 579 | int p = state.getParentIndex(); | ||
| 580 | if (p == -1) { | ||
| 581 | continue; | ||
| 582 | } | ||
| 583 | MuscleConstraint* constraint = new MuscleConstraint(&(_ragdollPoints[p]), &(_ragdollPoints[i])); | ||
| 584 | _muscleConstraints.push_back(constraint); | ||
| 585 | |||
| 586 | // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length: | ||
| 587 | // long = weak and short = strong. | ||
| 588 | constraint->setIndices(p, i); | ||
| 589 | float boneLength = glm::length(state.getPositionInParentFrame()); | ||
| 590 | |||
| 591 | float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone); | ||
| 592 | if (!families.contains(i)) { | ||
| 593 | // Although muscles only pull on the children not parents, nevertheless those joints that have | ||
| 594 | // parents AND children are more stable than joints at the end such as fingers. For such joints we | ||
| 595 | // bestow maximum strength which helps reduce wiggle. | ||
| 596 | strength = MAX_MUSCLE_STRENGTH; | ||
| 597 | } | ||
| 598 | constraint->setStrength(strength); | ||
| 599 | } | ||
| 600 | |||
| 601 | } | ||
| 602 | |||
| 603 | void SkeletonModel::updateVisibleJointStates() { | 527 | void SkeletonModel::updateVisibleJointStates() { |
| 604 | if (_showTrueJointTransforms) { | 528 | if (_showTrueJointTransforms || !_ragdoll) { |
| 605 | // no need to update visible transforms | 529 | // no need to update visible transforms |
| 606 | return; | 530 | return; |
| 607 | } | 531 | } |
| 532 | const QVector<VerletPoint>& ragdollPoints = _ragdoll->getPoints(); | ||
| 608 | QVector<glm::vec3> points; | 533 | QVector<glm::vec3> points; |
| 609 | points.reserve(_jointStates.size()); | 534 | points.reserve(_jointStates.size()); |
| 610 | glm::quat invRotation = glm::inverse(_rotation); | 535 | glm::quat invRotation = glm::inverse(_rotation); |
| 611 | for (int i = 0; i < _jointStates.size(); i++) { | 536 | for (int i = 0; i < _jointStates.size(); i++) { |
| 612 | JointState& state = _jointStates[i]; | 537 | JointState& state = _jointStates[i]; |
| 613 | points.push_back(_ragdollPoints[i]._position); | 538 | points.push_back(ragdollPoints[i]._position); |
| 614 | 539 | ||
| 615 | // get the parent state (this is the state that we want to rotate) | 540 | // get the parent state (this is the state that we want to rotate) |
| 616 | int parentIndex = state.getParentIndex(); | 541 | int parentIndex = state.getParentIndex(); |
| @@ -644,15 +569,14 @@ void SkeletonModel::updateVisibleJointStates() { · 27 unmodified lines | |||
| 644 | } | 569 | } |
| 645 | } | 570 | } |
| 646 | 571 | ||
| 647 | // virtual | 572 | SkeletonRagdoll* SkeletonModel::buildRagdoll() { |
| 648 | void SkeletonModel::stepRagdollForward(float deltaTime) { | 573 | if (!_ragdoll) { |
| 649 | setRagdollTransform(_translation, _rotation); | 574 | _ragdoll = new SkeletonRagdoll(this); |
| 650 | Ragdoll::stepRagdollForward(deltaTime); | 575 | if (_enableShapes) { |
| 651 | updateMuscles(); | 576 | buildShapes(); |
| 652 | int numConstraints = _muscleConstraints.size(); | 577 | } |
| 653 | for (int i = 0; i < numConstraints; ++i) { | ||
| 654 | _muscleConstraints[i]->enforce(); | ||
| 655 | } | 578 | } |
| 579 | return _ragdoll; | ||
| 656 | } | 580 | } |
| 657 | 581 | ||
| 658 | float DENSITY_OF_WATER = 1000.0f; // kg/m^3 | 582 | float DENSITY_OF_WATER = 1000.0f; // kg/m^3 |
| @@ -670,8 +594,13 @@ void SkeletonModel::buildShapes() { · 11 unmodified lines | |||
| 670 | return; | 594 | return; |
| 671 | } | 595 | } |
| 672 | 596 | ||
| 673 | initRagdollPoints(); | 597 | if (!_ragdoll) { |
| 674 | float massScale = getMassScale(); | 598 | _ragdoll = new SkeletonRagdoll(this); |
| 599 | } | ||
| 600 | _ragdoll->initPoints(); | ||
| 601 | QVector<VerletPoint>& points = _ragdoll->getPoints(); | ||
| 602 | |||
| 603 | float massScale = _ragdoll->getMassScale(); | ||
| 675 | 604 | ||
| 676 | float uniformScale = extractUniformScale(_scale); | 605 | float uniformScale = extractUniformScale(_scale); |
| 677 | const int numStates = _jointStates.size(); | 606 | const int numStates = _jointStates.size(); |
| @@ -691,14 +620,14 @@ void SkeletonModel::buildShapes() { · 13 unmodified lines | |||
| 691 | Shape* shape = NULL; | 620 | Shape* shape = NULL; |
| 692 | int parentIndex = joint.parentIndex; | 621 | int parentIndex = joint.parentIndex; |
| 693 | if (type == Shape::SPHERE_SHAPE) { | 622 | if (type == Shape::SPHERE_SHAPE) { |
| 694 | shape = new VerletSphereShape(radius, &(_ragdollPoints[i])); | 623 | shape = new VerletSphereShape(radius, &(points[i])); |
| 695 | shape->setEntity(this); | 624 | shape->setEntity(this); |
| 696 | _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); | 625 | points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); |
| 697 | } else if (type == Shape::CAPSULE_SHAPE) { | 626 | } else if (type == Shape::CAPSULE_SHAPE) { |
| 698 | assert(parentIndex != -1); | 627 | assert(parentIndex != -1); |
| 699 | shape = new VerletCapsuleShape(radius, &(_ragdollPoints[parentIndex]), &(_ragdollPoints[i])); | 628 | shape = new VerletCapsuleShape(radius, &(points[parentIndex]), &(points[i])); |
| 700 | shape->setEntity(this); | 629 | shape->setEntity(this); |
| 701 | _ragdollPoints[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); | 630 | points[i].setMass(massScale * glm::max(MIN_JOINT_MASS, DENSITY_OF_WATER * shape->getVolume())); |
| 702 | } | 631 | } |
| 703 | if (parentIndex != -1) { | 632 | if (parentIndex != -1) { |
| 704 | // always disable collisions between joint and its parent | 633 | // always disable collisions between joint and its parent |
| @@ -708,7 +637,7 @@ void SkeletonModel::buildShapes() { · 3 unmodified lines | |||
| 708 | } else { | 637 | } else { |
| 709 | // give the base joint a very large mass since it doesn't actually move | 638 | // give the base joint a very large mass since it doesn't actually move |
| 710 | // in the local-frame simulation (it defines the origin) | 639 | // in the local-frame simulation (it defines the origin) |
| 711 | _ragdollPoints[i].setMass(VERY_BIG_MASS); | 640 | points[i].setMass(VERY_BIG_MASS); |
| 712 | } | 641 | } |
| 713 | _shapes.push_back(shape); | 642 | _shapes.push_back(shape); |
| 714 | } | 643 | } |
| @@ -720,17 +649,11 @@ void SkeletonModel::buildShapes() { · 5 unmodified lines | |||
| 720 | // joints that are currently colliding. | 649 | // joints that are currently colliding. |
| 721 | disableCurrentSelfCollisions(); | 650 | disableCurrentSelfCollisions(); |
| 722 | 651 | ||
| 723 | buildRagdollConstraints(); | 652 | _ragdoll->buildConstraints(); |
| 724 | 653 | ||
| 725 | // ... then move shapes back to current joint positions | 654 | // ... then move shapes back to current joint positions |
| 726 | if (_ragdollPoints.size() == numStates) { | 655 | _ragdoll->slamPointPositions(); |
| 727 | int numStates = _jointStates.size(); | 656 | _ragdoll->enforceConstraints(); |
| 728 | for (int i = 0; i < numStates; ++i) { | ||
| 729 | // ragdollPoints start in model-frame | ||
| 730 | _ragdollPoints[i].initPosition(_jointStates.at(i).getPosition()); | ||
| 731 | } | ||
| 732 | } | ||
| 733 | enforceRagdollConstraints(); | ||
| 734 | } | 657 | } |
| 735 | 658 | ||
| 736 | void SkeletonModel::moveShapesTowardJoints(float deltaTime) { | 659 | void SkeletonModel::moveShapesTowardJoints(float deltaTime) { |
| @@ -738,8 +661,9 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { · 1 unmodified line | |||
| 738 | // unravel a skelton that has become tangled in its constraints. So let's keep this | 661 | // unravel a skelton that has become tangled in its constraints. So let's keep this |
| 739 | // around for a while just in case. | 662 | // around for a while just in case. |
| 740 | const int numStates = _jointStates.size(); | 663 | const int numStates = _jointStates.size(); |
| 741 | assert(_jointStates.size() == _ragdollPoints.size()); | 664 | QVector<VerletPoint>& ragdollPoints = _ragdoll->getPoints(); |
| 742 | if (_ragdollPoints.size() != numStates) { | 665 | assert(_jointStates.size() == ragdollPoints.size()); |
| 666 | if (ragdollPoints.size() != numStates) { | ||
| 743 | return; | 667 | return; |
| 744 | } | 668 | } |
| 745 | 669 | ||
| @@ -748,32 +672,22 @@ void SkeletonModel::moveShapesTowardJoints(float deltaTime) { · 2 unmodified lines | |||
| 748 | float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f); | 672 | float fraction = glm::clamp(deltaTime / RAGDOLL_FOLLOWS_JOINTS_TIMESCALE, 0.0f, 1.0f); |
| 749 | 673 | ||
| 750 | float oneMinusFraction = 1.0f - fraction; | 674 | float oneMinusFraction = 1.0f - fraction; |
| 751 | glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); | 675 | glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); |
| 752 | for (int i = 0; i < numStates; ++i) { | 676 | for (int i = 0; i < numStates; ++i) { |
| 753 | // ragdollPoints are in simulation-frame but jointStates are in model-frame | 677 | // ragdollPoints are in simulation-frame but jointStates are in model-frame |
| 754 | _ragdollPoints[i].initPosition(oneMinusFraction * _ragdollPoints[i]._position + | 678 | ragdollPoints[i].initPosition(oneMinusFraction * ragdollPoints[i]._position + |
| 755 | fraction * (simulationTranslation + _rotation * (_jointStates.at(i).getPosition()))); | 679 | fraction * (simulationTranslation + _rotation * (_jointStates.at(i).getPosition()))); |
| 756 | } | 680 | } |
| 757 | } | 681 | } |
| 758 | 682 | ||
| 759 | void SkeletonModel::updateMuscles() { | ||
| 760 | int numConstraints = _muscleConstraints.size(); | ||
| 761 | for (int i = 0; i < numConstraints; ++i) { | ||
| 762 | MuscleConstraint* constraint = _muscleConstraints[i]; | ||
| 763 | int j = constraint->getParentIndex(); | ||
| 764 | int k = constraint->getChildIndex(); | ||
| 765 | assert(j != -1 && k != -1); | ||
| 766 | // ragdollPoints are in simulation-frame but jointStates are in model-frame | ||
| 767 | constraint->setChildOffset(_rotation * (_jointStates.at(k).getPosition() - _jointStates.at(j).getPosition())); | ||
| 768 | } | ||
| 769 | } | ||
| 770 | |||
| 771 | void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { | 683 | void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { |
| 772 | // compute default joint transforms | 684 | // compute default joint transforms |
| 773 | int numStates = _jointStates.size(); | 685 | int numStates = _jointStates.size(); |
| 774 | QVector<glm::mat4> transforms; | 686 | QVector<glm::mat4> transforms; |
| 775 | transforms.fill(glm::mat4(), numStates); | 687 | transforms.fill(glm::mat4(), numStates); |
| 776 | 688 | ||
| 689 | QVector<VerletPoint>& ragdollPoints = _ragdoll->getPoints(); | ||
| 690 | |||
| 777 | // compute the default transforms and slam the ragdoll positions accordingly | 691 | // compute the default transforms and slam the ragdoll positions accordingly |
| 778 | // (which puts the shapes where we want them) | 692 | // (which puts the shapes where we want them) |
| 779 | for (int i = 0; i < numStates; i++) { | 693 | for (int i = 0; i < numStates; i++) { |
| @@ -782,7 +696,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { · 2 unmodified lines | |||
| 782 | int parentIndex = joint.parentIndex; | 696 | int parentIndex = joint.parentIndex; |
| 783 | if (parentIndex == -1) { | 697 | if (parentIndex == -1) { |
| 784 | transforms[i] = _jointStates[i].getTransform(); | 698 | transforms[i] = _jointStates[i].getTransform(); |
| 785 | _ragdollPoints[i].initPosition(extractTranslation(transforms[i])); | 699 | ragdollPoints[i].initPosition(extractTranslation(transforms[i])); |
| 786 | continue; | 700 | continue; |
| 787 | } | 701 | } |
| 788 | 702 | ||
| @@ -790,7 +704,7 @@ void SkeletonModel::computeBoundingShape(const FBXGeometry& geometry) { · 1 unmodified line | |||
| 790 | transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) | 704 | transforms[i] = transforms[parentIndex] * glm::translate(joint.translation) |
| 791 | * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform; | 705 | * joint.preTransform * glm::mat4_cast(modifiedRotation) * joint.postTransform; |
| 792 | // setting the ragdollPoints here slams the VerletShapes into their default positions | 706 | // setting the ragdollPoints here slams the VerletShapes into their default positions |
| 793 | _ragdollPoints[i].initPosition(extractTranslation(transforms[i])); | 707 | ragdollPoints[i].initPosition(extractTranslation(transforms[i])); |
| 794 | } | 708 | } |
| 795 | 709 | ||
| 796 | // compute bounding box that encloses all shapes | 710 | // compute bounding box that encloses all shapes |
| @@ -909,9 +823,12 @@ const int BALL_SUBDIVISIONS = 10; · 112 unmodified lines | |||
| 909 | 823 | ||
| 910 | // virtual | 824 | // virtual |
| 911 | void SkeletonModel::renderJointCollisionShapes(float alpha) { | 825 | void SkeletonModel::renderJointCollisionShapes(float alpha) { |
| 826 | if (!_ragdoll) { | ||
| 827 | return; | ||
| 828 | } | ||
| 912 | glPushMatrix(); | 829 | glPushMatrix(); |
| 913 | Application::getInstance()->loadTranslatedViewMatrix(_translation); | 830 | Application::getInstance()->loadTranslatedViewMatrix(_translation); |
| 914 | glm::vec3 simulationTranslation = getTranslationInSimulationFrame(); | 831 | glm::vec3 simulationTranslation = _ragdoll->getTranslationInSimulationFrame(); |
| 915 | for (int i = 0; i < _shapes.size(); i++) { | 832 | for (int i = 0; i < _shapes.size(); i++) { |
| 916 | Shape* shape = _shapes[i]; | 833 | Shape* shape = _shapes[i]; |
| 917 | if (!shape) { | 834 | if (!shape) { |
| @@ -15,18 +15,20 @@ · 14 unmodified lines | |||
| 15 | #include "renderer/Model.h" | 15 | #include "renderer/Model.h" |
| 16 | 16 | ||
| 17 | #include <CapsuleShape.h> | 17 | #include <CapsuleShape.h> |
| 18 | #include <Ragdoll.h> | 18 | #include "SkeletonRagdoll.h" |
| 19 | 19 | ||
| 20 | class Avatar; | 20 | class Avatar; |
| 21 | class MuscleConstraint; | 21 | class MuscleConstraint; |
| 22 | class SkeletonRagdoll; | ||
| 22 | 23 | ||
| 23 | /// A skeleton loaded from a model. | 24 | /// A skeleton loaded from a model. |
| 24 | class SkeletonModel : public Model, public Ragdoll { | 25 | class SkeletonModel : public Model { |
| 25 | Q_OBJECT | 26 | Q_OBJECT |
| 26 | 27 | ||
| 27 | public: | 28 | public: |
| 28 | 29 | ||
| 29 | SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL); | 30 | SkeletonModel(Avatar* owningAvatar, QObject* parent = NULL); |
| 31 | ~SkeletonModel(); | ||
| 30 | 32 | ||
| 31 | void setJointStates(QVector<JointState> states); | 33 | void setJointStates(QVector<JointState> states); |
| 32 | 34 | ||
| @@ -96,12 +98,11 @@ public: · 63 unmodified lines | |||
| 96 | bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; | 98 | bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; |
| 97 | 99 | ||
| 98 | virtual void updateVisibleJointStates(); | 100 | virtual void updateVisibleJointStates(); |
| 99 | |||
| 100 | // virtual overrride from Ragdoll | ||
| 101 | virtual void stepRagdollForward(float deltaTime); | ||
| 102 | 101 | ||
| 102 | SkeletonRagdoll* buildRagdoll(); | ||
| 103 | SkeletonRagdoll* getRagdoll() { return _ragdoll; } | ||
| 104 | |||
| 103 | void moveShapesTowardJoints(float fraction); | 105 | void moveShapesTowardJoints(float fraction); |
| 104 | void updateMuscles(); | ||
| 105 | 106 | ||
| 106 | void computeBoundingShape(const FBXGeometry& geometry); | 107 | void computeBoundingShape(const FBXGeometry& geometry); |
| 107 | void renderBoundingCollisionShapes(float alpha); | 108 | void renderBoundingCollisionShapes(float alpha); |
| @@ -115,10 +116,6 @@ public: · 7 unmodified lines | |||
| 115 | 116 | ||
| 116 | protected: | 117 | protected: |
| 117 | 118 | ||
| 118 | // virtual overrrides from Ragdoll | ||
| 119 | void initRagdollPoints(); | ||
| 120 | void buildRagdollConstraints(); | ||
| 121 | |||
| 122 | void buildShapes(); | 119 | void buildShapes(); |
| 123 | 120 | ||
| 124 | /// \param jointIndex index of joint in model | 121 | /// \param jointIndex index of joint in model |
| @@ -147,7 +144,7 @@ private: · 22 unmodified lines | |||
| 147 | 144 | ||
| 148 | CapsuleShape _boundingShape; | 145 | CapsuleShape _boundingShape; |
| 149 | glm::vec3 _boundingShapeLocalOffset; | 146 | glm::vec3 _boundingShapeLocalOffset; |
| 150 | QVector<MuscleConstraint*> _muscleConstraints; | 147 | SkeletonRagdoll* _ragdoll; |
| 151 | }; | 148 | }; |
| 152 | 149 | ||
| 153 | #endif // hifi_SkeletonModel_h | 150 | #endif // hifi_SkeletonModel_h |
| @@ -0,0 +1,148 @@ | |||
| 1 | // | ||
| 2 | // SkeletonRagdoll.cpp | ||
| 3 | // interface/src/avatar | ||
| 4 | // | ||
| 5 | // Created by Andrew Meadows 2014.08.14 | ||
| 6 | // Copyright 2014 High Fidelity, Inc. | ||
| 7 | // | ||
| 8 | // Distributed under the Apache License, Version 2.0. | ||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | // | ||
| 11 | |||
| 12 | #include <DistanceConstraint.h> | ||
| 13 | #include <FixedConstraint.h> | ||
| 14 | |||
| 15 | #include "SkeletonRagdoll.h" | ||
| 16 | #include "MuscleConstraint.h" | ||
| 17 | #include "../renderer/Model.h" | ||
| 18 | |||
| 19 | SkeletonRagdoll::SkeletonRagdoll(Model* model) : Ragdoll(), _model(model) { | ||
| 20 | assert(_model); | ||
| 21 | } | ||
| 22 | |||
| 23 | SkeletonRagdoll::~SkeletonRagdoll() { | ||
| 24 | } | ||
| 25 | |||
| 26 | // virtual | ||
| 27 | void SkeletonRagdoll::stepForward(float deltaTime) { | ||
| 28 | setTransform(_model->getTranslation(), _model->getRotation()); | ||
| 29 | Ragdoll::stepForward(deltaTime); | ||
| 30 | updateMuscles(); | ||
| 31 | int numConstraints = _muscleConstraints.size(); | ||
| 32 | for (int i = 0; i < numConstraints; ++i) { | ||
| 33 | _muscleConstraints[i]->enforce(); | ||
| 34 | } | ||
| 35 | } | ||
| 36 | |||
| 37 | void SkeletonRagdoll::slamPointPositions() { | ||
| 38 | QVector<JointState>& jointStates = _model->getJointStates(); | ||
| 39 | int numStates = jointStates.size(); | ||
| 40 | for (int i = 0; i < numStates; ++i) { | ||
| 41 | _points[i].initPosition(jointStates.at(i).getPosition()); | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | // virtual | ||
| 46 | void SkeletonRagdoll::initPoints() { | ||
| 47 | clearConstraintsAndPoints(); | ||
| 48 | _muscleConstraints.clear(); | ||
| 49 | |||
| 50 | initTransform(); | ||
| 51 | // one point for each joint | ||
| 52 | QVector<JointState>& jointStates = _model->getJointStates(); | ||
| 53 | int numStates = jointStates.size(); | ||
| 54 | _points.fill(VerletPoint(), numStates); | ||
| 55 | slamPointPositions(); | ||
| 56 | } | ||
| 57 | |||
| 58 | // virtual | ||
| 59 | void SkeletonRagdoll::buildConstraints() { | ||
| 60 | QVector<JointState>& jointStates = _model->getJointStates(); | ||
| 61 | |||
| 62 | // NOTE: the length of DistanceConstraints is computed and locked in at this time | ||
| 63 | // so make sure the ragdoll positions are in a normal configuration before here. | ||
| 64 | const int numPoints = _points.size(); | ||
| 65 | assert(numPoints == jointStates.size()); | ||
| 66 | |||
| 67 | float minBone = FLT_MAX; | ||
| 68 | float maxBone = -FLT_MAX; | ||
| 69 | QMultiMap<int, int> families; | ||
| 70 | for (int i = 0; i < numPoints; ++i) { | ||
| 71 | const JointState& state = jointStates.at(i); | ||
| 72 | int parentIndex = state.getParentIndex(); | ||
| 73 | if (parentIndex == -1) { | ||
| 74 | FixedConstraint* anchor = new FixedConstraint(&_translationInSimulationFrame, &(_points[i])); | ||
| 75 | _fixedConstraints.push_back(anchor); | ||
| 76 | } else { | ||
| 77 | DistanceConstraint* bone = new DistanceConstraint(&(_points[i]), &(_points[parentIndex])); | ||
| 78 | bone->setDistance(state.getDistanceToParent()); | ||
| 79 | _boneConstraints.push_back(bone); | ||
| 80 | families.insert(parentIndex, i); | ||
| 81 | } | ||
| 82 | float boneLength = glm::length(state.getPositionInParentFrame()); | ||
| 83 | if (boneLength > maxBone) { | ||
| 84 | maxBone = boneLength; | ||
| 85 | } else if (boneLength < minBone) { | ||
| 86 | minBone = boneLength; | ||
| 87 | } | ||
| 88 | } | ||
| 89 | // Joints that have multiple children effectively have rigid constraints between the children | ||
| 90 | // in the parent frame, so we add DistanceConstraints between children in the same family. | ||
| 91 | QMultiMap<int, int>::iterator itr = families.begin(); | ||
| 92 | while (itr != families.end()) { | ||
| 93 | QList<int> children = families.values(itr.key()); | ||
| 94 | int numChildren = children.size(); | ||
| 95 | if (numChildren > 1) { | ||
| 96 | for (int i = 1; i < numChildren; ++i) { | ||
| 97 | DistanceConstraint* bone = new DistanceConstraint(&(_points[children[i-1]]), &(_points[children[i]])); | ||
| 98 | _boneConstraints.push_back(bone); | ||
| 99 | } | ||
| 100 | if (numChildren > 2) { | ||
| 101 | DistanceConstraint* bone = new DistanceConstraint(&(_points[children[numChildren-1]]), &(_points[children[0]])); | ||
| 102 | _boneConstraints.push_back(bone); | ||
| 103 | } | ||
| 104 | } | ||
| 105 | ++itr; | ||
| 106 | } | ||
| 107 | |||
| 108 | float MAX_STRENGTH = 0.6f; | ||
| 109 | float MIN_STRENGTH = 0.05f; | ||
| 110 | // each joint gets a MuscleConstraint to its parent | ||
| 111 | for (int i = 1; i < numPoints; ++i) { | ||
| 112 | const JointState& state = jointStates.at(i); | ||
| 113 | int p = state.getParentIndex(); | ||
| 114 | if (p == -1) { | ||
| 115 | continue; | ||
| 116 | } | ||
| 117 | MuscleConstraint* constraint = new MuscleConstraint(&(_points[p]), &(_points[i])); | ||
| 118 | _muscleConstraints.push_back(constraint); | ||
| 119 | |||
| 120 | // Short joints are more susceptible to wiggle so we modulate the strength based on the joint's length: | ||
| 121 | // long = weak and short = strong. | ||
| 122 | constraint->setIndices(p, i); | ||
| 123 | float boneLength = glm::length(state.getPositionInParentFrame()); | ||
| 124 | |||
| 125 | float strength = MIN_STRENGTH + (MAX_STRENGTH - MIN_STRENGTH) * (maxBone - boneLength) / (maxBone - minBone); | ||
| 126 | if (!families.contains(i)) { | ||
| 127 | // Although muscles only pull on the children not parents, nevertheless those joints that have | ||
| 128 | // parents AND children are more stable than joints at the end such as fingers. For such joints we | ||
| 129 | // bestow maximum strength which helps reduce wiggle. | ||
| 130 | strength = MAX_MUSCLE_STRENGTH; | ||
| 131 | } | ||
| 132 | constraint->setStrength(strength); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | void SkeletonRagdoll::updateMuscles() { | ||
| 137 | QVector<JointState>& jointStates = _model->getJointStates(); | ||
| 138 | int numConstraints = _muscleConstraints.size(); | ||
| 139 | glm::quat rotation = _model->getRotation(); | ||
| 140 | for (int i = 0; i < numConstraints; ++i) { | ||
| 141 | MuscleConstraint* constraint = _muscleConstraints[i]; | ||
| 142 | int j = constraint->getParentIndex(); | ||
| 143 | int k = constraint->getChildIndex(); | ||
| 144 | assert(j != -1 && k != -1); | ||
| 145 | // ragdollPoints are in simulation-frame but jointStates are in model-frame | ||
| 146 | constraint->setChildOffset(rotation * (jointStates.at(k).getPosition() - jointStates.at(j).getPosition())); | ||
| 147 | } | ||
| 148 | } | ||
| @@ -0,0 +1,42 @@ | |||
| 1 | // | ||
| 2 | // SkeletonkRagdoll.h | ||
| 3 | // interface/src/avatar | ||
| 4 | // | ||
| 5 | // Created by Andrew Meadows 2014.08.14 | ||
| 6 | // Copyright 2014 High Fidelity, Inc. | ||
| 7 | // | ||
| 8 | // Distributed under the Apache License, Version 2.0. | ||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | // | ||
| 11 | |||
| 12 | #ifndef hifi_SkeletonRagdoll_h | ||
| 13 | #define hifi_SkeletonRagdoll_h | ||
| 14 | |||
| 15 | #include <QVector> | ||
| 16 | |||
| 17 | #include <Ragdoll.h> | ||
| 18 | |||
| 19 | #include "../renderer/JointState.h" | ||
| 20 | |||
| 21 | class MuscleConstraint; | ||
| 22 | class Model; | ||
| 23 | |||
| 24 | class SkeletonRagdoll : public Ragdoll { | ||
| 25 | public: | ||
| 26 | |||
| 27 | SkeletonRagdoll(Model* model); | ||
| 28 | virtual ~SkeletonRagdoll(); | ||
| 29 | |||
| 30 | void slamPointPositions(); | ||
| 31 | virtual void stepForward(float deltaTime); | ||
| 32 | |||
| 33 | virtual void initPoints(); | ||
| 34 | virtual void buildConstraints(); | ||
| 35 | |||
| 36 | void updateMuscles(); | ||
| 37 | private: | ||
| 38 | Model* _model; | ||
| 39 | QVector<MuscleConstraint*> _muscleConstraints; | ||
| 40 | }; | ||
| 41 | |||
| 42 | #endif // hifi_SkeletonRagdoll_h | ||
| @@ -10,7 +10,7 @@ · 9 unmodified lines | |||
| 10 | // | 10 | // |
| 11 | 11 | ||
| 12 | #include "CaraFaceTracker.h" | 12 | #include "CaraFaceTracker.h" |
| 13 | #include <SharedUtil.h> | 13 | #include <GLMHelpers.h> |
| 14 | 14 | ||
| 15 | //qt | 15 | //qt |
| 16 | #include <QJsonDocument> | 16 | #include <QJsonDocument> |
| @@ -178,6 +178,31 @@ float rescaleCoef(float ddeCoef) { · 177 unmodified lines | |||
| 178 | return (ddeCoef - DDE_MIN_RANGE) / (DDE_MAX_RANGE - DDE_MIN_RANGE); | 178 | return (ddeCoef - DDE_MIN_RANGE) / (DDE_MAX_RANGE - DDE_MIN_RANGE); |
| 179 | } | 179 | } |
| 180 | 180 | ||
| 181 | const int MIN = 0; | ||
| 182 | const int AVG = 1; | ||
| 183 | const int MAX = 2; | ||
| 184 | const float LONG_TERM_AVERAGE = 0.999f; | ||
| 185 | |||
| 186 | |||
| 187 | void resetCoefficient(float * coefficient, float currentValue) { | ||
| 188 | coefficient[MIN] = coefficient[MAX] = coefficient[AVG] = currentValue; | ||
| 189 | } | ||
| 190 | |||
| 191 | float updateAndGetCoefficient(float * coefficient, float currentValue, bool scaleToRange = false) { | ||
| 192 | coefficient[MIN] = (currentValue < coefficient[MIN]) ? currentValue : coefficient[MIN]; | ||
| 193 | coefficient[MAX] = (currentValue > coefficient[MAX]) ? currentValue : coefficient[MAX]; | ||
| 194 | coefficient[AVG] = LONG_TERM_AVERAGE * coefficient[AVG] + (1.f - LONG_TERM_AVERAGE) * currentValue; | ||
| 195 | if (coefficient[MAX] > coefficient[MIN]) { | ||
| 196 | if (scaleToRange) { | ||
| 197 | return glm::clamp((currentValue - coefficient[AVG]) / (coefficient[MAX] - coefficient[MIN]), 0.f, 1.f); | ||
| 198 | } else { | ||
| 199 | return glm::clamp(currentValue - coefficient[AVG], 0.f, 1.f); | ||
| 200 | } | ||
| 201 | } else { | ||
| 202 | return 0.f; | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 181 | void DdeFaceTracker::decodePacket(const QByteArray& buffer) { | 206 | void DdeFaceTracker::decodePacket(const QByteArray& buffer) { |
| 182 | if(buffer.size() > MIN_PACKET_SIZE) { | 207 | if(buffer.size() > MIN_PACKET_SIZE) { |
| 183 | Packet packet; | 208 | Packet packet; |
| @@ -189,14 +214,17 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 5 unmodified lines | |||
| 189 | memcpy(&translation, packet.translation, sizeof(packet.translation)); | 214 | memcpy(&translation, packet.translation, sizeof(packet.translation)); |
| 190 | glm::quat rotation; | 215 | glm::quat rotation; |
| 191 | memcpy(&rotation, &packet.rotation, sizeof(packet.rotation)); | 216 | memcpy(&rotation, &packet.rotation, sizeof(packet.rotation)); |
| 192 | if (_reset) { | 217 | if (_reset || (_lastReceiveTimestamp == 0)) { |
| 193 | memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3)); | 218 | memcpy(&_referenceTranslation, &translation, sizeof(glm::vec3)); |
| 194 | memcpy(&_referenceRotation, &rotation, sizeof(glm::quat)); | 219 | memcpy(&_referenceRotation, &rotation, sizeof(glm::quat)); |
| 220 | |||
| 221 | resetCoefficient(_rightEye, packet.expressions[0]); | ||
| 222 | resetCoefficient(_leftEye, packet.expressions[1]); | ||
| 195 | _reset = false; | 223 | _reset = false; |
| 196 | } | 224 | } |
| 197 | 225 | ||
| 198 | // Compute relative translation | 226 | // Compute relative translation |
| 199 | float LEAN_DAMPING_FACTOR = 40; | 227 | float LEAN_DAMPING_FACTOR = 200.0f; |
| 200 | translation -= _referenceTranslation; | 228 | translation -= _referenceTranslation; |
| 201 | translation /= LEAN_DAMPING_FACTOR; | 229 | translation /= LEAN_DAMPING_FACTOR; |
| 202 | translation.x *= -1; | 230 | translation.x *= -1; |
| @@ -208,10 +236,19 @@ void DdeFaceTracker::decodePacket(const QByteArray& buffer) { · 5 unmodified lines | |||
| 208 | _headTranslation = translation; | 236 | _headTranslation = translation; |
| 209 | _headRotation = rotation; | 237 | _headRotation = rotation; |
| 210 | 238 | ||
| 239 | if (_lastReceiveTimestamp == 0) { | ||
| 240 | // On first packet, reset coefficients | ||
| 241 | } | ||
| 242 | |||
| 211 | // Set blendshapes | 243 | // Set blendshapes |
| 212 | float BLINK_MAGNIFIER = 2.0f; | 244 | float EYE_MAGNIFIER = 4.0f; |
| 213 | _blendshapeCoefficients[_leftBlinkIndex] = rescaleCoef(packet.expressions[1]) * BLINK_MAGNIFIER; | 245 | |
| 214 | _blendshapeCoefficients[_rightBlinkIndex] = rescaleCoef(packet.expressions[0]) * BLINK_MAGNIFIER; | 246 | float rightEye = (updateAndGetCoefficient(_rightEye, packet.expressions[0])) * EYE_MAGNIFIER; |
| 247 | _blendshapeCoefficients[_rightBlinkIndex] = rightEye; | ||
| 248 | float leftEye = (updateAndGetCoefficient(_leftEye, packet.expressions[1])) * EYE_MAGNIFIER; | ||
| 249 | _blendshapeCoefficients[_leftBlinkIndex] = leftEye; | ||
| 250 | |||
| 251 | // Right eye = packet.expressions[0]; | ||
| 215 | 252 | ||
| 216 | float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]); | 253 | float leftBrow = 1.0f - rescaleCoef(packet.expressions[14]); |
| 217 | if (leftBrow < 0.5f) { | 254 | if (leftBrow < 0.5f) { |
| @@ -84,6 +84,10 @@ private: · 83 unmodified lines | |||
| 84 | int _mouthSmileRightIndex; | 84 | int _mouthSmileRightIndex; |
| 85 | 85 | ||
| 86 | int _jawOpenIndex; | 86 | int _jawOpenIndex; |
| 87 | |||
| 88 | float _leftEye[3]; | ||
| 89 | float _rightEye[3]; | ||
| 90 | |||
| 87 | }; | 91 | }; |
| 88 | 92 | ||
| 89 | #endif // hifi_DdeFaceTracker_h | 93 | #endif // hifi_DdeFaceTracker_h |
| @@ -44,7 +44,7 @@ ovrFovPort OculusManager::_eyeFov[ovrEye_Count]; · 43 unmodified lines | |||
| 44 | ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count]; | 44 | ovrEyeRenderDesc OculusManager::_eyeRenderDesc[ovrEye_Count]; |
| 45 | ovrSizei OculusManager::_renderTargetSize; | 45 | ovrSizei OculusManager::_renderTargetSize; |
| 46 | ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2]; | 46 | ovrVector2f OculusManager::_UVScaleOffset[ovrEye_Count][2]; |
| 47 | GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 }; | 47 | GLuint OculusManager::_vertices[ovrEye_Count] = { 0, 0 }; |
| 48 | GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 }; | 48 | GLuint OculusManager::_indices[ovrEye_Count] = { 0, 0 }; |
| 49 | GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 }; | 49 | GLsizei OculusManager::_meshSize[ovrEye_Count] = { 0, 0 }; |
| 50 | ovrFrameTiming OculusManager::_hmdFrameTiming; | 50 | ovrFrameTiming OculusManager::_hmdFrameTiming; |
| @@ -66,12 +66,14 @@ void OculusManager::connect() { · 15 unmodified lines | |||
| 66 | UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); | 66 | UserActivityLogger::getInstance().connectedDevice("hmd", "oculus"); |
| 67 | } | 67 | } |
| 68 | _isConnected = true; | 68 | _isConnected = true; |
| 69 | 69 | #if defined(__APPLE__) || defined(_WIN32) | |
| 70 | _eyeFov[0] = _ovrHmd->DefaultEyeFov[0]; | ||
| 71 | _eyeFov[1] = _ovrHmd->DefaultEyeFov[1]; | ||
| 72 | #else | ||
| 70 | ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc); | 73 | ovrHmd_GetDesc(_ovrHmd, &_ovrHmdDesc); |
| 71 | |||
| 72 | _eyeFov[0] = _ovrHmdDesc.DefaultEyeFov[0]; | 74 | _eyeFov[0] = _ovrHmdDesc.DefaultEyeFov[0]; |
| 73 | _eyeFov[1] = _ovrHmdDesc.DefaultEyeFov[1]; | 75 | _eyeFov[1] = _ovrHmdDesc.DefaultEyeFov[1]; |
| 74 | 76 | #endif | |
| 75 | //Get texture size | 77 | //Get texture size |
| 76 | ovrSizei recommendedTex0Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, | 78 | ovrSizei recommendedTex0Size = ovrHmd_GetFovTextureSize(_ovrHmd, ovrEye_Left, |
| 77 | _eyeFov[0], 1.0f); | 79 | _eyeFov[0], 1.0f); |
| @@ -86,11 +88,21 @@ void OculusManager::connect() { · 8 unmodified lines | |||
| 86 | _eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]); | 88 | _eyeRenderDesc[0] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Left, _eyeFov[0]); |
| 87 | _eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]); | 89 | _eyeRenderDesc[1] = ovrHmd_GetRenderDesc(_ovrHmd, ovrEye_Right, _eyeFov[1]); |
| 88 | 90 | ||
| 91 | #if defined(__APPLE__) || defined(_WIN32) | ||
| 92 | ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence); | ||
| 93 | #else | ||
| 89 | ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_LatencyTest); | 94 | ovrHmd_SetEnabledCaps(_ovrHmd, ovrHmdCap_LowPersistence | ovrHmdCap_LatencyTest); |
| 95 | #endif | ||
| 90 | 96 | ||
| 97 | #if defined(__APPLE__) || defined(_WIN32) | ||
| 98 | ovrHmd_ConfigureTracking(_ovrHmd, ovrTrackingCap_Orientation | ovrTrackingCap_Position | | ||
| 99 | ovrTrackingCap_MagYawCorrection, | ||
| 100 | ovrTrackingCap_Orientation); | ||
| 101 | #else | ||
| 91 | ovrHmd_StartSensor(_ovrHmd, ovrSensorCap_Orientation | ovrSensorCap_YawCorrection | | 102 | ovrHmd_StartSensor(_ovrHmd, ovrSensorCap_Orientation | ovrSensorCap_YawCorrection | |
| 92 | ovrSensorCap_Position, | 103 | ovrSensorCap_Position, |
| 93 | ovrSensorCap_Orientation); | 104 | ovrSensorCap_Orientation); |
| 105 | #endif | ||
| 94 | 106 | ||
| 95 | if (!_camera) { | 107 | if (!_camera) { |
| 96 | _camera = new Camera; | 108 | _camera = new Camera; |
| @@ -123,6 +135,10 @@ void OculusManager::connect() { · 26 unmodified lines | |||
| 123 | 135 | ||
| 124 | } else { | 136 | } else { |
| 125 | _isConnected = false; | 137 | _isConnected = false; |
| 138 | |||
| 139 | // we're definitely not in "VR mode" so tell the menu that | ||
| 140 | Menu::getInstance()->getActionForOption(MenuOption::EnableVRMode)->setChecked(false); | ||
| 141 | |||
| 126 | ovrHmd_Destroy(_ovrHmd); | 142 | ovrHmd_Destroy(_ovrHmd); |
| 127 | ovr_Shutdown(); | 143 | ovr_Shutdown(); |
| 128 | } | 144 | } |
| @@ -183,6 +199,16 @@ void OculusManager::generateDistortionMesh() { · 54 unmodified lines | |||
| 183 | DistortionVertex* v = pVBVerts; | 199 | DistortionVertex* v = pVBVerts; |
| 184 | ovrDistortionVertex* ov = meshData.pVertexData; | 200 | ovrDistortionVertex* ov = meshData.pVertexData; |
| 185 | for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) { | 201 | for (unsigned int vertNum = 0; vertNum < meshData.VertexCount; vertNum++) { |
| 202 | #if defined(__APPLE__) || defined(_WIN32) | ||
| 203 | v->pos.x = ov->ScreenPosNDC.x; | ||
| 204 | v->pos.y = ov->ScreenPosNDC.y; | ||
| 205 | v->texR.x = ov->TanEyeAnglesR.x; | ||
| 206 | v->texR.y = ov->TanEyeAnglesR.y; | ||
| 207 | v->texG.x = ov->TanEyeAnglesG.x; | ||
| 208 | v->texG.y = ov->TanEyeAnglesG.y; | ||
| 209 | v->texB.x = ov->TanEyeAnglesB.x; | ||
| 210 | v->texB.y = ov->TanEyeAnglesB.y; | ||
| 211 | #else | ||
| 186 | v->pos.x = ov->Pos.x; | 212 | v->pos.x = ov->Pos.x; |
| 187 | v->pos.y = ov->Pos.y; | 213 | v->pos.y = ov->Pos.y; |
| 188 | v->texR.x = ov->TexR.x; | 214 | v->texR.x = ov->TexR.x; |
| @@ -191,6 +217,7 @@ void OculusManager::generateDistortionMesh() { · 2 unmodified lines | |||
| 191 | v->texG.y = ov->TexG.y; | 217 | v->texG.y = ov->TexG.y; |
| 192 | v->texB.x = ov->TexB.x; | 218 | v->texB.x = ov->TexB.x; |
| 193 | v->texB.y = ov->TexB.y; | 219 | v->texB.y = ov->TexB.y; |
| 220 | #endif | ||
| 194 | v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f); | 221 | v->color.r = v->color.g = v->color.b = (GLubyte)(ov->VignetteFactor * 255.99f); |
| 195 | v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f); | 222 | v->color.a = (GLubyte)(ov->TimeWarpFactor * 255.99f); |
| 196 | v++; | 223 | v++; |
| @@ -291,12 +318,23 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p · 94 unmodified lines | |||
| 291 | glPushMatrix(); | 318 | glPushMatrix(); |
| 292 | 319 | ||
| 293 | glm::quat orientation; | 320 | glm::quat orientation; |
| 294 | 321 | glm::vec3 trackerPosition; | |
| 322 | |||
| 323 | #if defined(__APPLE__) || defined(_WIN32) | ||
| 324 | ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); | ||
| 325 | ovrVector3f ovrHeadPosition = ts.HeadPose.ThePose.Position; | ||
| 326 | |||
| 327 | trackerPosition = glm::vec3(ovrHeadPosition.x, ovrHeadPosition.y, ovrHeadPosition.z); | ||
| 328 | trackerPosition = bodyOrientation * trackerPosition; | ||
| 329 | #endif | ||
| 330 | |||
| 295 | //Render each eye into an fbo | 331 | //Render each eye into an fbo |
| 296 | for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { | 332 | for (int eyeIndex = 0; eyeIndex < ovrEye_Count; eyeIndex++) { |
| 297 | 333 | #if defined(__APPLE__) || defined(_WIN32) | |
| 334 | ovrEyeType eye = _ovrHmd->EyeRenderOrder[eyeIndex]; | ||
| 335 | #else | ||
| 298 | ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex]; | 336 | ovrEyeType eye = _ovrHmdDesc.EyeRenderOrder[eyeIndex]; |
| 299 | 337 | #endif | |
| 300 | //Set the camera rotation for this eye | 338 | //Set the camera rotation for this eye |
| 301 | eyeRenderPose[eye] = ovrHmd_GetEyePose(_ovrHmd, eye); | 339 | eyeRenderPose[eye] = ovrHmd_GetEyePose(_ovrHmd, eye); |
| 302 | orientation.x = eyeRenderPose[eye].Orientation.x; | 340 | orientation.x = eyeRenderPose[eye].Orientation.x; |
| @@ -305,7 +343,8 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p · 2 unmodified lines | |||
| 305 | orientation.w = eyeRenderPose[eye].Orientation.w; | 343 | orientation.w = eyeRenderPose[eye].Orientation.w; |
| 306 | 344 | ||
| 307 | _camera->setTargetRotation(bodyOrientation * orientation); | 345 | _camera->setTargetRotation(bodyOrientation * orientation); |
| 308 | _camera->setTargetPosition(position); | 346 | _camera->setTargetPosition(position + trackerPosition); |
| 347 | |||
| 309 | _camera->update(1.0f / Application::getInstance()->getFps()); | 348 | _camera->update(1.0f / Application::getInstance()->getFps()); |
| 310 | 349 | ||
| 311 | Matrix4f proj = ovrMatrix4f_Projection(_eyeRenderDesc[eye].Fov, whichCamera.getNearClip(), whichCamera.getFarClip(), true); | 350 | Matrix4f proj = ovrMatrix4f_Projection(_eyeRenderDesc[eye].Fov, whichCamera.getNearClip(), whichCamera.getFarClip(), true); |
| @@ -425,19 +464,32 @@ void OculusManager::renderDistortionMesh(ovrPosef eyeRenderPose[ovrEye_Count]) { · 113 unmodified lines | |||
| 425 | //Tries to reconnect to the sensors | 464 | //Tries to reconnect to the sensors |
| 426 | void OculusManager::reset() { | 465 | void OculusManager::reset() { |
| 427 | #ifdef HAVE_LIBOVR | 466 | #ifdef HAVE_LIBOVR |
| 428 | disconnect(); | 467 | if (_isConnected) { |
| 429 | connect(); | 468 | ovrHmd_RecenterPose(_ovrHmd); |
| 469 | } | ||
| 430 | #endif | 470 | #endif |
| 431 | } | 471 | } |
| 432 | 472 | ||
| 433 | //Gets the current predicted angles from the oculus sensors | 473 | //Gets the current predicted angles from the oculus sensors |
| 434 | void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { | 474 | void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { |
| 435 | #ifdef HAVE_LIBOVR | 475 | #ifdef HAVE_LIBOVR |
| 476 | #if defined(__APPLE__) || defined(_WIN32) | ||
| 477 | ovrTrackingState ts = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); | ||
| 478 | #else | ||
| 436 | ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds); | 479 | ovrSensorState ss = ovrHmd_GetSensorState(_ovrHmd, _hmdFrameTiming.ScanoutMidpointSeconds); |
| 437 | 480 | #endif | |
| 481 | #if defined(__APPLE__) || defined(_WIN32) | ||
| 482 | if (ts.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { | ||
| 483 | #else | ||
| 438 | if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { | 484 | if (ss.StatusFlags & (ovrStatus_OrientationTracked | ovrStatus_PositionTracked)) { |
| 439 | ovrPosef pose = ss.Predicted.Pose; | 485 | #endif |
| 440 | Quatf orientation = Quatf(pose.Orientation); | 486 | |
| 487 | #if defined(__APPLE__) || defined(_WIN32) | ||
| 488 | ovrPosef headPose = ts.HeadPose.ThePose; | ||
| 489 | #else | ||
| 490 | ovrPosef headPose = ss.Predicted.Pose; | ||
| 491 | #endif | ||
| 492 | Quatf orientation = Quatf(headPose.Orientation); | ||
| 441 | orientation.GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll); | 493 | orientation.GetEulerAngles<Axis_Y, Axis_X, Axis_Z, Rotate_CCW, Handed_R>(&yaw, &pitch, &roll); |
| 442 | } else { | 494 | } else { |
| 443 | yaw = 0.0f; | 495 | yaw = 0.0f; |
| @@ -450,6 +502,18 @@ void OculusManager::getEulerAngles(float& yaw, float& pitch, float& roll) { · 6 unmodified lines | |||
| 450 | roll = 0.0f; | 502 | roll = 0.0f; |
| 451 | #endif | 503 | #endif |
| 452 | } | 504 | } |
| 505 | |||
| 506 | glm::vec3 OculusManager::getRelativePosition() { | ||
| 507 | #if (defined(__APPLE__) || defined(_WIN32)) && HAVE_LIBOVR | ||
| 508 | ovrTrackingState trackingState = ovrHmd_GetTrackingState(_ovrHmd, ovr_GetTimeInSeconds()); | ||
| 509 | ovrVector3f headPosition = trackingState.HeadPose.ThePose.Position; | ||
| 510 | |||
| 511 | return glm::vec3(headPosition.x, headPosition.y, headPosition.z); | ||
| 512 | #else | ||
| 513 | // no positional tracking in Linux yet | ||
| 514 | return glm::vec3(0.0f, 0.0f, 0.0f); | ||
| 515 | #endif | ||
| 516 | } | ||
| 453 | 517 | ||
| 454 | //Used to set the size of the glow framebuffers | 518 | //Used to set the size of the glow framebuffers |
| 455 | QSize OculusManager::getRenderTargetSize() { | 519 | QSize OculusManager::getRenderTargetSize() { |
| @@ -40,6 +40,7 @@ public: · 39 unmodified lines | |||
| 40 | /// param \pitch[out] pitch in radians | 40 | /// param \pitch[out] pitch in radians |
| 41 | /// param \roll[out] roll in radians | 41 | /// param \roll[out] roll in radians |
| 42 | static void getEulerAngles(float& yaw, float& pitch, float& roll); | 42 | static void getEulerAngles(float& yaw, float& pitch, float& roll); |
| 43 | static glm::vec3 getRelativePosition(); | ||
| 43 | static QSize getRenderTargetSize(); | 44 | static QSize getRenderTargetSize(); |
| 44 | 45 | ||
| 45 | private: | 46 | private: |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | |||
| 19 | #include "UserActivityLogger.h" | 19 | #include "UserActivityLogger.h" |
| 20 | 20 | ||
| 21 | #ifdef HAVE_SIXENSE | 21 | #ifdef HAVE_SIXENSE |
| 22 | |||
| 22 | const int CALIBRATION_STATE_IDLE = 0; | 23 | const int CALIBRATION_STATE_IDLE = 0; |
| 23 | const int CALIBRATION_STATE_X = 1; | 24 | const int CALIBRATION_STATE_X = 1; |
| 24 | const int CALIBRATION_STATE_Y = 2; | 25 | const int CALIBRATION_STATE_Y = 2; |
| @@ -41,8 +42,9 @@ SixenseManager::SixenseManager() { · 16 unmodified lines | |||
| 41 | // By default we assume the _neckBase (in orb frame) is as high above the orb | 42 | // By default we assume the _neckBase (in orb frame) is as high above the orb |
| 42 | // as the "torso" is below it. | 43 | // as the "torso" is below it. |
| 43 | _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); | 44 | _neckBase = glm::vec3(NECK_X, -NECK_Y, NECK_Z); |
| 44 | 45 | ||
| 45 | sixenseInit(); | 46 | sixenseInit(); |
| 47 | |||
| 46 | #endif | 48 | #endif |
| 47 | _hydrasConnected = false; | 49 | _hydrasConnected = false; |
| 48 | _triggerPressed[0] = false; | 50 | _triggerPressed[0] = false; |
| @@ -71,7 +71,7 @@ private: · 70 unmodified lines | |||
| 71 | glm::vec3 _reachUp; | 71 | glm::vec3 _reachUp; |
| 72 | glm::vec3 _reachForward; | 72 | glm::vec3 _reachForward; |
| 73 | float _lastDistance; | 73 | float _lastDistance; |
| 74 | 74 | ||
| 75 | #endif | 75 | #endif |
| 76 | bool _hydrasConnected; | 76 | bool _hydrasConnected; |
| 77 | quint64 _lastMovement; | 77 | quint64 _lastMovement; |
| @@ -16,6 +16,7 @@ · 15 unmodified lines | |||
| 16 | #include <glm/gtx/quaternion.hpp> | 16 | #include <glm/gtx/quaternion.hpp> |
| 17 | #include <glm/gtx/transform.hpp> | 17 | #include <glm/gtx/transform.hpp> |
| 18 | 18 | ||
| 19 | #include <GLMHelpers.h> | ||
| 19 | #include <FBXReader.h> | 20 | #include <FBXReader.h> |
| 20 | 21 | ||
| 21 | class AngularConstraint; | 22 | class AngularConstraint; |
| @@ -1449,9 +1449,11 @@ void Model::renderMeshes(float alpha, RenderMode mode, bool translucent, bool re · 1448 unmodified lines | |||
| 1449 | if (cascadedShadows) { | 1449 | if (cascadedShadows) { |
| 1450 | activeProgram->setUniform(activeLocations->shadowDistances, Application::getInstance()->getShadowDistances()); | 1450 | activeProgram->setUniform(activeLocations->shadowDistances, Application::getInstance()->getShadowDistances()); |
| 1451 | } | 1451 | } |
| 1452 | activeProgram->setUniformValueArray(activeLocations->localLightDirections, | 1452 | if (mode != SHADOW_RENDER_MODE) { |
| 1453 | (const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4); | 1453 | activeProgram->setUniformValueArray(activeLocations->localLightDirections, |
| 1454 | 1454 | (const GLfloat*)_localLightDirections, MAX_LOCAL_LIGHTS, 4); | |
| 1455 | } | ||
| 1456 | |||
| 1455 | if (mesh.blendshapes.isEmpty()) { | 1457 | if (mesh.blendshapes.isEmpty()) { |
| 1456 | if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { | 1458 | if (!(mesh.tangents.isEmpty() || mode == SHADOW_RENDER_MODE)) { |
| 1457 | activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); | 1459 | activeProgram->setAttributeBuffer(activeLocations->tangent, GL_FLOAT, vertexCount * 2 * sizeof(glm::vec3), 3); |
| @@ -164,6 +164,9 @@ public: · 163 unmodified lines | |||
| 164 | const QVector<LocalLight>& getLocalLights() const { return _localLights; } | 164 | const QVector<LocalLight>& getLocalLights() const { return _localLights; } |
| 165 | 165 | ||
| 166 | void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; } | 166 | void setShowTrueJointTransforms(bool show) { _showTrueJointTransforms = show; } |
| 167 | |||
| 168 | QVector<JointState>& getJointStates() { return _jointStates; } | ||
| 169 | const QVector<JointState>& getJointStates() const { return _jointStates; } | ||
| 167 | 170 | ||
| 168 | protected: | 171 | protected: |
| 169 | QSharedPointer<NetworkGeometry> _geometry; | 172 | QSharedPointer<NetworkGeometry> _geometry; |
| @@ -87,6 +87,37 @@ bool ClipboardScriptingInterface::importVoxels() { · 86 unmodified lines | |||
| 87 | return Application::getInstance()->getImportSucceded(); | 87 | return Application::getInstance()->getImportSucceded(); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | bool ClipboardScriptingInterface::importVoxels(const QString& filename) { | ||
| 91 | qDebug() << "Importing ... "; | ||
| 92 | |||
| 93 | VoxelImporter* importer = Application::getInstance()->getVoxelImporter(); | ||
| 94 | |||
| 95 | if (!importer->validImportFile(filename)) { | ||
| 96 | return false; | ||
| 97 | } | ||
| 98 | |||
| 99 | QEventLoop loop; | ||
| 100 | connect(importer, SIGNAL(importDone()), &loop, SLOT(quit())); | ||
| 101 | importer->import(filename); | ||
| 102 | loop.exec(); | ||
| 103 | |||
| 104 | return true; | ||
| 105 | } | ||
| 106 | |||
| 107 | bool ClipboardScriptingInterface::importVoxels(const QString& filename, float x, float y, float z, float s) { | ||
| 108 | bool success = importVoxels(filename); | ||
| 109 | |||
| 110 | if (success) { | ||
| 111 | pasteVoxel(x, y, z, s); | ||
| 112 | } | ||
| 113 | |||
| 114 | return success; | ||
| 115 | } | ||
| 116 | |||
| 117 | bool ClipboardScriptingInterface::importVoxels(const QString& filename, const VoxelDetail& destinationVoxel) { | ||
| 118 | return importVoxels(filename, destinationVoxel.x, destinationVoxel.y, destinationVoxel.z, destinationVoxel.s); | ||
| 119 | } | ||
| 120 | |||
| 90 | void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) { | 121 | void ClipboardScriptingInterface::nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec) { |
| 91 | nudgeVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s, nudgeVec); | 122 | nudgeVoxel(sourceVoxel.x, sourceVoxel.y, sourceVoxel.z, sourceVoxel.s, nudgeVec); |
| 92 | } | 123 | } |
| @@ -39,6 +39,9 @@ public slots: · 38 unmodified lines | |||
| 39 | void exportVoxel(float x, float y, float z, float s); | 39 | void exportVoxel(float x, float y, float z, float s); |
| 40 | 40 | ||
| 41 | bool importVoxels(); | 41 | bool importVoxels(); |
| 42 | bool importVoxels(const QString& filename); | ||
| 43 | bool importVoxels(const QString& filename, float x, float y, float z, float s); | ||
| 44 | bool importVoxels(const QString& filename, const VoxelDetail& destinationVoxel); | ||
| 42 | 45 | ||
| 43 | void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); | 46 | void nudgeVoxel(const VoxelDetail& sourceVoxel, const glm::vec3& nudgeVec); |
| 44 | void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec); | 47 | void nudgeVoxel(float x, float y, float z, float s, const glm::vec3& nudgeVec); |
| @@ -57,6 +57,9 @@ ApplicationOverlay::~ApplicationOverlay() { · 56 unmodified lines | |||
| 57 | const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; | 57 | const float WHITE_TEXT[] = { 0.93f, 0.93f, 0.93f }; |
| 58 | const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; | 58 | const float RETICLE_COLOR[] = { 0.0f, 198.0f / 255.0f, 244.0f / 255.0f }; |
| 59 | 59 | ||
| 60 | const float CONNECTION_STATUS_BORDER_COLOR[] = { 1.0f, 0.0f, 0.0f }; | ||
| 61 | const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; | ||
| 62 | |||
| 60 | // Renders the overlays either to a texture or to the screen | 63 | // Renders the overlays either to a texture or to the screen |
| 61 | void ApplicationOverlay::renderOverlay(bool renderToTexture) { | 64 | void ApplicationOverlay::renderOverlay(bool renderToTexture) { |
| 62 | 65 | ||
| @@ -115,6 +118,8 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { · 52 unmodified lines | |||
| 115 | 118 | ||
| 116 | renderPointers(); | 119 | renderPointers(); |
| 117 | 120 | ||
| 121 | renderDomainConnectionStatusBorder(); | ||
| 122 | |||
| 118 | glPopMatrix(); | 123 | glPopMatrix(); |
| 119 | 124 | ||
| 120 | 125 | ||
| @@ -1234,6 +1239,30 @@ void ApplicationOverlay::renderTexturedHemisphere() { · 1113 unmodified lines | |||
| 1234 | 1239 | ||
| 1235 | } | 1240 | } |
| 1236 | 1241 | ||
| 1242 | void ApplicationOverlay::renderDomainConnectionStatusBorder() { | ||
| 1243 | NodeList* nodeList = NodeList::getInstance(); | ||
| 1244 | |||
| 1245 | if (nodeList && !nodeList->getDomainHandler().isConnected()) { | ||
| 1246 | QGLWidget* glWidget = Application::getInstance()->getGLWidget(); | ||
| 1247 | int right = glWidget->width(); | ||
| 1248 | int bottom = glWidget->height(); | ||
| 1249 | |||
| 1250 | glColor3f(CONNECTION_STATUS_BORDER_COLOR[0], | ||
| 1251 | CONNECTION_STATUS_BORDER_COLOR[1], | ||
| 1252 | CONNECTION_STATUS_BORDER_COLOR[2]); | ||
| 1253 | glLineWidth(CONNECTION_STATUS_BORDER_LINE_WIDTH); | ||
| 1254 | |||
| 1255 | glBegin(GL_LINE_LOOP); | ||
| 1256 | |||
| 1257 | glVertex2i(0, 0); | ||
| 1258 | glVertex2i(0, bottom); | ||
| 1259 | glVertex2i(right, bottom); | ||
| 1260 | glVertex2i(right, 0); | ||
| 1261 | |||
| 1262 | glEnd(); | ||
| 1263 | } | ||
| 1264 | } | ||
| 1265 | |||
| 1237 | QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() { | 1266 | QOpenGLFramebufferObject* ApplicationOverlay::getFramebufferObject() { |
| 1238 | QSize size = Application::getInstance()->getGLWidget()->size(); | 1267 | QSize size = Application::getInstance()->getGLWidget()->size(); |
| 1239 | if (!_framebufferObject || _framebufferObject->size() != size) { | 1268 | if (!_framebufferObject || _framebufferObject->size() != size) { |
| @@ -56,6 +56,7 @@ private: · 55 unmodified lines | |||
| 56 | void renderAudioMeter(); | 56 | void renderAudioMeter(); |
| 57 | void renderStatsAndLogs(); | 57 | void renderStatsAndLogs(); |
| 58 | void renderTexturedHemisphere(); | 58 | void renderTexturedHemisphere(); |
| 59 | void renderDomainConnectionStatusBorder(); | ||
| 59 | 60 | ||
| 60 | QOpenGLFramebufferObject* _framebufferObject; | 61 | QOpenGLFramebufferObject* _framebufferObject; |
| 61 | float _trailingAudioLoudness; | 62 | float _trailingAudioLoudness; |
| @@ -76,4 +77,4 @@ private: · 14 unmodified lines | |||
| 76 | GLuint _crosshairTexture; | 77 | GLuint _crosshairTexture; |
| 77 | }; | 78 | }; |
| 78 | 79 | ||
| 79 | #endif // hifi_ApplicationOverlay_h | 80 | #endif // hifi_ApplicationOverlay_h |
| @@ -118,6 +118,8 @@ MetavoxelEditor::MetavoxelEditor() : · 117 unmodified lines | |||
| 118 | addTool(new SetSpannerTool(this)); | 118 | addTool(new SetSpannerTool(this)); |
| 119 | addTool(new ImportHeightfieldTool(this)); | 119 | addTool(new ImportHeightfieldTool(this)); |
| 120 | addTool(new EraseHeightfieldTool(this)); | 120 | addTool(new EraseHeightfieldTool(this)); |
| 121 | addTool(new HeightfieldHeightBrushTool(this)); | ||
| 122 | addTool(new HeightfieldColorBrushTool(this)); | ||
| 121 | 123 | ||
| 122 | updateAttributes(); | 124 | updateAttributes(); |
| 123 | 125 | ||
| @@ -954,11 +956,11 @@ void ImportHeightfieldTool::apply() { · 830 unmodified lines | |||
| 954 | HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(bufferData.data()); | 956 | HeightfieldBuffer* buffer = static_cast<HeightfieldBuffer*>(bufferData.data()); |
| 955 | MetavoxelData data; | 957 | MetavoxelData data; |
| 956 | data.setSize(scale); | 958 | data.setSize(scale); |
| 957 | HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getHeight())); | 959 | HeightfieldDataPointer heightPointer(new HeightfieldData(buffer->getUnextendedHeight())); |
| 958 | data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue( | 960 | data.setRoot(AttributeRegistry::getInstance()->getHeightfieldAttribute(), new MetavoxelNode(AttributeValue( |
| 959 | AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer)))); | 961 | AttributeRegistry::getInstance()->getHeightfieldAttribute(), encodeInline(heightPointer)))); |
| 960 | if (!buffer->getColor().isEmpty()) { | 962 | if (!buffer->getColor().isEmpty()) { |
| 961 | HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getColor())); | 963 | HeightfieldDataPointer colorPointer(new HeightfieldData(buffer->getUnextendedColor())); |
| 962 | data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue( | 964 | data.setRoot(AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), new MetavoxelNode(AttributeValue( |
| 963 | AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer)))); | 965 | AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), encodeInline(colorPointer)))); |
| 964 | } | 966 | } |
| @@ -1001,34 +1003,38 @@ void ImportHeightfieldTool::updatePreview() { · 36 unmodified lines | |||
| 1001 | if (_heightImage.width() > 0 && _heightImage.height() > 0) { | 1003 | if (_heightImage.width() > 0 && _heightImage.height() > 0) { |
| 1002 | float z = 0.0f; | 1004 | float z = 0.0f; |
| 1003 | int blockSize = pow(2.0, _blockSize->value()); | 1005 | int blockSize = pow(2.0, _blockSize->value()); |
| 1004 | int blockAdvancement = blockSize - 1; | 1006 | int heightSize = blockSize + HeightfieldBuffer::HEIGHT_EXTENSION; |
| 1005 | for (int i = 0; i < _heightImage.height(); i += blockAdvancement, z++) { | 1007 | int colorSize = blockSize + HeightfieldBuffer::SHARED_EDGE; |
| 1008 | for (int i = 0; i < _heightImage.height(); i += blockSize, z++) { | ||
| 1006 | float x = 0.0f; | 1009 | float x = 0.0f; |
| 1007 | for (int j = 0; j < _heightImage.width(); j += blockAdvancement, x++) { | 1010 | for (int j = 0; j < _heightImage.width(); j += blockSize, x++) { |
| 1008 | QByteArray height(blockSize * blockSize, 0); | 1011 | QByteArray height(heightSize * heightSize, 0); |
| 1009 | int rows = qMin(blockSize, _heightImage.height() - i); | 1012 | int extendedI = qMax(i - HeightfieldBuffer::HEIGHT_BORDER, 0); |
| 1010 | int columns = qMin(blockSize, _heightImage.width() - j); | 1013 | int extendedJ = qMax(j - HeightfieldBuffer::HEIGHT_BORDER, 0); |
| 1011 | const int BYTES_PER_COLOR = 3; | 1014 | int offsetY = extendedI - i + HeightfieldBuffer::HEIGHT_BORDER; |
| 1015 | int offsetX = extendedJ - j + HeightfieldBuffer::HEIGHT_BORDER; | ||
| 1016 | int rows = qMin(heightSize - offsetY, _heightImage.height() - extendedI); | ||
| 1017 | int columns = qMin(heightSize - offsetX, _heightImage.width() - extendedJ); | ||
| 1012 | for (int y = 0; y < rows; y++) { | 1018 | for (int y = 0; y < rows; y++) { |
| 1013 | uchar* src = _heightImage.scanLine(i + y) + j * BYTES_PER_COLOR; | 1019 | uchar* src = _heightImage.scanLine(extendedI + y) + extendedJ * HeightfieldData::COLOR_BYTES; |
| 1014 | char* dest = height.data() + y * blockSize; | 1020 | char* dest = height.data() + (y + offsetY) * heightSize + offsetX; |
| 1015 | for (int x = 0; x < columns; x++) { | 1021 | for (int x = 0; x < columns; x++) { |
| 1016 | *dest++ = *src; | 1022 | *dest++ = *src; |
| 1017 | src += BYTES_PER_COLOR; | 1023 | src += HeightfieldData::COLOR_BYTES; |
| 1018 | } | 1024 | } |
| 1019 | } | 1025 | } |
| 1020 | |||
| 1021 | QByteArray color; | 1026 | QByteArray color; |
| 1022 | if (!_colorImage.isNull()) { | 1027 | if (!_colorImage.isNull()) { |
| 1023 | color = QByteArray(blockSize * blockSize * BYTES_PER_COLOR, 0); | 1028 | color = QByteArray(colorSize * colorSize * HeightfieldData::COLOR_BYTES, 0); |
| 1024 | rows = qMax(0, qMin(blockSize, _colorImage.height() - i)); | 1029 | rows = qMax(0, qMin(colorSize, _colorImage.height() - i)); |
| 1025 | columns = qMax(0, qMin(blockSize, _colorImage.width() - j)); | 1030 | columns = qMax(0, qMin(colorSize, _colorImage.width() - j)); |
| 1026 | for (int y = 0; y < rows; y++) { | 1031 | for (int y = 0; y < rows; y++) { |
| 1027 | memcpy(color.data() + y * blockSize * BYTES_PER_COLOR, | 1032 | memcpy(color.data() + y * colorSize * HeightfieldData::COLOR_BYTES, |
| 1028 | _colorImage.scanLine(i + y) + j * BYTES_PER_COLOR, columns * BYTES_PER_COLOR); | 1033 | _colorImage.scanLine(i + y) + j * HeightfieldData::COLOR_BYTES, |
| 1034 | columns * HeightfieldData::COLOR_BYTES); | ||
| 1029 | } | 1035 | } |
| 1030 | } | 1036 | } |
| 1031 | buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color, false))); | 1037 | buffers.append(BufferDataPointer(new HeightfieldBuffer(glm::vec3(x, 0.0f, z), 1.0f, height, color))); |
| 1032 | } | 1038 | } |
| 1033 | } | 1039 | } |
| 1034 | } | 1040 | } |
| @@ -1080,3 +1086,72 @@ void EraseHeightfieldTool::apply() { · 45 unmodified lines | |||
| 1080 | message.edit = QVariant::fromValue(edit); | 1086 | message.edit = QVariant::fromValue(edit); |
| 1081 | Application::getInstance()->getMetavoxels()->applyEdit(message, true); | 1087 | Application::getInstance()->getMetavoxels()->applyEdit(message, true); |
| 1082 | } | 1088 | } |
| 1089 | |||
| 1090 | HeightfieldBrushTool::HeightfieldBrushTool(MetavoxelEditor* editor, const QString& name) : | ||
| 1091 | MetavoxelTool(editor, name, false) { | ||
| 1092 | |||
| 1093 | QWidget* widget = new QWidget(); | ||
| 1094 | widget->setLayout(_form = new QFormLayout()); | ||
| 1095 | layout()->addWidget(widget); | ||
| 1096 | |||
| 1097 | _form->addRow("Radius:", _radius = new QDoubleSpinBox()); | ||
| 1098 | _radius->setSingleStep(0.01); | ||
| 1099 | _radius->setMaximum(FLT_MAX); | ||
| 1100 | _radius->setValue(1.0); | ||
| 1101 | } | ||
| 1102 | |||
| 1103 | void HeightfieldBrushTool::render() { | ||
| 1104 | if (Application::getInstance()->isMouseHidden()) { | ||
| 1105 | return; | ||
| 1106 | } | ||
| 1107 | |||
| 1108 | // find the intersection with the heightfield | ||
| 1109 | glm::vec3 origin = Application::getInstance()->getMouseRayOrigin(); | ||
| 1110 | glm::vec3 direction = Application::getInstance()->getMouseRayDirection(); | ||
| 1111 | |||
| 1112 | float distance; | ||
| 1113 | if (!Application::getInstance()->getMetavoxels()->findFirstRayHeightfieldIntersection(origin, direction, distance)) { | ||
| 1114 | return; | ||
| 1115 | } | ||
| 1116 | Application::getInstance()->getMetavoxels()->renderHeightfieldCursor( | ||
| 1117 | _position = origin + distance * direction, _radius->value()); | ||
| 1118 | } | ||
| 1119 | |||
| 1120 | bool HeightfieldBrushTool::eventFilter(QObject* watched, QEvent* event) { | ||
| 1121 | if (event->type() == QEvent::Wheel) { | ||
| 1122 | float angle = static_cast<QWheelEvent*>(event)->angleDelta().y(); | ||
| 1123 | const float ANGLE_SCALE = 1.0f / 1000.0f; | ||
| 1124 | _radius->setValue(_radius->value() * glm::pow(2.0f, angle * ANGLE_SCALE)); | ||
| 1125 | return true; | ||
| 1126 | |||
| 1127 | } else if (event->type() == QEvent::MouseButtonPress) { | ||
| 1128 | MetavoxelEditMessage message = { createEdit(static_cast<QMouseEvent*>(event)->button() == Qt::RightButton) }; | ||
| 1129 | Application::getInstance()->getMetavoxels()->applyEdit(message, true); | ||
| 1130 | return true; | ||
| 1131 | } | ||
| 1132 | return false; | ||
| 1133 | } | ||
| 1134 | |||
| 1135 | HeightfieldHeightBrushTool::HeightfieldHeightBrushTool(MetavoxelEditor* editor) : | ||
| 1136 | HeightfieldBrushTool(editor, "Height Brush") { | ||
| 1137 | |||
| 1138 | _form->addRow("Height:", _height = new QDoubleSpinBox()); | ||
| 1139 | _height->setMinimum(-FLT_MAX); | ||
| 1140 | _height->setMaximum(FLT_MAX); | ||
| 1141 | _height->setValue(1.0); | ||
| 1142 | } | ||
| 1143 | |||
| 1144 | QVariant HeightfieldHeightBrushTool::createEdit(bool alternate) { | ||
| 1145 | return QVariant::fromValue(PaintHeightfieldHeightEdit(_position, _radius->value(), | ||
| 1146 | alternate ? -_height->value() : _height->value())); | ||
| 1147 | } | ||
| 1148 | |||
| 1149 | HeightfieldColorBrushTool::HeightfieldColorBrushTool(MetavoxelEditor* editor) : | ||
| 1150 | HeightfieldBrushTool(editor, "Color Brush") { | ||
| 1151 | |||
| 1152 | _form->addRow("Color:", _color = new QColorEditor(this)); | ||
| 1153 | } | ||
| 1154 | |||
| 1155 | QVariant HeightfieldColorBrushTool::createEdit(bool alternate) { | ||
| 1156 | return QVariant::fromValue(PaintHeightfieldColorEdit(_position, _radius->value(), _color->getColor())); | ||
| 1157 | } | ||
| @@ -18,6 +18,7 @@ · 17 unmodified lines | |||
| 18 | #include "MetavoxelSystem.h" | 18 | #include "MetavoxelSystem.h" |
| 19 | #include "renderer/ProgramObject.h" | 19 | #include "renderer/ProgramObject.h" |
| 20 | 20 | ||
| 21 | class QColorEditor; | ||
| 21 | class QComboBox; | 22 | class QComboBox; |
| 22 | class QDoubleSpinBox; | 23 | class QDoubleSpinBox; |
| 23 | class QGroupBox; | 24 | class QGroupBox; |
| @@ -282,7 +283,7 @@ private: · 258 unmodified lines | |||
| 282 | HeightfieldPreview _preview; | 283 | HeightfieldPreview _preview; |
| 283 | }; | 284 | }; |
| 284 | 285 | ||
| 285 | // Allows clearing heighfield blocks. | 286 | /// Allows clearing heighfield blocks. |
| 286 | class EraseHeightfieldTool : public HeightfieldTool { | 287 | class EraseHeightfieldTool : public HeightfieldTool { |
| 287 | Q_OBJECT | 288 | Q_OBJECT |
| 288 | 289 | ||
| @@ -302,4 +303,60 @@ private: · 13 unmodified lines | |||
| 302 | QSpinBox* _length; | 303 | QSpinBox* _length; |
| 303 | }; | 304 | }; |
| 304 | 305 | ||
| 306 | /// Base class for tools that allow painting on heightfields. | ||
| 307 | class HeightfieldBrushTool : public MetavoxelTool { | ||
| 308 | Q_OBJECT | ||
| 309 | |||
| 310 | public: | ||
| 311 | |||
| 312 | HeightfieldBrushTool(MetavoxelEditor* editor, const QString& name); | ||
| 313 | |||
| 314 | virtual void render(); | ||
| 315 | |||
| 316 | virtual bool eventFilter(QObject* watched, QEvent* event); | ||
| 317 | |||
| 318 | protected: | ||
| 319 | |||
| 320 | virtual QVariant createEdit(bool alternate) = 0; | ||
| 321 | |||
| 322 | QFormLayout* _form; | ||
| 323 | QDoubleSpinBox* _radius; | ||
| 324 | |||
| 325 | glm::vec3 _position; | ||
| 326 | }; | ||
| 327 | |||
| 328 | /// Allows raising or lowering parts of the heightfield. | ||
| 329 | class HeightfieldHeightBrushTool : public HeightfieldBrushTool { | ||
| 330 | Q_OBJECT | ||
| 331 | |||
| 332 | public: | ||
| 333 | |||
| 334 | HeightfieldHeightBrushTool(MetavoxelEditor* editor); | ||
| 335 | |||
| 336 | protected: | ||
| 337 | |||
| 338 | virtual QVariant createEdit(bool alternate); | ||
| 339 | |||
| 340 | private: | ||
| 341 | |||
| 342 | QDoubleSpinBox* _height; | ||
| 343 | }; | ||
| 344 | |||
| 345 | /// Allows coloring parts of the heightfield. | ||
| 346 | class HeightfieldColorBrushTool : public HeightfieldBrushTool { | ||
| 347 | Q_OBJECT | ||
| 348 | |||
| 349 | public: | ||
| 350 | |||
| 351 | HeightfieldColorBrushTool(MetavoxelEditor* editor); | ||
| 352 | |||
| 353 | protected: | ||
| 354 | |||
| 355 | virtual QVariant createEdit(bool alternate); | ||
| 356 | |||
| 357 | private: | ||
| 358 | |||
| 359 | QColorEditor* _color; | ||
| 360 | }; | ||
| 361 | |||
| 305 | #endif // hifi_MetavoxelEditor_h | 362 | #endif // hifi_MetavoxelEditor_h |
| @@ -1,5 +1,5 @@ | |||
| 1 | // | 1 | // |
| 2 | // ImportDialog.cpp | 2 | // VoxelImportDialog.cpp |
| 3 | // interface/src/ui | 3 | // interface/src/ui |
| 4 | // | 4 | // |
| 5 | // Created by Clement Brisset on 8/12/13. | 5 | // Created by Clement Brisset on 8/12/13. |
| @@ -20,7 +20,11 @@ · 14 unmodified lines | |||
| 20 | 20 | ||
| 21 | #include "Application.h" | 21 | #include "Application.h" |
| 22 | 22 | ||
| 23 | #include "ImportDialog.h" | 23 | #include "VoxelImportDialog.h" |
| 24 | #include "voxels/VoxelImporter.h" | ||
| 25 | |||
| 26 | const QString SETTINGS_GROUP_NAME = "VoxelImport"; | ||
| 27 | const QString IMPORT_DIALOG_SETTINGS_KEY = "VoxelImportDialogSettings"; | ||
| 24 | 28 | ||
| 25 | const QString WINDOW_NAME = QObject::tr("Import Voxels"); | 29 | const QString WINDOW_NAME = QObject::tr("Import Voxels"); |
| 26 | const QString IMPORT_BUTTON_NAME = QObject::tr("Import Voxels"); | 30 | const QString IMPORT_BUTTON_NAME = QObject::tr("Import Voxels"); |
| @@ -97,12 +101,14 @@ QString HiFiIconProvider::type(const QFileInfo &info) const { · 70 unmodified lines | |||
| 97 | return QFileIconProvider::type(info); | 101 | return QFileIconProvider::type(info); |
| 98 | } | 102 | } |
| 99 | 103 | ||
| 100 | ImportDialog::ImportDialog(QWidget* parent) : | 104 | VoxelImportDialog::VoxelImportDialog(QWidget* parent) : |
| 101 | QFileDialog(parent, WINDOW_NAME, DOWNLOAD_LOCATION, NULL), | 105 | QFileDialog(parent, WINDOW_NAME, DOWNLOAD_LOCATION, NULL), |
| 102 | _progressBar(this), | ||
| 103 | _importButton(IMPORT_BUTTON_NAME, this), | ||
| 104 | _cancelButton(CANCEL_BUTTON_NAME, this), | 106 | _cancelButton(CANCEL_BUTTON_NAME, this), |
| 105 | _mode(importMode) { | 107 | _importButton(IMPORT_BUTTON_NAME, this), |
| 108 | _importer(Application::getInstance()->getVoxelImporter()), | ||
| 109 | _mode(importMode), | ||
| 110 | _progressBar(this), | ||
| 111 | _didImport(false) { | ||
| 106 | 112 | ||
| 107 | setOption(QFileDialog::DontUseNativeDialog, true); | 113 | setOption(QFileDialog::DontUseNativeDialog, true); |
| 108 | setFileMode(QFileDialog::ExistingFile); | 114 | setFileMode(QFileDialog::ExistingFile); |
| @@ -113,41 +119,54 @@ ImportDialog::ImportDialog(QWidget* parent) : · 4 unmodified lines | |||
| 113 | 119 | ||
| 114 | _progressBar.setRange(0, 100); | 120 | _progressBar.setRange(0, 100); |
| 115 | 121 | ||
| 116 | connect(&_importButton, SIGNAL(pressed()), SLOT(accept())); | 122 | connect(&_importButton, SIGNAL(pressed()), this, SLOT(accept())); |
| 117 | connect(&_cancelButton, SIGNAL(pressed()), SIGNAL(canceled())); | 123 | connect(&_cancelButton, SIGNAL(pressed()), this, SLOT(cancel())); |
| 118 | connect(this, SIGNAL(currentChanged(QString)), SLOT(saveCurrentFile(QString))); | 124 | connect(this, SIGNAL(currentChanged(QString)), SLOT(saveCurrentFile(QString))); |
| 119 | } | 125 | } |
| 120 | 126 | ||
| 121 | void ImportDialog::reset() { | 127 | void VoxelImportDialog::cancel() { |
| 128 | switch (getMode()) { | ||
| 129 | case importMode: | ||
| 130 | _importer->cancel(); | ||
| 131 | close(); | ||
| 132 | break; | ||
| 133 | default: | ||
| 134 | _importer->reset(); | ||
| 135 | setMode(importMode); | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | emit canceled(); | ||
| 139 | } | ||
| 140 | |||
| 141 | void VoxelImportDialog::saveSettings(QSettings* settings) { | ||
| 142 | settings->beginGroup(SETTINGS_GROUP_NAME); | ||
| 143 | settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, saveState()); | ||
| 144 | settings->endGroup(); | ||
| 145 | } | ||
| 146 | |||
| 147 | void VoxelImportDialog::loadSettings(QSettings* settings) { | ||
| 148 | settings->beginGroup(SETTINGS_GROUP_NAME); | ||
| 149 | restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray()); | ||
| 150 | settings->endGroup(); | ||
| 151 | } | ||
| 152 | |||
| 153 | bool VoxelImportDialog::prompt() { | ||
| 154 | reset(); | ||
| 155 | exec(); | ||
| 156 | return _didImport; | ||
| 157 | } | ||
| 158 | |||
| 159 | void VoxelImportDialog::reset() { | ||
| 122 | setMode(importMode); | 160 | setMode(importMode); |
| 123 | _progressBar.setValue(0); | 161 | _didImport = false; |
| 124 | } | 162 | } |
| 125 | 163 | ||
| 126 | void ImportDialog::setMode(dialogMode mode) { | 164 | void VoxelImportDialog::setMode(dialogMode mode) { |
| 165 | dialogMode previousMode = _mode; | ||
| 127 | _mode = mode; | 166 | _mode = mode; |
| 128 | 167 | ||
| 129 | switch (_mode) { | 168 | switch (_mode) { |
| 130 | case loadingMode: | ||
| 131 | _importButton.setEnabled(false); | ||
| 132 | _importButton.setText(LOADING_BUTTON_NAME); | ||
| 133 | findChild<QWidget*>("sidebar")->setEnabled(false); | ||
| 134 | findChild<QWidget*>("treeView")->setEnabled(false); | ||
| 135 | findChild<QWidget*>("backButton")->setEnabled(false); | ||
| 136 | findChild<QWidget*>("forwardButton")->setEnabled(false); | ||
| 137 | findChild<QWidget*>("toParentButton")->setEnabled(false); | ||
| 138 | break; | ||
| 139 | case placeMode: | ||
| 140 | _progressBar.setValue(100); | ||
| 141 | _importButton.setEnabled(true); | ||
| 142 | _importButton.setText(PLACE_BUTTON_NAME); | ||
| 143 | findChild<QWidget*>("sidebar")->setEnabled(false); | ||
| 144 | findChild<QWidget*>("treeView")->setEnabled(false); | ||
| 145 | findChild<QWidget*>("backButton")->setEnabled(false); | ||
| 146 | findChild<QWidget*>("forwardButton")->setEnabled(false); | ||
| 147 | findChild<QWidget*>("toParentButton")->setEnabled(false); | ||
| 148 | break; | ||
| 149 | case importMode: | 169 | case importMode: |
| 150 | default: | ||
| 151 | _progressBar.setValue(0); | 170 | _progressBar.setValue(0); |
| 152 | _importButton.setEnabled(true); | 171 | _importButton.setEnabled(true); |
| 153 | _importButton.setText(IMPORT_BUTTON_NAME); | 172 | _importButton.setText(IMPORT_BUTTON_NAME); |
| @@ -157,22 +176,60 @@ void ImportDialog::setMode(dialogMode mode) { · 3 unmodified lines | |||
| 157 | findChild<QWidget*>("forwardButton")->setEnabled(true); | 176 | findChild<QWidget*>("forwardButton")->setEnabled(true); |
| 158 | findChild<QWidget*>("toParentButton")->setEnabled(true); | 177 | findChild<QWidget*>("toParentButton")->setEnabled(true); |
| 159 | break; | 178 | break; |
| 179 | case loadingMode: | ||
| 180 | // Connect to VoxelImporter signals | ||
| 181 | connect(_importer, SIGNAL(importProgress(int)), this, SLOT(updateProgressBar(int))); | ||
| 182 | connect(_importer, SIGNAL(importDone()), this, SLOT(afterImport())); | ||
| 183 | |||
| 184 | _importButton.setEnabled(false); | ||
| 185 | _importButton.setText(LOADING_BUTTON_NAME); | ||
| 186 | findChild<QWidget*>("sidebar")->setEnabled(false); | ||
| 187 | findChild<QWidget*>("treeView")->setEnabled(false); | ||
| 188 | findChild<QWidget*>("backButton")->setEnabled(false); | ||
| 189 | findChild<QWidget*>("forwardButton")->setEnabled(false); | ||
| 190 | findChild<QWidget*>("toParentButton")->setEnabled(false); | ||
| 191 | break; | ||
| 192 | case finishedMode: | ||
| 193 | if (previousMode == loadingMode) { | ||
| 194 | // Disconnect from VoxelImporter signals | ||
| 195 | disconnect(_importer, SIGNAL(importProgress(int)), this, SLOT(setProgressBarValue(int))); | ||
| 196 | disconnect(_importer, SIGNAL(importDone()), this, SLOT(afterImport())); | ||
| 197 | } | ||
| 198 | setMode(importMode); | ||
| 199 | break; | ||
| 160 | } | 200 | } |
| 161 | } | 201 | } |
| 162 | 202 | ||
| 163 | void ImportDialog::setProgressBarValue(int value) { | 203 | void VoxelImportDialog::setProgressBarValue(int value) { |
| 164 | _progressBar.setValue(value); | 204 | _progressBar.setValue(value); |
| 165 | } | 205 | } |
| 166 | 206 | ||
| 167 | void ImportDialog::accept() { | 207 | void VoxelImportDialog::accept() { |
| 168 | emit accepted(); | 208 | if (getMode() == importMode) { |
| 209 | QString filename = getCurrentFile(); | ||
| 210 | |||
| 211 | // If file is invalid we ignore the call | ||
| 212 | if (!_importer->validImportFile(filename)) { | ||
| 213 | return; | ||
| 214 | } | ||
| 215 | // Let's prepare the dialog window for import | ||
| 216 | setMode(loadingMode); | ||
| 217 | |||
| 218 | _importer->import(filename); | ||
| 219 | } | ||
| 220 | } | ||
| 221 | |||
| 222 | void VoxelImportDialog::afterImport() { | ||
| 223 | setMode(finishedMode); | ||
| 224 | _didImport = true; | ||
| 225 | close(); | ||
| 169 | } | 226 | } |
| 170 | 227 | ||
| 171 | void ImportDialog::saveCurrentFile(QString filename) { | 228 | void VoxelImportDialog::saveCurrentFile(QString filename) { |
| 172 | _currentFile = QFileInfo(filename).isFile() ? filename : ""; | 229 | _currentFile = QFileInfo(filename).isFile() ? filename : ""; |
| 173 | } | 230 | } |
| 174 | 231 | ||
| 175 | void ImportDialog::setLayout() { | 232 | void VoxelImportDialog::setLayout() { |
| 176 | QGridLayout* gridLayout = (QGridLayout*) layout(); | 233 | QGridLayout* gridLayout = (QGridLayout*) layout(); |
| 177 | gridLayout->addWidget(&_progressBar, 2, 0, 2, 1); | 234 | gridLayout->addWidget(&_progressBar, 2, 0, 2, 1); |
| 178 | gridLayout->addWidget(&_cancelButton, 2, 1, 2, 1); | 235 | gridLayout->addWidget(&_cancelButton, 2, 1, 2, 1); |
| @@ -258,7 +315,7 @@ void ImportDialog::setLayout() { · 79 unmodified lines | |||
| 258 | 315 | ||
| 259 | } | 316 | } |
| 260 | 317 | ||
| 261 | void ImportDialog::setImportTypes() { | 318 | void VoxelImportDialog::setImportTypes() { |
| 262 | QFile config(Application::resourcesPath() + "config/config.json"); | 319 | QFile config(Application::resourcesPath() + "config/config.json"); |
| 263 | config.open(QFile::ReadOnly | QFile::Text); | 320 | config.open(QFile::ReadOnly | QFile::Text); |
| 264 | QJsonDocument document = QJsonDocument::fromJson(config.readAll()); | 321 | QJsonDocument document = QJsonDocument::fromJson(config.readAll()); |
| @@ -1,5 +1,5 @@ | |||
| 1 | // | 1 | // |
| 2 | // ImportDialog.h | 2 | // VoxelImportDialog.h |
| 3 | // interface/src/ui | 3 | // interface/src/ui |
| 4 | // | 4 | // |
| 5 | // Created by Clement Brisset on 8/12/13. | 5 | // Created by Clement Brisset on 8/12/13. |
| @@ -9,8 +9,8 @@ · 3 unmodified lines | |||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | // | 10 | // |
| 11 | 11 | ||
| 12 | #ifndef hifi_ImportDialog_h | 12 | #ifndef hifi_VoxelImportDialog_h |
| 13 | #define hifi_ImportDialog_h | 13 | #define hifi_VoxelImportDialog_h |
| 14 | 14 | ||
| 15 | #include "InterfaceConfig.h" | 15 | #include "InterfaceConfig.h" |
| 16 | 16 | ||
| @@ -23,6 +23,8 @@ · 6 unmodified lines | |||
| 23 | 23 | ||
| 24 | #include <SharedUtil.h> | 24 | #include <SharedUtil.h> |
| 25 | 25 | ||
| 26 | #include "voxels/VoxelImporter.h" | ||
| 27 | |||
| 26 | class HiFiIconProvider : public QFileIconProvider { | 28 | class HiFiIconProvider : public QFileIconProvider { |
| 27 | public: | 29 | public: |
| 28 | HiFiIconProvider(const QHash<QString, QString> map) { iconsMap = map; }; | 30 | HiFiIconProvider(const QHash<QString, QString> map) { iconsMap = map; }; |
| @@ -35,39 +37,45 @@ public: · 6 unmodified lines | |||
| 35 | enum dialogMode { | 37 | enum dialogMode { |
| 36 | importMode, | 38 | importMode, |
| 37 | loadingMode, | 39 | loadingMode, |
| 38 | placeMode | 40 | finishedMode |
| 39 | }; | 41 | }; |
| 40 | 42 | ||
| 41 | class ImportDialog : public QFileDialog { | 43 | class VoxelImportDialog : public QFileDialog { |
| 42 | Q_OBJECT | 44 | Q_OBJECT |
| 43 | 45 | ||
| 44 | public: | 46 | public: |
| 45 | ImportDialog(QWidget* parent = NULL); | 47 | VoxelImportDialog(QWidget* parent = NULL); |
| 46 | void reset(); | ||
| 47 | 48 | ||
| 48 | QString getCurrentFile() const { return _currentFile; } | 49 | QString getCurrentFile() const { return _currentFile; } |
| 49 | dialogMode getMode() const { return _mode; } | 50 | dialogMode getMode() const { return _mode; } |
| 51 | |||
| 50 | void setMode(dialogMode mode); | 52 | void setMode(dialogMode mode); |
| 53 | void reset(); | ||
| 54 | bool prompt(); | ||
| 55 | void loadSettings(QSettings* settings); | ||
| 56 | void saveSettings(QSettings* settings); | ||
| 51 | 57 | ||
| 52 | signals: | 58 | signals: |
| 53 | void canceled(); | 59 | void canceled(); |
| 54 | |||
| 55 | public slots: | ||
| 56 | void setProgressBarValue(int value); | ||
| 57 | 60 | ||
| 58 | private slots: | 61 | private slots: |
| 62 | void setProgressBarValue(int value); | ||
| 59 | void accept(); | 63 | void accept(); |
| 64 | void cancel(); | ||
| 60 | void saveCurrentFile(QString filename); | 65 | void saveCurrentFile(QString filename); |
| 66 | void afterImport(); | ||
| 61 | 67 | ||
| 62 | private: | 68 | private: |
| 69 | QPushButton _cancelButton; | ||
| 63 | QString _currentFile; | 70 | QString _currentFile; |
| 64 | QProgressBar _progressBar; | ||
| 65 | QPushButton _importButton; | 71 | QPushButton _importButton; |
| 66 | QPushButton _cancelButton; | 72 | VoxelImporter* _importer; |
| 67 | dialogMode _mode; | 73 | dialogMode _mode; |
| 74 | QProgressBar _progressBar; | ||
| 75 | bool _didImport; | ||
| 68 | 76 | ||
| 69 | void setLayout(); | 77 | void setLayout(); |
| 70 | void setImportTypes(); | 78 | void setImportTypes(); |
| 71 | }; | 79 | }; |
| 72 | 80 | ||
| 73 | #endif // hifi_ImportDialog_h | 81 | #endif // hifi_VoxelImportDialog_h |
| @@ -11,6 +11,8 @@ · 10 unmodified lines | |||
| 11 | #ifndef hifi_Base3DOverlay_h | 11 | #ifndef hifi_Base3DOverlay_h |
| 12 | #define hifi_Base3DOverlay_h | 12 | #define hifi_Base3DOverlay_h |
| 13 | 13 | ||
| 14 | #include <glm/glm.hpp> | ||
| 15 | |||
| 14 | #include "Overlay.h" | 16 | #include "Overlay.h" |
| 15 | 17 | ||
| 16 | class Base3DOverlay : public Overlay { | 18 | class Base3DOverlay : public Overlay { |
| @@ -26,7 +26,7 @@ void OctreePacketProcessor::processPacket(const SharedNodePointer& sendingNode, · 25 unmodified lines | |||
| 26 | if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) { | 26 | if (packetsToProcessCount() > WAY_BEHIND && Application::getInstance()->getLogger()->extraDebugging()) { |
| 27 | qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount()); | 27 | qDebug("OctreePacketProcessor::processPacket() packets to process=%d", packetsToProcessCount()); |
| 28 | } | 28 | } |
| 29 | ssize_t messageLength = mutablePacket.size(); | 29 | int messageLength = mutablePacket.size(); |
| 30 | 30 | ||
| 31 | Application* app = Application::getInstance(); | 31 | Application* app = Application::getInstance(); |
| 32 | bool wasStatsPacket = false; | 32 | bool wasStatsPacket = false; |
| @@ -20,8 +20,7 @@ · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | #include "voxels/VoxelImporter.h" | 21 | #include "voxels/VoxelImporter.h" |
| 22 | 22 | ||
| 23 | const QString SETTINGS_GROUP_NAME = "VoxelImport"; | 23 | const QStringList SUPPORTED_EXTENSIONS = QStringList() << "png" << "svo" << "schematic"; |
| 24 | const QString IMPORT_DIALOG_SETTINGS_KEY = "ImportDialogSettings"; | ||
| 25 | 24 | ||
| 26 | class ImportTask : public QObject, public QRunnable { | 25 | class ImportTask : public QObject, public QRunnable { |
| 27 | public: | 26 | public: |
| @@ -32,104 +31,46 @@ private: · 4 unmodified lines | |||
| 32 | QString _filename; | 31 | QString _filename; |
| 33 | }; | 32 | }; |
| 34 | 33 | ||
| 35 | VoxelImporter::VoxelImporter(QWidget* parent) : | 34 | VoxelImporter::VoxelImporter() : |
| 36 | QObject(parent), | ||
| 37 | _voxelTree(true), | 35 | _voxelTree(true), |
| 38 | _importDialog(parent), | 36 | _task(NULL) |
| 39 | _task(NULL), | ||
| 40 | _didImport(false) | ||
| 41 | { | 37 | { |
| 42 | LocalVoxelsList::getInstance()->addPersistantTree(IMPORT_TREE_NAME, &_voxelTree); | 38 | LocalVoxelsList::getInstance()->addPersistantTree(IMPORT_TREE_NAME, &_voxelTree); |
| 43 | 39 | ||
| 44 | connect(&_voxelTree, SIGNAL(importProgress(int)), &_importDialog, SLOT(setProgressBarValue(int))); | 40 | connect(&_voxelTree, SIGNAL(importProgress(int)), this, SIGNAL(importProgress(int))); |
| 45 | connect(&_importDialog, SIGNAL(canceled()), this, SLOT(cancel())); | ||
| 46 | connect(&_importDialog, SIGNAL(accepted()), this, SLOT(import())); | ||
| 47 | } | ||
| 48 | |||
| 49 | void VoxelImporter::saveSettings(QSettings* settings) { | ||
| 50 | settings->beginGroup(SETTINGS_GROUP_NAME); | ||
| 51 | settings->setValue(IMPORT_DIALOG_SETTINGS_KEY, _importDialog.saveState()); | ||
| 52 | settings->endGroup(); | ||
| 53 | } | ||
| 54 | |||
| 55 | void VoxelImporter::loadSettings(QSettings* settings) { | ||
| 56 | settings->beginGroup(SETTINGS_GROUP_NAME); | ||
| 57 | _importDialog.restoreState(settings->value(IMPORT_DIALOG_SETTINGS_KEY).toByteArray()); | ||
| 58 | settings->endGroup(); | ||
| 59 | } | 41 | } |
| 60 | 42 | ||
| 61 | VoxelImporter::~VoxelImporter() { | 43 | VoxelImporter::~VoxelImporter() { |
| 62 | cleanupTask(); | 44 | cleanupTask(); |
| 63 | } | 45 | } |
| 64 | 46 | ||
| 47 | void VoxelImporter::cancel() { | ||
| 48 | if (_task) { | ||
| 49 | disconnect(_task, 0, 0, 0); | ||
| 50 | } | ||
| 51 | reset(); | ||
| 52 | } | ||
| 53 | |||
| 65 | void VoxelImporter::reset() { | 54 | void VoxelImporter::reset() { |
| 66 | _voxelTree.eraseAllOctreeElements(); | 55 | _voxelTree.eraseAllOctreeElements(); |
| 67 | _importDialog.reset(); | ||
| 68 | |||
| 69 | cleanupTask(); | 56 | cleanupTask(); |
| 70 | } | 57 | } |
| 71 | 58 | ||
| 72 | int VoxelImporter::exec() { | 59 | void VoxelImporter::import(const QString& filename) { |
| 73 | reset(); | 60 | // If present, abort existing import |
| 74 | _importDialog.exec(); | 61 | if (_task) { |
| 75 | |||
| 76 | if (!_didImport) { | ||
| 77 | // if the import is rejected, we make sure to cleanup before leaving | ||
| 78 | cleanupTask(); | 62 | cleanupTask(); |
| 79 | return 1; | ||
| 80 | } else { | ||
| 81 | _didImport = false; | ||
| 82 | return 0; | ||
| 83 | } | 63 | } |
| 84 | } | ||
| 85 | 64 | ||
| 86 | void VoxelImporter::import() { | 65 | // If not already done, we switch to the local tree |
| 87 | switch (_importDialog.getMode()) { | 66 | if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) { |
| 88 | case loadingMode: | 67 | Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree); |
| 89 | _importDialog.setMode(placeMode); | ||
| 90 | return; | ||
| 91 | case placeMode: | ||
| 92 | // Means the user chose to import | ||
| 93 | _didImport = true; | ||
| 94 | _importDialog.close(); | ||
| 95 | return; | ||
| 96 | case importMode: | ||
| 97 | default: | ||
| 98 | QString filename = _importDialog.getCurrentFile(); | ||
| 99 | // if it's not a file, we ignore the call | ||
| 100 | if (!QFileInfo(filename).isFile()) { | ||
| 101 | return; | ||
| 102 | } | ||
| 103 | |||
| 104 | // Let's prepare the dialog window for import | ||
| 105 | _importDialog.setMode(loadingMode); | ||
| 106 | |||
| 107 | // If not already done, we switch to the local tree | ||
| 108 | if (Application::getInstance()->getSharedVoxelSystem()->getTree() != &_voxelTree) { | ||
| 109 | Application::getInstance()->getSharedVoxelSystem()->changeTree(&_voxelTree); | ||
| 110 | } | ||
| 111 | |||
| 112 | // Creation and launch of the import task on the thread pool | ||
| 113 | _task = new ImportTask(filename); | ||
| 114 | connect(_task, SIGNAL(destroyed()), SLOT(import())); | ||
| 115 | QThreadPool::globalInstance()->start(_task); | ||
| 116 | break; | ||
| 117 | } | 68 | } |
| 118 | } | ||
| 119 | 69 | ||
| 120 | void VoxelImporter::cancel() { | 70 | // Creation and launch of the import task on the thread pool |
| 121 | switch (_importDialog.getMode()) { | 71 | _task = new ImportTask(filename); |
| 122 | case loadingMode: | 72 | connect(_task, SIGNAL(destroyed()), SLOT(finishImport())); |
| 123 | disconnect(_task, 0, 0, 0); | 73 | QThreadPool::globalInstance()->start(_task); |
| 124 | cleanupTask(); | ||
| 125 | case placeMode: | ||
| 126 | _importDialog.setMode(importMode); | ||
| 127 | break; | ||
| 128 | case importMode: | ||
| 129 | default: | ||
| 130 | _importDialog.close(); | ||
| 131 | break; | ||
| 132 | } | ||
| 133 | } | 74 | } |
| 134 | 75 | ||
| 135 | void VoxelImporter::cleanupTask() { | 76 | void VoxelImporter::cleanupTask() { |
| @@ -140,6 +81,16 @@ void VoxelImporter::cleanupTask() { · 4 unmodified lines | |||
| 140 | } | 81 | } |
| 141 | } | 82 | } |
| 142 | 83 | ||
| 84 | void VoxelImporter::finishImport() { | ||
| 85 | cleanupTask(); | ||
| 86 | emit importDone(); | ||
| 87 | } | ||
| 88 | |||
| 89 | bool VoxelImporter::validImportFile(const QString& filename) { | ||
| 90 | QFileInfo fileInfo = QFileInfo(filename); | ||
| 91 | return fileInfo.isFile() && SUPPORTED_EXTENSIONS.indexOf(fileInfo.suffix().toLower()) != -1; | ||
| 92 | } | ||
| 93 | |||
| 143 | ImportTask::ImportTask(const QString &filename) | 94 | ImportTask::ImportTask(const QString &filename) |
| 144 | : _filename(filename) | 95 | : _filename(filename) |
| 145 | { | 96 | { |
| @@ -151,7 +102,7 @@ void ImportTask::run() { · 5 unmodified lines | |||
| 151 | // We start by cleaning up the shared voxel system just in case | 102 | // We start by cleaning up the shared voxel system just in case |
| 152 | voxelSystem->killLocalVoxels(); | 103 | voxelSystem->killLocalVoxels(); |
| 153 | 104 | ||
| 154 | // Then we call the righ method for the job | 105 | // Then we call the right method for the job |
| 155 | if (_filename.endsWith(".png", Qt::CaseInsensitive)) { | 106 | if (_filename.endsWith(".png", Qt::CaseInsensitive)) { |
| 156 | voxelSystem->getTree()->readFromSquareARGB32Pixels(_filename.toLocal8Bit().data()); | 107 | voxelSystem->getTree()->readFromSquareARGB32Pixels(_filename.toLocal8Bit().data()); |
| 157 | } else if (_filename.endsWith(".svo", Qt::CaseInsensitive)) { | 108 | } else if (_filename.endsWith(".svo", Qt::CaseInsensitive)) { |
| @@ -163,6 +114,6 @@ void ImportTask::run() { · 5 unmodified lines | |||
| 163 | qDebug() << "[ERROR] Invalid file extension." << endl; | 114 | qDebug() << "[ERROR] Invalid file extension." << endl; |
| 164 | } | 115 | } |
| 165 | 116 | ||
| 166 | // Here we reaverage the tree so that he is ready for preview | 117 | // Here we reaverage the tree so that it is ready for preview |
| 167 | voxelSystem->getTree()->reaverageOctreeElements(); | 118 | voxelSystem->getTree()->reaverageOctreeElements(); |
| 168 | } | 119 | } |
| @@ -14,8 +14,8 @@ · 13 unmodified lines | |||
| 14 | 14 | ||
| 15 | #include <QThread> | 15 | #include <QThread> |
| 16 | #include <QRunnable> | 16 | #include <QRunnable> |
| 17 | #include <QStringList> | ||
| 17 | 18 | ||
| 18 | #include "ui/ImportDialog.h" | ||
| 19 | #include "voxels/VoxelSystem.h" | 19 | #include "voxels/VoxelSystem.h" |
| 20 | 20 | ||
| 21 | class ImportTask; | 21 | class ImportTask; |
| @@ -23,28 +23,29 @@ class ImportTask; · 1 unmodified line | |||
| 23 | class VoxelImporter : public QObject { | 23 | class VoxelImporter : public QObject { |
| 24 | Q_OBJECT | 24 | Q_OBJECT |
| 25 | public: | 25 | public: |
| 26 | VoxelImporter(QWidget* parent = NULL); | 26 | VoxelImporter(); |
| 27 | ~VoxelImporter(); | 27 | ~VoxelImporter(); |
| 28 | 28 | ||
| 29 | void reset(); | 29 | void reset(); |
| 30 | void loadSettings(QSettings* settings); | 30 | void cancel(); |
| 31 | void saveSettings(QSettings* settings); | ||
| 32 | |||
| 33 | VoxelTree* getVoxelTree() { return &_voxelTree; } | 31 | VoxelTree* getVoxelTree() { return &_voxelTree; } |
| 32 | bool validImportFile(const QString& filename); | ||
| 34 | 33 | ||
| 35 | public slots: | 34 | public slots: |
| 36 | int exec(); | 35 | void import(const QString& filename); |
| 37 | void import(); | 36 | |
| 38 | void cancel(); | 37 | signals: |
| 38 | void importDone(); | ||
| 39 | void importProgress(int); | ||
| 39 | 40 | ||
| 40 | private: | 41 | private: |
| 41 | VoxelTree _voxelTree; | 42 | VoxelTree _voxelTree; |
| 42 | ImportDialog _importDialog; | ||
| 43 | |||
| 44 | ImportTask* _task; | 43 | ImportTask* _task; |
| 45 | bool _didImport; | ||
| 46 | 44 | ||
| 47 | void cleanupTask(); | 45 | void cleanupTask(); |
| 46 | |||
| 47 | private slots: | ||
| 48 | void finishImport(); | ||
| 48 | }; | 49 | }; |
| 49 | 50 | ||
| 50 | #endif // hifi_VoxelImporter_h | 51 | #endif // hifi_VoxelImporter_h |
| @@ -1,29 +1,9 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME animation) | 1 | set(TARGET_NAME animation) |
| 8 | 2 | ||
| 9 | find_package(Qt5Widgets REQUIRED) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 10 | 4 | setup_hifi_library(Network Script) | |
| 11 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | ||
| 12 | setup_hifi_library(${TARGET_NAME}) | ||
| 13 | |||
| 14 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 15 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 16 | |||
| 17 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | ||
| 18 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 19 | link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") | ||
| 20 | |||
| 21 | # link ZLIB | ||
| 22 | find_package(ZLIB) | ||
| 23 | 5 | ||
| 24 | target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) | 6 | link_hifi_libraries(shared fbx) |
| 25 | 7 | ||
| 26 | # add a definition for ssize_t so that windows doesn't bail | 8 | # call macro to link our dependencies and bubble them up via a property on our target |
| 27 | if (WIN32) | 9 | link_shared_dependencies() |
| 28 | add_definitions(-Dssize_t=long) | ||
| 29 | endif () | ||
| @@ -1,26 +1,11 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME audio) | 1 | set(TARGET_NAME audio) |
| 8 | 2 | ||
| 9 | find_package(Qt5 COMPONENTS Script) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 10 | include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") | 4 | setup_hifi_library(Network) |
| 11 | |||
| 12 | # set up the external glm library | ||
| 13 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | ||
| 14 | setup_hifi_library(${TARGET_NAME}) | ||
| 15 | 5 | ||
| 16 | include(${MACRO_DIR}/IncludeGLM.cmake) | 6 | include_glm() |
| 17 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 18 | 7 | ||
| 19 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 8 | link_hifi_libraries(networking shared) |
| 20 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 21 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 22 | 9 | ||
| 23 | # add a definition for ssize_t so that windows doesn't bail | 10 | # call macro to link our dependencies and bubble them up via a property on our target |
| 24 | if (WIN32) | 11 | link_shared_dependencies() |
| 25 | add_definitions(-Dssize_t=long) | ||
| 26 | endif () | ||
| @@ -0,0 +1,26 @@ | |||
| 1 | // | ||
| 2 | // AudioFilter.cpp | ||
| 3 | // hifi | ||
| 4 | // | ||
| 5 | // Created by Craig Hansen-Sturm on 8/10/14. | ||
| 6 | // Copyright 2014 High Fidelity, Inc. | ||
| 7 | // | ||
| 8 | // Distributed under the Apache License, Version 2.0. | ||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | // | ||
| 11 | |||
| 12 | #include <math.h> | ||
| 13 | #include <vector> | ||
| 14 | #include <SharedUtil.h> | ||
| 15 | #include "AudioRingBuffer.h" | ||
| 16 | #include "AudioFilter.h" | ||
| 17 | |||
| 18 | template<> | ||
| 19 | AudioFilterPEQ3::FilterParameter AudioFilterPEQ3::_profiles[ AudioFilterPEQ3::_profileCount ][ AudioFilterPEQ3::_filterCount ] = { | ||
| 20 | |||
| 21 | // Freq Gain Q Freq Gain Q Freq Gain Q | ||
| 22 | { { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // flat response (default) | ||
| 23 | { { 300.0f, 1.0f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 0.1f, 1.0f } }, // treble cut | ||
| 24 | { { 300.0f, 0.1f, 1.0f }, { 1000.0f, 1.0f, 1.0f }, { 4000.0f, 1.0f, 1.0f } }, // bass cut | ||
| 25 | { { 300.0f, 1.5f, 0.71f }, { 1000.0f, 0.5f, 1.0f }, { 4000.0f, 1.50f, 0.71f } } // smiley curve | ||
| 26 | }; | ||
| @@ -0,0 +1,298 @@ | |||
| 1 | // | ||
| 2 | // AudioFilter.h | ||
| 3 | // hifi | ||
| 4 | // | ||
| 5 | // Created by Craig Hansen-Sturm on 8/9/14. | ||
| 6 | // Copyright 2014 High Fidelity, Inc. | ||
| 7 | // | ||
| 8 | // Distributed under the Apache License, Version 2.0. | ||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | // | ||
| 11 | |||
| 12 | #ifndef hifi_AudioFilter_h | ||
| 13 | #define hifi_AudioFilter_h | ||
| 14 | |||
| 15 | //////////////////////////////////////////////////////////////////////////////////////////// | ||
| 16 | // Implements a standard biquad filter in "Direct Form 1" | ||
| 17 | // Reference http://www.musicdsp.org/files/Audio-EQ-Cookbook.txt | ||
| 18 | // | ||
| 19 | class AudioBiquad { | ||
| 20 | |||
| 21 | // | ||
| 22 | // private data | ||
| 23 | // | ||
| 24 | float _a0; // gain | ||
| 25 | float _a1; // feedforward 1 | ||
| 26 | float _a2; // feedforward 2 | ||
| 27 | float _b1; // feedback 1 | ||
| 28 | float _b2; // feedback 2 | ||
| 29 | |||
| 30 | float _xm1; | ||
| 31 | float _xm2; | ||
| 32 | float _ym1; | ||
| 33 | float _ym2; | ||
| 34 | |||
| 35 | public: | ||
| 36 | |||
| 37 | // | ||
| 38 | // ctor/dtor | ||
| 39 | // | ||
| 40 | AudioBiquad() | ||
| 41 | : _xm1(0.) | ||
| 42 | , _xm2(0.) | ||
| 43 | , _ym1(0.) | ||
| 44 | , _ym2(0.) { | ||
| 45 | setParameters(0.,0.,0.,0.,0.); | ||
| 46 | } | ||
| 47 | |||
| 48 | ~AudioBiquad() { | ||
| 49 | } | ||
| 50 | |||
| 51 | // | ||
| 52 | // public interface | ||
| 53 | // | ||
| 54 | void setParameters( const float a0, const float a1, const float a2, const float b1, const float b2 ) { | ||
| 55 | _a0 = a0; _a1 = a1; _a2 = a2; _b1 = b1; _b2 = b2; | ||
| 56 | } | ||
| 57 | |||
| 58 | void getParameters( float& a0, float& a1, float& a2, float& b1, float& b2 ) { | ||
| 59 | a0 = _a0; a1 = _a1; a2 = _a2; b1 = _b1; b2 = _b2; | ||
| 60 | } | ||
| 61 | |||
| 62 | void render( const float* in, float* out, const int frames) { | ||
| 63 | |||
| 64 | float x; | ||
| 65 | float y; | ||
| 66 | |||
| 67 | for (int i = 0; i < frames; ++i) { | ||
| 68 | |||
| 69 | x = *in++; | ||
| 70 | |||
| 71 | // biquad | ||
| 72 | y = (_a0 * x) | ||
| 73 | + (_a1 * _xm1) | ||
| 74 | + (_a2 * _xm2) | ||
| 75 | - (_b1 * _ym1) | ||
| 76 | - (_b2 * _ym2); | ||
| 77 | |||
| 78 | // update delay line | ||
| 79 | _xm2 = _xm1; | ||
| 80 | _xm1 = x; | ||
| 81 | _ym2 = _ym1; | ||
| 82 | _ym1 = y; | ||
| 83 | |||
| 84 | *out++ = y; | ||
| 85 | } | ||
| 86 | } | ||
| 87 | |||
| 88 | void reset() { | ||
| 89 | _xm1 = _xm2 = _ym1 = _ym2 = 0.; | ||
| 90 | } | ||
| 91 | }; | ||
| 92 | |||
| 93 | //////////////////////////////////////////////////////////////////////////////////////////// | ||
| 94 | // Implements a single-band parametric EQ using a biquad "peaking EQ" configuration | ||
| 95 | // | ||
| 96 | // gain > 1.0 boosts the center frequency | ||
| 97 | // gain < 1.0 cuts the center frequency | ||
| 98 | // | ||
| 99 | class AudioParametricEQ { | ||
| 100 | |||
| 101 | // | ||
| 102 | // private data | ||
| 103 | // | ||
| 104 | AudioBiquad _kernel; | ||
| 105 | float _sampleRate; | ||
| 106 | float _frequency; | ||
| 107 | float _gain; | ||
| 108 | float _slope; | ||
| 109 | |||
| 110 | // helpers | ||
| 111 | void updateKernel() { | ||
| 112 | |||
| 113 | /* | ||
| 114 | a0 = 1 + alpha*A | ||
| 115 | a1 = -2*cos(w0) | ||
| 116 | a2 = 1 - alpha*A | ||
| 117 | b1 = -2*cos(w0) | ||
| 118 | b2 = 1 - alpha/A | ||
| 119 | */ | ||
| 120 | |||
| 121 | const float a = _gain; | ||
| 122 | const float omega = TWO_PI * _frequency / _sampleRate; | ||
| 123 | const float alpha = 0.5f * sinf(omega) / _slope; | ||
| 124 | const float gamma = 1.0f / ( 1.0f + (alpha/a) ); | ||
| 125 | |||
| 126 | const float a0 = 1.0f + (alpha*a); | ||
| 127 | const float a1 = -2.0f * cosf(omega); | ||
| 128 | const float a2 = 1.0f - (alpha*a); | ||
| 129 | const float b1 = a1; | ||
| 130 | const float b2 = 1.0f - (alpha/a); | ||
| 131 | |||
| 132 | _kernel.setParameters( a0*gamma,a1*gamma,a2*gamma,b1*gamma,b2*gamma ); | ||
| 133 | } | ||
| 134 | |||
| 135 | public: | ||
| 136 | // | ||
| 137 | // ctor/dtor | ||
| 138 | // | ||
| 139 | AudioParametricEQ() { | ||
| 140 | |||
| 141 | setParameters(0.,0.,0.,0.); | ||
| 142 | updateKernel(); | ||
| 143 | } | ||
| 144 | |||
| 145 | ~AudioParametricEQ() { | ||
| 146 | } | ||
| 147 | |||
| 148 | // | ||
| 149 | // public interface | ||
| 150 | // | ||
| 151 | void setParameters( const float sampleRate, const float frequency, const float gain, const float slope ) { | ||
| 152 | |||
| 153 | _sampleRate = std::max(sampleRate,1.0f); | ||
| 154 | _frequency = std::max(frequency,2.0f); | ||
| 155 | _gain = std::max(gain,0.0f); | ||
| 156 | _slope = std::max(slope,0.00001f); | ||
| 157 | |||
| 158 | updateKernel(); | ||
| 159 | } | ||
| 160 | |||
| 161 | void getParameters( float& sampleRate, float& frequency, float& gain, float& slope ) { | ||
| 162 | sampleRate = _sampleRate; frequency = _frequency; gain = _gain; slope = _slope; | ||
| 163 | } | ||
| 164 | |||
| 165 | void render(const float* in, float* out, const int frames ) { | ||
| 166 | _kernel.render(in,out,frames); | ||
| 167 | } | ||
| 168 | |||
| 169 | void reset() { | ||
| 170 | _kernel.reset(); | ||
| 171 | } | ||
| 172 | }; | ||
| 173 | |||
| 174 | //////////////////////////////////////////////////////////////////////////////////////////// | ||
| 175 | // Helper/convenience class that implements a bank of EQ objects | ||
| 176 | // | ||
| 177 | template< typename T, const int N> | ||
| 178 | class AudioFilterBank { | ||
| 179 | |||
| 180 | // | ||
| 181 | // types | ||
| 182 | // | ||
| 183 | struct FilterParameter { | ||
| 184 | float _p1; | ||
| 185 | float _p2; | ||
| 186 | float _p3; | ||
| 187 | }; | ||
| 188 | |||
| 189 | // | ||
| 190 | // private static data | ||
| 191 | // | ||
| 192 | static const int _filterCount = N; | ||
| 193 | static const int _profileCount = 4; | ||
| 194 | |||
| 195 | static FilterParameter _profiles[_profileCount][_filterCount]; | ||
| 196 | |||
| 197 | // | ||
| 198 | // private data | ||
| 199 | // | ||
| 200 | T _filters[ _filterCount ]; | ||
| 201 | float* _buffer; | ||
| 202 | float _sampleRate; | ||
| 203 | uint16_t _frameCount; | ||
| 204 | |||
| 205 | public: | ||
| 206 | |||
| 207 | // | ||
| 208 | // ctor/dtor | ||
| 209 | // | ||
| 210 | AudioFilterBank() | ||
| 211 | : _buffer(NULL) | ||
| 212 | , _sampleRate(0.) | ||
| 213 | , _frameCount(0) { | ||
| 214 | } | ||
| 215 | |||
| 216 | ~AudioFilterBank() { | ||
| 217 | finalize(); | ||
| 218 | } | ||
| 219 | |||
| 220 | // | ||
| 221 | // public interface | ||
| 222 | // | ||
| 223 | void initialize( const float sampleRate, const int frameCount ) { | ||
| 224 | finalize(); | ||
| 225 | |||
| 226 | _buffer = (float*)malloc( frameCount * sizeof(float) ); | ||
| 227 | if(!_buffer) { | ||
| 228 | return; | ||
| 229 | } | ||
| 230 | |||
| 231 | _sampleRate = sampleRate; | ||
| 232 | _frameCount = frameCount; | ||
| 233 | |||
| 234 | reset(); | ||
| 235 | loadProfile(0); // load default profile "flat response" into the bank (see AudioFilter.cpp) | ||
| 236 | } | ||
| 237 | |||
| 238 | void finalize() { | ||
| 239 | if (_buffer ) { | ||
| 240 | free (_buffer); | ||
| 241 | _buffer = NULL; | ||
| 242 | } | ||
| 243 | } | ||
| 244 | |||
| 245 | void loadProfile( int profileIndex ) { | ||
| 246 | if (profileIndex >= 0 && profileIndex < _profileCount) { | ||
| 247 | |||
| 248 | for (int i = 0; i < _filterCount; ++i) { | ||
| 249 | FilterParameter p = _profiles[profileIndex][i]; | ||
| 250 | |||
| 251 | _filters[i].setParameters(_sampleRate,p._p1,p._p2,p._p3); | ||
| 252 | } | ||
| 253 | } | ||
| 254 | } | ||
| 255 | |||
| 256 | void render( const float* in, float* out, const int frameCount ) { | ||
| 257 | for (int i = 0; i < _filterCount; ++i) { | ||
| 258 | _filters[i].render( in, out, frameCount ); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | void render( const int16_t* in, int16_t* out, const int frameCount ) { | ||
| 263 | if (!_buffer || ( frameCount > _frameCount )) | ||
| 264 | return; | ||
| 265 | |||
| 266 | const int scale = (2 << ((8*sizeof(int16_t))-1)); | ||
| 267 | |||
| 268 | // convert int16_t to float32 (normalized to -1. ... 1.) | ||
| 269 | for (int i = 0; i < frameCount; ++i) { | ||
| 270 | _buffer[i] = ((float)(*in++)) / scale; | ||
| 271 | } | ||
| 272 | // for this filter, we share input/output buffers at each stage, but our design does not mandate this | ||
| 273 | render( _buffer, _buffer, frameCount ); | ||
| 274 | |||
| 275 | // convert float32 to int16_t | ||
| 276 | for (int i = 0; i < frameCount; ++i) { | ||
| 277 | *out++ = (int16_t)(_buffer[i] * scale); | ||
| 278 | } | ||
| 279 | } | ||
| 280 | |||
| 281 | void reset() { | ||
| 282 | for (int i = 0; i < _filterCount; ++i ) { | ||
| 283 | _filters[i].reset(); | ||
| 284 | } | ||
| 285 | } | ||
| 286 | |||
| 287 | }; | ||
| 288 | |||
| 289 | //////////////////////////////////////////////////////////////////////////////////////////// | ||
| 290 | // Specializations of AudioFilterBank | ||
| 291 | // | ||
| 292 | typedef AudioFilterBank< AudioParametricEQ, 1> AudioFilterPEQ1; // bank with one band of PEQ | ||
| 293 | typedef AudioFilterBank< AudioParametricEQ, 2> AudioFilterPEQ2; // bank with two bands of PEQ | ||
| 294 | typedef AudioFilterBank< AudioParametricEQ, 3> AudioFilterPEQ3; // bank with three bands of PEQ | ||
| 295 | // etc.... | ||
| 296 | |||
| 297 | |||
| 298 | #endif // hifi_AudioFilter_h | ||
| @@ -15,9 +15,9 @@ · 14 unmodified lines | |||
| 15 | 15 | ||
| 16 | #include <QtCore/QDebug> | 16 | #include <QtCore/QDebug> |
| 17 | 17 | ||
| 18 | #include "PacketHeaders.h" | 18 | #include <PacketHeaders.h> |
| 19 | #include "AudioRingBuffer.h" | ||
| 20 | 19 | ||
| 20 | #include "AudioRingBuffer.h" | ||
| 21 | 21 | ||
| 22 | AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) : | 22 | AudioRingBuffer::AudioRingBuffer(int numFrameSamples, bool randomAccessMode, int numFramesCapacity) : |
| 23 | _frameCapacity(numFramesCapacity), | 23 | _frameCapacity(numFramesCapacity), |
| @@ -15,12 +15,10 @@ · 14 unmodified lines | |||
| 15 | #include <limits> | 15 | #include <limits> |
| 16 | #include <stdint.h> | 16 | #include <stdint.h> |
| 17 | 17 | ||
| 18 | #include <glm/glm.hpp> | ||
| 19 | |||
| 20 | #include <QtCore/QIODevice> | 18 | #include <QtCore/QIODevice> |
| 21 | 19 | ||
| 22 | #include "NodeData.h" | 20 | #include <SharedUtil.h> |
| 23 | #include "SharedUtil.h" | 21 | #include <NodeData.h> |
| 24 | 22 | ||
| 25 | const int SAMPLE_RATE = 24000; | 23 | const int SAMPLE_RATE = 24000; |
| 26 | 24 | ||
| @@ -9,6 +9,8 @@ · 8 unmodified lines | |||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | // | 10 | // |
| 11 | 11 | ||
| 12 | #include <glm/glm.hpp> | ||
| 13 | |||
| 12 | #include "InboundAudioStream.h" | 14 | #include "InboundAudioStream.h" |
| 13 | #include "PacketHeaders.h" | 15 | #include "PacketHeaders.h" |
| 14 | 16 | ||
| @@ -1,30 +1,12 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME avatars) | 1 | set(TARGET_NAME avatars) |
| 8 | 2 | ||
| 9 | find_package(Qt5Script REQUIRED) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 10 | 4 | setup_hifi_library(Network Script) | |
| 11 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | ||
| 12 | setup_hifi_library(${TARGET_NAME}) | ||
| 13 | |||
| 14 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 15 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 16 | |||
| 17 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | ||
| 18 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 19 | 5 | ||
| 20 | # link in the hifi voxels library | 6 | include_glm() |
| 21 | link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") | ||
| 22 | link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 23 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 24 | 7 | ||
| 25 | target_link_libraries(${TARGET_NAME} Qt5::Script) | 8 | link_hifi_libraries(shared octree voxels networking) |
| 9 | include_hifi_library_headers(fbx) | ||
| 26 | 10 | ||
| 27 | # add a definition for ssize_t so that windows doesn't bail | 11 | # call macro to link our dependencies and bubble them up via a property on our target |
| 28 | if (WIN32) | 12 | link_shared_dependencies() |
| 29 | add_definitions(-Dssize_t=long) | ||
| 30 | endif () | ||
| @@ -22,7 +22,7 @@ · 21 unmodified lines | |||
| 22 | #include <NetworkAccessManager.h> | 22 | #include <NetworkAccessManager.h> |
| 23 | #include <NodeList.h> | 23 | #include <NodeList.h> |
| 24 | #include <PacketHeaders.h> | 24 | #include <PacketHeaders.h> |
| 25 | #include <SharedUtil.h> | 25 | #include <GLMHelpers.h> |
| 26 | #include <StreamUtils.h> | 26 | #include <StreamUtils.h> |
| 27 | #include <UUID.h> | 27 | #include <UUID.h> |
| 28 | #include <VoxelConstants.h> | 28 | #include <VoxelConstants.h> |
| @@ -11,13 +11,13 @@ · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | #include <glm/gtx/quaternion.hpp> | 12 | #include <glm/gtx/quaternion.hpp> |
| 13 | 13 | ||
| 14 | #include <FBXReader.h> | ||
| 15 | #include <GLMHelpers.h> | ||
| 14 | #include <OctreeConstants.h> | 16 | #include <OctreeConstants.h> |
| 15 | 17 | ||
| 16 | #include "AvatarData.h" | 18 | #include "AvatarData.h" |
| 17 | #include "HeadData.h" | 19 | #include "HeadData.h" |
| 18 | 20 | ||
| 19 | #include "../fbx/src/FBXReader.h" | ||
| 20 | |||
| 21 | HeadData::HeadData(AvatarData* owningAvatar) : | 21 | HeadData::HeadData(AvatarData* owningAvatar) : |
| 22 | _baseYaw(0.0f), | 22 | _baseYaw(0.0f), |
| 23 | _basePitch(0.0f), | 23 | _basePitch(0.0f), |
| @@ -9,7 +9,7 @@ · 8 unmodified lines | |||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | // | 10 | // |
| 11 | 11 | ||
| 12 | #include <SharedUtil.h> | 12 | #include <GLMHelpers.h> |
| 13 | 13 | ||
| 14 | #include "AvatarData.h" | 14 | #include "AvatarData.h" |
| 15 | #include "Referential.h" | 15 | #include "Referential.h" |
| @@ -1,14 +1,7 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME embedded-webserver) | 1 | set(TARGET_NAME embedded-webserver) |
| 8 | 2 | ||
| 9 | find_package(Qt5Network REQUIRED) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 10 | 4 | setup_hifi_library(Network) | |
| 11 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | ||
| 12 | setup_hifi_library(${TARGET_NAME}) | ||
| 13 | 5 | ||
| 14 | target_link_libraries(${TARGET_NAME} Qt5::Network) | 6 | # call macro to link our dependencies and bubble them up via a property on our target |
| 7 | link_shared_dependencies() | ||
| @@ -1,39 +1,11 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME entities) | 1 | set(TARGET_NAME entities) |
| 8 | 2 | ||
| 9 | find_package(Qt5Widgets REQUIRED) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 10 | 4 | setup_hifi_library(Network Script) | |
| 11 | include(${MACRO_DIR}/AutoMTC.cmake) | ||
| 12 | auto_mtc(${TARGET_NAME} "${ROOT_DIR}") | ||
| 13 | |||
| 14 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | ||
| 15 | setup_hifi_library(${TARGET_NAME} "${AUTOMTC_SRC}") | ||
| 16 | |||
| 17 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 18 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 19 | |||
| 20 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | ||
| 21 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 22 | link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") | ||
| 23 | link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") | ||
| 24 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 25 | link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") | ||
| 26 | |||
| 27 | # for streamable | ||
| 28 | link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 29 | 5 | ||
| 30 | # link ZLIB | 6 | include_glm() |
| 31 | find_package(ZLIB) | ||
| 32 | 7 | ||
| 33 | include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") | 8 | link_hifi_libraries(shared octree fbx networking animation) |
| 34 | target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) | ||
| 35 | 9 | ||
| 36 | # add a definition for ssize_t so that windows doesn't bail | 10 | # call macro to link our dependencies and bubble them up via a property on our target |
| 37 | if (WIN32) | 11 | link_shared_dependencies() |
| 38 | add_definitions(-Dssize_t=long) | ||
| 39 | endif () | ||
| @@ -1,30 +1,15 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME fbx) | 1 | set(TARGET_NAME fbx) |
| 8 | 2 | ||
| 9 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 10 | setup_hifi_library(${TARGET_NAME}) | 4 | setup_hifi_library() |
| 11 | |||
| 12 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 13 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 14 | 5 | ||
| 15 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 6 | include_glm() |
| 16 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 17 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 18 | link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") | ||
| 19 | link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 20 | 7 | ||
| 21 | # link ZLIB | 8 | link_hifi_libraries(shared networking octree voxels) |
| 22 | find_package(ZLIB) | ||
| 23 | 9 | ||
| 10 | find_package(ZLIB REQUIRED) | ||
| 24 | include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") | 11 | include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") |
| 25 | target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) | 12 | list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") |
| 26 | 13 | ||
| 27 | # add a definition for ssize_t so that windows doesn't bail | 14 | # call macro to link our dependencies and bubble them up via a property on our target |
| 28 | if (WIN32) | 15 | link_shared_dependencies() |
| 29 | add_definitions(-Dssize_t=long) | ||
| 30 | endif () | ||
| @@ -23,9 +23,9 @@ · 22 unmodified lines | |||
| 23 | #include <glm/gtx/transform.hpp> | 23 | #include <glm/gtx/transform.hpp> |
| 24 | 24 | ||
| 25 | #include <GeometryUtil.h> | 25 | #include <GeometryUtil.h> |
| 26 | #include <GLMHelpers.h> | ||
| 26 | #include <OctalCode.h> | 27 | #include <OctalCode.h> |
| 27 | #include <Shape.h> | 28 | #include <Shape.h> |
| 28 | #include <SharedUtil.h> | ||
| 29 | 29 | ||
| 30 | #include <VoxelTree.h> | 30 | #include <VoxelTree.h> |
| 31 | 31 | ||
| @@ -1,29 +1,14 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME metavoxels) | 1 | set(TARGET_NAME metavoxels) |
| 8 | 2 | ||
| 9 | find_package(Qt5 COMPONENTS Network Script Widgets) | 3 | auto_mtc() |
| 10 | 4 | ||
| 11 | include(${MACRO_DIR}/AutoMTC.cmake) | 5 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 12 | auto_mtc(${TARGET_NAME} "${ROOT_DIR}") | 6 | setup_hifi_library(Network Script Widgets) |
| 13 | |||
| 14 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | ||
| 15 | setup_hifi_library(${TARGET_NAME} "${AUTOMTC_SRC}") | ||
| 16 | 7 | ||
| 17 | # link in the networking library | 8 | # link in the networking library |
| 18 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 9 | link_hifi_libraries(shared networking) |
| 19 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 20 | |||
| 21 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 22 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 23 | 10 | ||
| 24 | target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) | 11 | include_glm() |
| 25 | 12 | ||
| 26 | # add a definition for ssize_t so that windows doesn't bail | 13 | # call macro to link our dependencies and bubble them up via a property on our target |
| 27 | if (WIN32) | 14 | link_shared_dependencies() |
| 28 | add_definitions(-Dssize_t=long) | ||
| 29 | endif () | ||
| @@ -489,22 +489,92 @@ HeightfieldData::HeightfieldData(const QByteArray& contents) : · 488 unmodified lines | |||
| 489 | _contents(contents) { | 489 | _contents(contents) { |
| 490 | } | 490 | } |
| 491 | 491 | ||
| 492 | const int BYTES_PER_PIXEL = 3; | 492 | HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) { |
| 493 | read(in, bytes, color); | ||
| 494 | } | ||
| 493 | 495 | ||
| 494 | HeightfieldData::HeightfieldData(Bitstream& in, int bytes, bool color) : | 496 | enum HeightfieldImage { NULL_HEIGHTFIELD_IMAGE, NORMAL_HEIGHTFIELD_IMAGE, DEFLATED_HEIGHTFIELD_IMAGE }; |
| 495 | _encoded(in.readAligned(bytes)) { | 497 | |
| 496 | 498 | static QByteArray encodeHeightfieldImage(const QImage& image) { | |
| 497 | QImage image = QImage::fromData(_encoded).convertToFormat(QImage::Format_RGB888); | 499 | if (image.isNull()) { |
| 498 | if (color) { | 500 | return QByteArray(1, NULL_HEIGHTFIELD_IMAGE); |
| 499 | _contents.resize(image.width() * image.height() * BYTES_PER_PIXEL); | 501 | } |
| 500 | memcpy(_contents.data(), image.constBits(), _contents.size()); | 502 | QBuffer buffer; |
| 503 | buffer.open(QIODevice::WriteOnly); | ||
| 504 | const int JPEG_ENCODE_THRESHOLD = 16; | ||
| 505 | if (image.width() >= JPEG_ENCODE_THRESHOLD && image.height() >= JPEG_ENCODE_THRESHOLD) { | ||
| 506 | qint32 offsetX = image.offset().x(), offsetY = image.offset().y(); | ||
| 507 | buffer.write((char*)&offsetX, sizeof(qint32)); | ||
| 508 | buffer.write((char*)&offsetY, sizeof(qint32)); | ||
| 509 | image.save(&buffer, "JPG"); | ||
| 510 | return QByteArray(1, DEFLATED_HEIGHTFIELD_IMAGE) + qCompress(buffer.data()); | ||
| 501 | 511 | ||
| 502 | } else { | 512 | } else { |
| 503 | _contents.resize(image.width() * image.height()); | 513 | buffer.putChar(NORMAL_HEIGHTFIELD_IMAGE); |
| 504 | char* dest = _contents.data(); | 514 | image.save(&buffer, "PNG"); |
| 505 | for (const uchar* src = image.constBits(), *end = src + _contents.size() * BYTES_PER_PIXEL; | 515 | return buffer.data(); |
| 506 | src != end; src += BYTES_PER_PIXEL) { | 516 | } |
| 507 | *dest++ = *src; | 517 | } |
| 518 | |||
| 519 | const QImage decodeHeightfieldImage(const QByteArray& data) { | ||
| 520 | switch (data.at(0)) { | ||
| 521 | case NULL_HEIGHTFIELD_IMAGE: | ||
| 522 | default: | ||
| 523 | return QImage(); | ||
| 524 | |||
| 525 | case NORMAL_HEIGHTFIELD_IMAGE: | ||
| 526 | return QImage::fromData(QByteArray::fromRawData(data.constData() + 1, data.size() - 1)); | ||
| 527 | |||
| 528 | case DEFLATED_HEIGHTFIELD_IMAGE: { | ||
| 529 | QByteArray inflated = qUncompress((const uchar*)data.constData() + 1, data.size() - 1); | ||
| 530 | const int OFFSET_SIZE = sizeof(qint32) * 2; | ||
| 531 | QImage image = QImage::fromData((const uchar*)inflated.constData() + OFFSET_SIZE, inflated.size() - OFFSET_SIZE); | ||
| 532 | const qint32* offsets = (const qint32*)inflated.constData(); | ||
| 533 | image.setOffset(QPoint(offsets[0], offsets[1])); | ||
| 534 | return image; | ||
| 535 | } | ||
| 536 | } | ||
| 537 | } | ||
| 538 | |||
| 539 | HeightfieldData::HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color) { | ||
| 540 | if (!reference) { | ||
| 541 | read(in, bytes, color); | ||
| 542 | return; | ||
| 543 | } | ||
| 544 | QMutexLocker locker(&reference->_encodedDeltaMutex); | ||
| 545 | reference->_encodedDelta = in.readAligned(bytes); | ||
| 546 | reference->_deltaData = this; | ||
| 547 | _contents = reference->_contents; | ||
| 548 | QImage image = decodeHeightfieldImage(reference->_encodedDelta); | ||
| 549 | if (image.isNull()) { | ||
| 550 | return; | ||
| 551 | } | ||
| 552 | QPoint offset = image.offset(); | ||
| 553 | image = image.convertToFormat(QImage::Format_RGB888); | ||
| 554 | if (offset.x() == 0) { | ||
| 555 | set(image, color); | ||
| 556 | return; | ||
| 557 | } | ||
| 558 | int minX = offset.x() - 1; | ||
| 559 | int minY = offset.y() - 1; | ||
| 560 | if (color) { | ||
| 561 | int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES); | ||
| 562 | char* dest = _contents.data() + (minY * size + minX) * COLOR_BYTES; | ||
| 563 | int destStride = size * COLOR_BYTES; | ||
| 564 | int srcStride = image.width() * COLOR_BYTES; | ||
| 565 | for (int y = 0; y < image.height(); y++) { | ||
| 566 | memcpy(dest, image.constScanLine(y), srcStride); | ||
| 567 | dest += destStride; | ||
| 568 | } | ||
| 569 | } else { | ||
| 570 | int size = glm::sqrt((float)_contents.size()); | ||
| 571 | char* lineDest = _contents.data() + minY * size + minX; | ||
| 572 | for (int y = 0; y < image.height(); y++) { | ||
| 573 | const uchar* src = image.constScanLine(y); | ||
| 574 | for (char* dest = lineDest, *end = dest + image.width(); dest != end; dest++, src += COLOR_BYTES) { | ||
| 575 | *dest = *src; | ||
| 576 | } | ||
| 577 | lineDest += size; | ||
| 508 | } | 578 | } |
| 509 | } | 579 | } |
| 510 | } | 580 | } |
| @@ -514,7 +584,7 @@ void HeightfieldData::write(Bitstream& out, bool color) { · 3 unmodified lines | |||
| 514 | if (_encoded.isEmpty()) { | 584 | if (_encoded.isEmpty()) { |
| 515 | QImage image; | 585 | QImage image; |
| 516 | if (color) { | 586 | if (color) { |
| 517 | int size = glm::sqrt(_contents.size() / (float)BYTES_PER_PIXEL); | 587 | int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES); |
| 518 | image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888); | 588 | image = QImage((uchar*)_contents.data(), size, size, QImage::Format_RGB888); |
| 519 | } else { | 589 | } else { |
| 520 | int size = glm::sqrt((float)_contents.size()); | 590 | int size = glm::sqrt((float)_contents.size()); |
| @@ -526,38 +596,170 @@ void HeightfieldData::write(Bitstream& out, bool color) { · 5 unmodified lines | |||
| 526 | *dest++ = *src; | 596 | *dest++ = *src; |
| 527 | } | 597 | } |
| 528 | } | 598 | } |
| 529 | QBuffer buffer(&_encoded); | 599 | _encoded = encodeHeightfieldImage(image); |
| 530 | buffer.open(QIODevice::WriteOnly); | ||
| 531 | image.save(&buffer, "JPG"); | ||
| 532 | } | 600 | } |
| 533 | out << _encoded.size(); | 601 | out << _encoded.size(); |
| 534 | out.writeAligned(_encoded); | 602 | out.writeAligned(_encoded); |
| 535 | } | 603 | } |
| 536 | 604 | ||
| 605 | void HeightfieldData::writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color) { | ||
| 606 | if (!reference || reference->getContents().size() != _contents.size()) { | ||
| 607 | write(out, color); | ||
| 608 | return; | ||
| 609 | } | ||
| 610 | QMutexLocker locker(&reference->_encodedDeltaMutex); | ||
| 611 | if (reference->_encodedDelta.isEmpty() || reference->_deltaData != this) { | ||
| 612 | QImage image; | ||
| 613 | int minX, minY; | ||
| 614 | if (color) { | ||
| 615 | int size = glm::sqrt(_contents.size() / (float)COLOR_BYTES); | ||
| 616 | minX = size; | ||
| 617 | minY = size; | ||
| 618 | int maxX = -1, maxY = -1; | ||
| 619 | const char* src = _contents.constData(); | ||
| 620 | const char* ref = reference->_contents.constData(); | ||
| 621 | for (int y = 0; y < size; y++) { | ||
| 622 | bool difference = false; | ||
| 623 | for (int x = 0; x < size; x++, src += COLOR_BYTES, ref += COLOR_BYTES) { | ||
| 624 | if (src[0] != ref[0] || src[1] != ref[1] || src[2] != ref[2]) { | ||
| 625 | minX = qMin(minX, x); | ||
| 626 | maxX = qMax(maxX, x); | ||
| 627 | difference = true; | ||
| 628 | } | ||
| 629 | } | ||
| 630 | if (difference) { | ||
| 631 | minY = qMin(minY, y); | ||
| 632 | maxY = qMax(maxY, y); | ||
| 633 | } | ||
| 634 | } | ||
| 635 | if (maxX >= minX) { | ||
| 636 | int width = maxX - minX + 1; | ||
| 637 | int height = maxY - minY + 1; | ||
| 638 | image = QImage(width, height, QImage::Format_RGB888); | ||
| 639 | src = _contents.constData() + (minY * size + minX) * COLOR_BYTES; | ||
| 640 | int srcStride = size * COLOR_BYTES; | ||
| 641 | int destStride = width * COLOR_BYTES; | ||
| 642 | for (int y = 0; y < height; y++) { | ||
| 643 | memcpy(image.scanLine(y), src, destStride); | ||
| 644 | src += srcStride; | ||
| 645 | } | ||
| 646 | } | ||
| 647 | } else { | ||
| 648 | int size = glm::sqrt((float)_contents.size()); | ||
| 649 | minX = size; | ||
| 650 | minY = size; | ||
| 651 | int maxX = -1, maxY = -1; | ||
| 652 | const char* src = _contents.constData(); | ||
| 653 | const char* ref = reference->_contents.constData(); | ||
| 654 | for (int y = 0; y < size; y++) { | ||
| 655 | bool difference = false; | ||
| 656 | for (int x = 0; x < size; x++) { | ||
| 657 | if (*src++ != *ref++) { | ||
| 658 | minX = qMin(minX, x); | ||
| 659 | maxX = qMax(maxX, x); | ||
| 660 | difference = true; | ||
| 661 | } | ||
| 662 | } | ||
| 663 | if (difference) { | ||
| 664 | minY = qMin(minY, y); | ||
| 665 | maxY = qMax(maxY, y); | ||
| 666 | } | ||
| 667 | } | ||
| 668 | if (maxX >= minX) { | ||
| 669 | int width = qMax(maxX - minX + 1, 0); | ||
| 670 | int height = qMax(maxY - minY + 1, 0); | ||
| 671 | image = QImage(width, height, QImage::Format_RGB888); | ||
| 672 | const uchar* lineSrc = (const uchar*)_contents.constData() + minY * size + minX; | ||
| 673 | for (int y = 0; y < height; y++) { | ||
| 674 | uchar* dest = image.scanLine(y); | ||
| 675 | for (const uchar* src = lineSrc, *end = src + width; src != end; src++) { | ||
| 676 | *dest++ = *src; | ||
| 677 | *dest++ = *src; | ||
| 678 | *dest++ = *src; | ||
| 679 | } | ||
| 680 | lineSrc += size; | ||
| 681 | } | ||
| 682 | } | ||
| 683 | } | ||
| 684 | image.setOffset(QPoint(minX + 1, minY + 1)); | ||
| 685 | reference->_encodedDelta = encodeHeightfieldImage(image); | ||
| 686 | reference->_deltaData = this; | ||
| 687 | } | ||
| 688 | out << reference->_encodedDelta.size(); | ||
| 689 | out.writeAligned(reference->_encodedDelta); | ||
| 690 | } | ||
| 691 | |||
| 692 | void HeightfieldData::read(Bitstream& in, int bytes, bool color) { | ||
| 693 | set(decodeHeightfieldImage(_encoded = in.readAligned(bytes)).convertToFormat(QImage::Format_RGB888), color); | ||
| 694 | } | ||
| 695 | |||
| 696 | void HeightfieldData::set(const QImage& image, bool color) { | ||
| 697 | if (color) { | ||
| 698 | _contents.resize(image.width() * image.height() * COLOR_BYTES); | ||
| 699 | memcpy(_contents.data(), image.constBits(), _contents.size()); | ||
| 700 | |||
| 701 | } else { | ||
| 702 | _contents.resize(image.width() * image.height()); | ||
| 703 | char* dest = _contents.data(); | ||
| 704 | for (const uchar* src = image.constBits(), *end = src + _contents.size() * COLOR_BYTES; | ||
| 705 | src != end; src += COLOR_BYTES) { | ||
| 706 | *dest++ = *src; | ||
| 707 | } | ||
| 708 | } | ||
| 709 | } | ||
| 710 | |||
| 537 | HeightfieldAttribute::HeightfieldAttribute(const QString& name) : | 711 | HeightfieldAttribute::HeightfieldAttribute(const QString& name) : |
| 538 | InlineAttribute<HeightfieldDataPointer>(name) { | 712 | InlineAttribute<HeightfieldDataPointer>(name) { |
| 539 | } | 713 | } |
| 540 | 714 | ||
| 541 | void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { | 715 | void HeightfieldAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { |
| 542 | if (isLeaf) { | 716 | if (!isLeaf) { |
| 543 | int size; | 717 | return; |
| 544 | in >> size; | 718 | } |
| 545 | if (size == 0) { | 719 | int size; |
| 546 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); | 720 | in >> size; |
| 547 | } else { | 721 | if (size == 0) { |
| 548 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false)); | 722 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); |
| 549 | } | 723 | } else { |
| 724 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, false)); | ||
| 550 | } | 725 | } |
| 551 | } | 726 | } |
| 552 | 727 | ||
| 553 | void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const { | 728 | void HeightfieldAttribute::write(Bitstream& out, void* value, bool isLeaf) const { |
| 554 | if (isLeaf) { | 729 | if (!isLeaf) { |
| 555 | HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value); | 730 | return; |
| 556 | if (data) { | 731 | } |
| 557 | data->write(out, false); | 732 | HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value); |
| 558 | } else { | 733 | if (data) { |
| 559 | out << 0; | 734 | data->write(out, false); |
| 560 | } | 735 | } else { |
| 736 | out << 0; | ||
| 737 | } | ||
| 738 | } | ||
| 739 | |||
| 740 | void HeightfieldAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { | ||
| 741 | if (!isLeaf) { | ||
| 742 | return; | ||
| 743 | } | ||
| 744 | int size; | ||
| 745 | in >> size; | ||
| 746 | if (size == 0) { | ||
| 747 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); | ||
| 748 | } else { | ||
| 749 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData( | ||
| 750 | in, size, decodeInline<HeightfieldDataPointer>(reference), false)); | ||
| 751 | } | ||
| 752 | } | ||
| 753 | |||
| 754 | void HeightfieldAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { | ||
| 755 | if (!isLeaf) { | ||
| 756 | return; | ||
| 757 | } | ||
| 758 | HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value); | ||
| 759 | if (data) { | ||
| 760 | data->writeDelta(out, decodeInline<HeightfieldDataPointer>(reference), false); | ||
| 761 | } else { | ||
| 762 | out << 0; | ||
| 561 | } | 763 | } |
| 562 | } | 764 | } |
| 563 | 765 | ||
| @@ -635,25 +837,53 @@ HeightfieldColorAttribute::HeightfieldColorAttribute(const QString& name) : · 71 unmodified lines | |||
| 635 | } | 837 | } |
| 636 | 838 | ||
| 637 | void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { | 839 | void HeightfieldColorAttribute::read(Bitstream& in, void*& value, bool isLeaf) const { |
| 638 | if (isLeaf) { | 840 | if (!isLeaf) { |
| 639 | int size; | 841 | return; |
| 640 | in >> size; | 842 | } |
| 641 | if (size == 0) { | 843 | int size; |
| 642 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); | 844 | in >> size; |
| 643 | } else { | 845 | if (size == 0) { |
| 644 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true)); | 846 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); |
| 645 | } | 847 | } else { |
| 848 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData(in, size, true)); | ||
| 646 | } | 849 | } |
| 647 | } | 850 | } |
| 648 | 851 | ||
| 649 | void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const { | 852 | void HeightfieldColorAttribute::write(Bitstream& out, void* value, bool isLeaf) const { |
| 650 | if (isLeaf) { | 853 | if (!isLeaf) { |
| 651 | HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value); | 854 | return; |
| 652 | if (data) { | 855 | } |
| 653 | data->write(out, true); | 856 | HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value); |
| 654 | } else { | 857 | if (data) { |
| 655 | out << 0; | 858 | data->write(out, true); |
| 656 | } | 859 | } else { |
| 860 | out << 0; | ||
| 861 | } | ||
| 862 | } | ||
| 863 | |||
| 864 | void HeightfieldColorAttribute::readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const { | ||
| 865 | if (!isLeaf) { | ||
| 866 | return; | ||
| 867 | } | ||
| 868 | int size; | ||
| 869 | in >> size; | ||
| 870 | if (size == 0) { | ||
| 871 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(); | ||
| 872 | } else { | ||
| 873 | *(HeightfieldDataPointer*)&value = HeightfieldDataPointer(new HeightfieldData( | ||
| 874 | in, size, decodeInline<HeightfieldDataPointer>(reference), true)); | ||
| 875 | } | ||
| 876 | } | ||
| 877 | |||
| 878 | void HeightfieldColorAttribute::writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const { | ||
| 879 | if (!isLeaf) { | ||
| 880 | return; | ||
| 881 | } | ||
| 882 | HeightfieldDataPointer data = decodeInline<HeightfieldDataPointer>(value); | ||
| 883 | if (data) { | ||
| 884 | data->writeDelta(out, decodeInline<HeightfieldDataPointer>(reference), true); | ||
| 885 | } else { | ||
| 886 | out << 0; | ||
| 657 | } | 887 | } |
| 658 | } | 888 | } |
| 659 | 889 | ||
| @@ -669,8 +899,8 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post · 9 unmodified lines | |||
| 669 | *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(); | 899 | *(HeightfieldDataPointer*)&parent = HeightfieldDataPointer(); |
| 670 | return true; | 900 | return true; |
| 671 | } | 901 | } |
| 672 | int size = glm::sqrt(maxSize / (float)BYTES_PER_PIXEL); | 902 | int size = glm::sqrt(maxSize / (float)HeightfieldData::COLOR_BYTES); |
| 673 | QByteArray contents(size * size * BYTES_PER_PIXEL, 0); | 903 | QByteArray contents(size * size * HeightfieldData::COLOR_BYTES, 0); |
| 674 | int halfSize = size / 2; | 904 | int halfSize = size / 2; |
| 675 | for (int i = 0; i < MERGE_COUNT; i++) { | 905 | for (int i = 0; i < MERGE_COUNT; i++) { |
| 676 | HeightfieldDataPointer child = decodeInline<HeightfieldDataPointer>(children[i]); | 906 | HeightfieldDataPointer child = decodeInline<HeightfieldDataPointer>(children[i]); |
| @@ -678,7 +908,7 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post · 1 unmodified line | |||
| 678 | continue; | 908 | continue; |
| 679 | } | 909 | } |
| 680 | const QByteArray& childContents = child->getContents(); | 910 | const QByteArray& childContents = child->getContents(); |
| 681 | int childSize = glm::sqrt(childContents.size() / (float)BYTES_PER_PIXEL); | 911 | int childSize = glm::sqrt(childContents.size() / (float)HeightfieldData::COLOR_BYTES); |
| 682 | const int INDEX_MASK = 1; | 912 | const int INDEX_MASK = 1; |
| 683 | int xIndex = i & INDEX_MASK; | 913 | int xIndex = i & INDEX_MASK; |
| 684 | const int Y_SHIFT = 1; | 914 | const int Y_SHIFT = 1; |
| @@ -688,24 +918,25 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post · 3 unmodified lines | |||
| 688 | } | 918 | } |
| 689 | int Z_SHIFT = 2; | 919 | int Z_SHIFT = 2; |
| 690 | int zIndex = (i >> Z_SHIFT) & INDEX_MASK; | 920 | int zIndex = (i >> Z_SHIFT) & INDEX_MASK; |
| 691 | char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * BYTES_PER_PIXEL; | 921 | char* dest = contents.data() + ((zIndex * halfSize * size) + (xIndex * halfSize)) * HeightfieldData::COLOR_BYTES; |
| 692 | uchar* src = (uchar*)childContents.data(); | 922 | uchar* src = (uchar*)childContents.data(); |
| 693 | int childStride = childSize * BYTES_PER_PIXEL; | 923 | int childStride = childSize * HeightfieldData::COLOR_BYTES; |
| 694 | int stride = size * BYTES_PER_PIXEL; | 924 | int stride = size * HeightfieldData::COLOR_BYTES; |
| 695 | int halfStride = stride / 2; | 925 | int halfStride = stride / 2; |
| 696 | int childStep = 2 * BYTES_PER_PIXEL; | 926 | int childStep = 2 * HeightfieldData::COLOR_BYTES; |
| 697 | int redOffset3 = childStride + BYTES_PER_PIXEL; | 927 | int redOffset3 = childStride + HeightfieldData::COLOR_BYTES; |
| 698 | int greenOffset1 = BYTES_PER_PIXEL + 1; | 928 | int greenOffset1 = HeightfieldData::COLOR_BYTES + 1; |
| 699 | int greenOffset2 = childStride + 1; | 929 | int greenOffset2 = childStride + 1; |
| 700 | int greenOffset3 = childStride + BYTES_PER_PIXEL + 1; | 930 | int greenOffset3 = childStride + HeightfieldData::COLOR_BYTES + 1; |
| 701 | int blueOffset1 = BYTES_PER_PIXEL + 2; | 931 | int blueOffset1 = HeightfieldData::COLOR_BYTES + 2; |
| 702 | int blueOffset2 = childStride + 2; | 932 | int blueOffset2 = childStride + 2; |
| 703 | int blueOffset3 = childStride + BYTES_PER_PIXEL + 2; | 933 | int blueOffset3 = childStride + HeightfieldData::COLOR_BYTES + 2; |
| 704 | if (childSize == size) { | 934 | if (childSize == size) { |
| 705 | // simple case: one destination value for four child values | 935 | // simple case: one destination value for four child values |
| 706 | for (int z = 0; z < halfSize; z++) { | 936 | for (int z = 0; z < halfSize; z++) { |
| 707 | for (char* end = dest + halfSize * BYTES_PER_PIXEL; dest != end; src += childStep) { | 937 | for (char* end = dest + halfSize * HeightfieldData::COLOR_BYTES; dest != end; src += childStep) { |
| 708 | *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; | 938 | *dest++ = ((int)src[0] + (int)src[HeightfieldData::COLOR_BYTES] + |
| 939 | (int)src[childStride] + (int)src[redOffset3]) >> 2; | ||
| 709 | *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; | 940 | *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; |
| 710 | *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; | 941 | *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; |
| 711 | } | 942 | } |
| @@ -717,13 +948,14 @@ bool HeightfieldColorAttribute::merge(void*& parent, void* children[], bool post · 5 unmodified lines | |||
| 717 | int halfChildSize = childSize / 2; | 948 | int halfChildSize = childSize / 2; |
| 718 | int destPerSrc = size / childSize; | 949 | int destPerSrc = size / childSize; |
| 719 | for (int z = 0; z < halfChildSize; z++) { | 950 | for (int z = 0; z < halfChildSize; z++) { |
| 720 | for (uchar* end = src + childSize * BYTES_PER_PIXEL; src != end; src += childStep) { | 951 | for (uchar* end = src + childSize * HeightfieldData::COLOR_BYTES; src != end; src += childStep) { |
| 721 | *dest++ = ((int)src[0] + (int)src[BYTES_PER_PIXEL] + (int)src[childStride] + (int)src[redOffset3]) >> 2; | 952 | *dest++ = ((int)src[0] + (int)src[HeightfieldData::COLOR_BYTES] + |
| 953 | (int)src[childStride] + (int)src[redOffset3]) >> 2; | ||
| 722 | *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; | 954 | *dest++ = ((int)src[1] + (int)src[greenOffset1] + (int)src[greenOffset2] + (int)src[greenOffset3]) >> 2; |
| 723 | *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; | 955 | *dest++ = ((int)src[2] + (int)src[blueOffset1] + (int)src[blueOffset2] + (int)src[blueOffset3]) >> 2; |
| 724 | for (int j = 1; j < destPerSrc; j++) { | 956 | for (int j = 1; j < destPerSrc; j++) { |
| 725 | memcpy(dest, dest - BYTES_PER_PIXEL, BYTES_PER_PIXEL); | 957 | memcpy(dest, dest - HeightfieldData::COLOR_BYTES, HeightfieldData::COLOR_BYTES); |
| 726 | dest += BYTES_PER_PIXEL; | 958 | dest += HeightfieldData::COLOR_BYTES; |
| 727 | } | 959 | } |
| 728 | } | 960 | } |
| 729 | dest += halfStride; | 961 | dest += halfStride; |
| @@ -28,6 +28,7 @@ class QScriptEngine; · 27 unmodified lines | |||
| 28 | class QScriptValue; | 28 | class QScriptValue; |
| 29 | 29 | ||
| 30 | class Attribute; | 30 | class Attribute; |
| 31 | class HeightfieldData; | ||
| 31 | class MetavoxelData; | 32 | class MetavoxelData; |
| 32 | class MetavoxelLOD; | 33 | class MetavoxelLOD; |
| 33 | class MetavoxelNode; | 34 | class MetavoxelNode; |
| @@ -421,26 +422,37 @@ public: · 387 unmodified lines | |||
| 421 | virtual AttributeValue inherit(const AttributeValue& parentValue) const; | 422 | virtual AttributeValue inherit(const AttributeValue& parentValue) const; |
| 422 | }; | 423 | }; |
| 423 | 424 | ||
| 425 | typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer; | ||
| 426 | |||
| 424 | /// Contains a block of heightfield data. | 427 | /// Contains a block of heightfield data. |
| 425 | class HeightfieldData : public QSharedData { | 428 | class HeightfieldData : public QSharedData { |
| 426 | public: | 429 | public: |
| 427 | 430 | ||
| 431 | static const int COLOR_BYTES = 3; | ||
| 432 | |||
| 428 | HeightfieldData(const QByteArray& contents); | 433 | HeightfieldData(const QByteArray& contents); |
| 429 | HeightfieldData(Bitstream& in, int bytes, bool color); | 434 | HeightfieldData(Bitstream& in, int bytes, bool color); |
| 430 | 435 | HeightfieldData(Bitstream& in, int bytes, const HeightfieldDataPointer& reference, bool color); | |
| 436 | |||
| 431 | const QByteArray& getContents() const { return _contents; } | 437 | const QByteArray& getContents() const { return _contents; } |
| 432 | 438 | ||
| 433 | void write(Bitstream& out, bool color); | 439 | void write(Bitstream& out, bool color); |
| 440 | void writeDelta(Bitstream& out, const HeightfieldDataPointer& reference, bool color); | ||
| 434 | 441 | ||
| 435 | private: | 442 | private: |
| 436 | 443 | ||
| 444 | void read(Bitstream& in, int bytes, bool color); | ||
| 445 | void set(const QImage& image, bool color); | ||
| 446 | |||
| 437 | QByteArray _contents; | 447 | QByteArray _contents; |
| 438 | QByteArray _encoded; | 448 | QByteArray _encoded; |
| 439 | QMutex _encodedMutex; | 449 | QMutex _encodedMutex; |
| 450 | |||
| 451 | HeightfieldDataPointer _deltaData; | ||
| 452 | QByteArray _encodedDelta; | ||
| 453 | QMutex _encodedDeltaMutex; | ||
| 440 | }; | 454 | }; |
| 441 | 455 | ||
| 442 | typedef QExplicitlySharedDataPointer<HeightfieldData> HeightfieldDataPointer; | ||
| 443 | |||
| 444 | /// An attribute that stores heightfield data. | 456 | /// An attribute that stores heightfield data. |
| 445 | class HeightfieldAttribute : public InlineAttribute<HeightfieldDataPointer> { | 457 | class HeightfieldAttribute : public InlineAttribute<HeightfieldDataPointer> { |
| 446 | Q_OBJECT | 458 | Q_OBJECT |
| @@ -451,7 +463,10 @@ public: · 4 unmodified lines | |||
| 451 | 463 | ||
| 452 | virtual void read(Bitstream& in, void*& value, bool isLeaf) const; | 464 | virtual void read(Bitstream& in, void*& value, bool isLeaf) const; |
| 453 | virtual void write(Bitstream& out, void* value, bool isLeaf) const; | 465 | virtual void write(Bitstream& out, void* value, bool isLeaf) const; |
| 454 | 466 | ||
| 467 | virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const; | ||
| 468 | virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const; | ||
| 469 | |||
| 455 | virtual bool merge(void*& parent, void* children[], bool postRead = false) const; | 470 | virtual bool merge(void*& parent, void* children[], bool postRead = false) const; |
| 456 | }; | 471 | }; |
| 457 | 472 | ||
| @@ -466,6 +481,9 @@ public: · 8 unmodified lines | |||
| 466 | virtual void read(Bitstream& in, void*& value, bool isLeaf) const; | 481 | virtual void read(Bitstream& in, void*& value, bool isLeaf) const; |
| 467 | virtual void write(Bitstream& out, void* value, bool isLeaf) const; | 482 | virtual void write(Bitstream& out, void* value, bool isLeaf) const; |
| 468 | 483 | ||
| 484 | virtual void readDelta(Bitstream& in, void*& value, void* reference, bool isLeaf) const; | ||
| 485 | virtual void writeDelta(Bitstream& out, void* value, void* reference, bool isLeaf) const; | ||
| 486 | |||
| 469 | virtual bool merge(void*& parent, void* children[], bool postRead = false) const; | 487 | virtual bool merge(void*& parent, void* children[], bool postRead = false) const; |
| 470 | }; | 488 | }; |
| 471 | 489 | ||
| @@ -318,3 +318,177 @@ SetDataEdit::SetDataEdit(const glm::vec3& minimum, const MetavoxelData& data, bo · 317 unmodified lines | |||
| 318 | void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { | 318 | void SetDataEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { |
| 319 | data.set(minimum, this->data, blend); | 319 | data.set(minimum, this->data, blend); |
| 320 | } | 320 | } |
| 321 | |||
| 322 | PaintHeightfieldHeightEdit::PaintHeightfieldHeightEdit(const glm::vec3& position, float radius, float height) : | ||
| 323 | position(position), | ||
| 324 | radius(radius), | ||
| 325 | height(height) { | ||
| 326 | } | ||
| 327 | |||
| 328 | class PaintHeightfieldHeightEditVisitor : public MetavoxelVisitor { | ||
| 329 | public: | ||
| 330 | |||
| 331 | PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit); | ||
| 332 | |||
| 333 | virtual int visit(MetavoxelInfo& info); | ||
| 334 | |||
| 335 | private: | ||
| 336 | |||
| 337 | PaintHeightfieldHeightEdit _edit; | ||
| 338 | Box _bounds; | ||
| 339 | }; | ||
| 340 | |||
| 341 | PaintHeightfieldHeightEditVisitor::PaintHeightfieldHeightEditVisitor(const PaintHeightfieldHeightEdit& edit) : | ||
| 342 | MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute(), | ||
| 343 | QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldAttribute()), | ||
| 344 | _edit(edit) { | ||
| 345 | |||
| 346 | glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius); | ||
| 347 | _bounds = Box(_edit.position - extents, _edit.position + extents); | ||
| 348 | } | ||
| 349 | |||
| 350 | int PaintHeightfieldHeightEditVisitor::visit(MetavoxelInfo& info) { | ||
| 351 | if (!info.getBounds().intersects(_bounds)) { | ||
| 352 | return STOP_RECURSION; | ||
| 353 | } | ||
| 354 | if (!info.isLeaf) { | ||
| 355 | return DEFAULT_ORDER; | ||
| 356 | } | ||
| 357 | HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>(); | ||
| 358 | if (!pointer) { | ||
| 359 | return STOP_RECURSION; | ||
| 360 | } | ||
| 361 | QByteArray contents(pointer->getContents()); | ||
| 362 | int size = glm::sqrt((float)contents.size()); | ||
| 363 | int highest = size - 1; | ||
| 364 | float heightScale = size / info.size; | ||
| 365 | |||
| 366 | glm::vec3 center = (_edit.position - info.minimum) * heightScale; | ||
| 367 | float scaledRadius = _edit.radius * heightScale; | ||
| 368 | glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius); | ||
| 369 | |||
| 370 | glm::vec3 start = glm::floor(center - extents); | ||
| 371 | glm::vec3 end = glm::ceil(center + extents); | ||
| 372 | |||
| 373 | // raise/lower all points within the radius | ||
| 374 | float z = qMax(start.z, 0.0f); | ||
| 375 | float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest); | ||
| 376 | uchar* lineDest = (uchar*)contents.data() + (int)z * size + (int)startX; | ||
| 377 | float squaredRadius = scaledRadius * scaledRadius; | ||
| 378 | float squaredRadiusReciprocal = 1.0f / squaredRadius; | ||
| 379 | const int EIGHT_BIT_MAXIMUM = 255; | ||
| 380 | float scaledHeight = _edit.height * EIGHT_BIT_MAXIMUM / info.size; | ||
| 381 | bool changed = false; | ||
| 382 | for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) { | ||
| 383 | uchar* dest = lineDest; | ||
| 384 | for (float x = startX; x <= endX; x += 1.0f, dest++) { | ||
| 385 | float dx = x - center.x, dz = z - center.z; | ||
| 386 | float distanceSquared = dx * dx + dz * dz; | ||
| 387 | if (distanceSquared <= squaredRadius) { | ||
| 388 | // height falls off towards edges | ||
| 389 | int value = *dest + scaledHeight * (squaredRadius - distanceSquared) * squaredRadiusReciprocal; | ||
| 390 | if (value != *dest) { | ||
| 391 | *dest = qMin(qMax(value, 0), EIGHT_BIT_MAXIMUM); | ||
| 392 | changed = true; | ||
| 393 | } | ||
| 394 | } | ||
| 395 | } | ||
| 396 | lineDest += size; | ||
| 397 | } | ||
| 398 | if (changed) { | ||
| 399 | HeightfieldDataPointer newPointer(new HeightfieldData(contents)); | ||
| 400 | info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer)); | ||
| 401 | } | ||
| 402 | return STOP_RECURSION; | ||
| 403 | } | ||
| 404 | |||
| 405 | void PaintHeightfieldHeightEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { | ||
| 406 | PaintHeightfieldHeightEditVisitor visitor(*this); | ||
| 407 | data.guide(visitor); | ||
| 408 | } | ||
| 409 | |||
| 410 | PaintHeightfieldColorEdit::PaintHeightfieldColorEdit(const glm::vec3& position, float radius, const QColor& color) : | ||
| 411 | position(position), | ||
| 412 | radius(radius), | ||
| 413 | color(color) { | ||
| 414 | } | ||
| 415 | |||
| 416 | class PaintHeightfieldColorEditVisitor : public MetavoxelVisitor { | ||
| 417 | public: | ||
| 418 | |||
| 419 | PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit); | ||
| 420 | |||
| 421 | virtual int visit(MetavoxelInfo& info); | ||
| 422 | |||
| 423 | private: | ||
| 424 | |||
| 425 | PaintHeightfieldColorEdit _edit; | ||
| 426 | Box _bounds; | ||
| 427 | }; | ||
| 428 | |||
| 429 | PaintHeightfieldColorEditVisitor::PaintHeightfieldColorEditVisitor(const PaintHeightfieldColorEdit& edit) : | ||
| 430 | MetavoxelVisitor(QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute(), | ||
| 431 | QVector<AttributePointer>() << AttributeRegistry::getInstance()->getHeightfieldColorAttribute()), | ||
| 432 | _edit(edit) { | ||
| 433 | |||
| 434 | glm::vec3 extents(_edit.radius, _edit.radius, _edit.radius); | ||
| 435 | _bounds = Box(_edit.position - extents, _edit.position + extents); | ||
| 436 | } | ||
| 437 | |||
| 438 | int PaintHeightfieldColorEditVisitor::visit(MetavoxelInfo& info) { | ||
| 439 | if (!info.getBounds().intersects(_bounds)) { | ||
| 440 | return STOP_RECURSION; | ||
| 441 | } | ||
| 442 | if (!info.isLeaf) { | ||
| 443 | return DEFAULT_ORDER; | ||
| 444 | } | ||
| 445 | HeightfieldDataPointer pointer = info.inputValues.at(0).getInlineValue<HeightfieldDataPointer>(); | ||
| 446 | if (!pointer) { | ||
| 447 | return STOP_RECURSION; | ||
| 448 | } | ||
| 449 | QByteArray contents(pointer->getContents()); | ||
| 450 | const int BYTES_PER_PIXEL = 3; | ||
| 451 | int size = glm::sqrt((float)contents.size() / BYTES_PER_PIXEL); | ||
| 452 | int highest = size - 1; | ||
| 453 | float heightScale = size / info.size; | ||
| 454 | |||
| 455 | glm::vec3 center = (_edit.position - info.minimum) * heightScale; | ||
| 456 | float scaledRadius = _edit.radius * heightScale; | ||
| 457 | glm::vec3 extents(scaledRadius, scaledRadius, scaledRadius); | ||
| 458 | |||
| 459 | glm::vec3 start = glm::floor(center - extents); | ||
| 460 | glm::vec3 end = glm::ceil(center + extents); | ||
| 461 | |||
| 462 | // paint all points within the radius | ||
| 463 | float z = qMax(start.z, 0.0f); | ||
| 464 | float startX = qMax(start.x, 0.0f), endX = qMin(end.x, (float)highest); | ||
| 465 | int stride = size * BYTES_PER_PIXEL; | ||
| 466 | char* lineDest = contents.data() + (int)z * stride + (int)startX * BYTES_PER_PIXEL; | ||
| 467 | float squaredRadius = scaledRadius * scaledRadius; | ||
| 468 | char red = _edit.color.red(), green = _edit.color.green(), blue = _edit.color.blue(); | ||
| 469 | bool changed = false; | ||
| 470 | for (float endZ = qMin(end.z, (float)highest); z <= endZ; z += 1.0f) { | ||
| 471 | char* dest = lineDest; | ||
| 472 | for (float x = startX; x <= endX; x += 1.0f, dest += BYTES_PER_PIXEL) { | ||
| 473 | float dx = x - center.x, dz = z - center.z; | ||
| 474 | if (dx * dx + dz * dz <= squaredRadius) { | ||
| 475 | dest[0] = red; | ||
| 476 | dest[1] = green; | ||
| 477 | dest[2] = blue; | ||
| 478 | changed = true; | ||
| 479 | } | ||
| 480 | } | ||
| 481 | lineDest += stride; | ||
| 482 | } | ||
| 483 | if (changed) { | ||
| 484 | HeightfieldDataPointer newPointer(new HeightfieldData(contents)); | ||
| 485 | info.outputValues[0] = AttributeValue(_outputs.at(0), encodeInline<HeightfieldDataPointer>(newPointer)); | ||
| 486 | } | ||
| 487 | return STOP_RECURSION; | ||
| 488 | } | ||
| 489 | |||
| 490 | void PaintHeightfieldColorEdit::apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const { | ||
| 491 | PaintHeightfieldColorEditVisitor visitor(*this); | ||
| 492 | data.guide(visitor); | ||
| 493 | } | ||
| 494 | |||
| @@ -207,4 +207,38 @@ public: · 206 unmodified lines | |||
| 207 | 207 | ||
| 208 | DECLARE_STREAMABLE_METATYPE(SetDataEdit) | 208 | DECLARE_STREAMABLE_METATYPE(SetDataEdit) |
| 209 | 209 | ||
| 210 | /// An edit that sets a region of a heightfield height. | ||
| 211 | class PaintHeightfieldHeightEdit : public MetavoxelEdit { | ||
| 212 | STREAMABLE | ||
| 213 | |||
| 214 | public: | ||
| 215 | |||
| 216 | STREAM glm::vec3 position; | ||
| 217 | STREAM float radius; | ||
| 218 | STREAM float height; | ||
| 219 | |||
| 220 | PaintHeightfieldHeightEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, float height = 0.0f); | ||
| 221 | |||
| 222 | virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; | ||
| 223 | }; | ||
| 224 | |||
| 225 | DECLARE_STREAMABLE_METATYPE(PaintHeightfieldHeightEdit) | ||
| 226 | |||
| 227 | /// An edit that sets a region of a heightfield color. | ||
| 228 | class PaintHeightfieldColorEdit : public MetavoxelEdit { | ||
| 229 | STREAMABLE | ||
| 230 | |||
| 231 | public: | ||
| 232 | |||
| 233 | STREAM glm::vec3 position; | ||
| 234 | STREAM float radius; | ||
| 235 | STREAM QColor color; | ||
| 236 | |||
| 237 | PaintHeightfieldColorEdit(const glm::vec3& position = glm::vec3(), float radius = 0.0f, const QColor& color = QColor()); | ||
| 238 | |||
| 239 | virtual void apply(MetavoxelData& data, const WeakSharedObjectHash& objects) const; | ||
| 240 | }; | ||
| 241 | |||
| 242 | DECLARE_STREAMABLE_METATYPE(PaintHeightfieldColorEdit) | ||
| 243 | |||
| 210 | #endif // hifi_MetavoxelMessages_h | 244 | #endif // hifi_MetavoxelMessages_h |
| @@ -24,6 +24,8 @@ · 23 unmodified lines | |||
| 24 | #include <QVBoxLayout> | 24 | #include <QVBoxLayout> |
| 25 | #include <QtDebug> | 25 | #include <QtDebug> |
| 26 | 26 | ||
| 27 | #include <GLMHelpers.h> | ||
| 28 | |||
| 27 | #include "MetavoxelUtil.h" | 29 | #include "MetavoxelUtil.h" |
| 28 | #include "ScriptCache.h" | 30 | #include "ScriptCache.h" |
| 29 | #include "StreamUtils.h" | 31 | #include "StreamUtils.h" |
| @@ -162,6 +164,11 @@ Box::Box(const glm::vec3& minimum, const glm::vec3& maximum) : · 132 unmodified lines | |||
| 162 | minimum(minimum), maximum(maximum) { | 164 | minimum(minimum), maximum(maximum) { |
| 163 | } | 165 | } |
| 164 | 166 | ||
| 167 | void Box::add(const Box& other) { | ||
| 168 | minimum = glm::min(minimum, other.minimum); | ||
| 169 | maximum = glm::max(maximum, other.maximum); | ||
| 170 | } | ||
| 171 | |||
| 165 | bool Box::contains(const glm::vec3& point) const { | 172 | bool Box::contains(const glm::vec3& point) const { |
| 166 | return point.x >= minimum.x && point.x <= maximum.x && | 173 | return point.x >= minimum.x && point.x <= maximum.x && |
| 167 | point.y >= minimum.y && point.y <= maximum.y && | 174 | point.y >= minimum.y && point.y <= maximum.y && |
| @@ -180,6 +187,14 @@ bool Box::intersects(const Box& other) const { · 12 unmodified lines | |||
| 180 | other.maximum.z >= minimum.z && other.minimum.z <= maximum.z; | 187 | other.maximum.z >= minimum.z && other.minimum.z <= maximum.z; |
| 181 | } | 188 | } |
| 182 | 189 | ||
| 190 | Box Box::getIntersection(const Box& other) const { | ||
| 191 | return Box(glm::max(minimum, other.minimum), glm::min(maximum, other.maximum)); | ||
| 192 | } | ||
| 193 | |||
| 194 | bool Box::isEmpty() const { | ||
| 195 | return minimum.x >= maximum.x || minimum.y >= maximum.y || minimum.z >= maximum.z; | ||
| 196 | } | ||
| 197 | |||
| 183 | const int X_MAXIMUM_FLAG = 1; | 198 | const int X_MAXIMUM_FLAG = 1; |
| 184 | const int Y_MAXIMUM_FLAG = 2; | 199 | const int Y_MAXIMUM_FLAG = 2; |
| 185 | const int Z_MAXIMUM_FLAG = 4; | 200 | const int Z_MAXIMUM_FLAG = 4; |
| @@ -44,12 +44,18 @@ public: · 43 unmodified lines | |||
| 44 | 44 | ||
| 45 | explicit Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3()); | 45 | explicit Box(const glm::vec3& minimum = glm::vec3(), const glm::vec3& maximum = glm::vec3()); |
| 46 | 46 | ||
| 47 | void add(const Box& other); | ||
| 48 | |||
| 47 | bool contains(const glm::vec3& point) const; | 49 | bool contains(const glm::vec3& point) const; |
| 48 | 50 | ||
| 49 | bool contains(const Box& other) const; | 51 | bool contains(const Box& other) const; |
| 50 | 52 | ||
| 51 | bool intersects(const Box& other) const; | 53 | bool intersects(const Box& other) const; |
| 52 | 54 | ||
| 55 | Box getIntersection(const Box& other) const; | ||
| 56 | |||
| 57 | bool isEmpty() const; | ||
| 58 | |||
| 53 | float getLongestSide() const { return qMax(qMax(maximum.x - minimum.x, maximum.y - minimum.y), maximum.z - minimum.z); } | 59 | float getLongestSide() const { return qMax(qMax(maximum.x - minimum.x, maximum.y - minimum.y), maximum.z - minimum.z); } |
| 54 | 60 | ||
| 55 | glm::vec3 getVertex(int index) const; | 61 | glm::vec3 getVertex(int index) const; |
| @@ -138,6 +144,8 @@ public: · 82 unmodified lines | |||
| 138 | 144 | ||
| 139 | QColorEditor(QWidget* parent); | 145 | QColorEditor(QWidget* parent); |
| 140 | 146 | ||
| 147 | const QColor& getColor() const { return _color; } | ||
| 148 | |||
| 141 | signals: | 149 | signals: |
| 142 | 150 | ||
| 143 | void colorChanged(const QColor& color); | 151 | void colorChanged(const QColor& color); |
| @@ -1,21 +1,14 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | set(TARGET_NAME networking) | 1 | set(TARGET_NAME networking) |
| 5 | project(${TARGET_NAME}) | ||
| 6 | |||
| 7 | find_package(Qt5 COMPONENTS Network) | ||
| 8 | 2 | ||
| 9 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 10 | setup_hifi_library(${TARGET_NAME}) | 4 | setup_hifi_library(Network) |
| 11 | 5 | ||
| 12 | # include GLM | 6 | link_hifi_libraries(shared) |
| 13 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 14 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 15 | 7 | ||
| 16 | target_link_libraries(${TARGET_NAME} Qt5::Network) | ||
| 17 | |||
| 18 | # add a definition for ssize_t so that windows doesn't bail | ||
| 19 | if (WIN32) | 8 | if (WIN32) |
| 20 | add_definitions(-Dssize_t=long) | 9 | # we need ws2_32.lib on windows, but it's static so we don't bubble it up |
| 21 | endif () | 10 | target_link_libraries(${TARGET_NAME} ws2_32.lib) |
| 11 | endif () | ||
| 12 | |||
| 13 | # call macro to link our dependencies and bubble them up via a property on our target | ||
| 14 | link_shared_dependencies() | ||
| @@ -36,6 +36,7 @@ DomainHandler::DomainHandler(QObject* parent) : · 35 unmodified lines | |||
| 36 | void DomainHandler::clearConnectionInfo() { | 36 | void DomainHandler::clearConnectionInfo() { |
| 37 | _uuid = QUuid(); | 37 | _uuid = QUuid(); |
| 38 | _isConnected = false; | 38 | _isConnected = false; |
| 39 | emit disconnectedFromDomain(); | ||
| 39 | 40 | ||
| 40 | if (_handshakeTimer) { | 41 | if (_handshakeTimer) { |
| 41 | _handshakeTimer->stop(); | 42 | _handshakeTimer->stop(); |
| @@ -129,6 +130,8 @@ void DomainHandler::setIsConnected(bool isConnected) { · 87 unmodified lines | |||
| 129 | 130 | ||
| 130 | // we've connected to new domain - time to ask it for global settings | 131 | // we've connected to new domain - time to ask it for global settings |
| 131 | requestDomainSettings(); | 132 | requestDomainSettings(); |
| 133 | } else { | ||
| 134 | emit disconnectedFromDomain(); | ||
| 132 | } | 135 | } |
| 133 | } | 136 | } |
| 134 | } | 137 | } |
| @@ -196,4 +199,4 @@ void DomainHandler::parseDTLSRequirementPacket(const QByteArray& dtlsRequirement · 61 unmodified lines | |||
| 196 | _sockAddr.setPort(dtlsPort); | 199 | _sockAddr.setPort(dtlsPort); |
| 197 | 200 | ||
| 198 | // initializeDTLSSession(); | 201 | // initializeDTLSSession(); |
| 199 | } | 202 | } |
| @@ -70,6 +70,7 @@ private slots: · 69 unmodified lines | |||
| 70 | signals: | 70 | signals: |
| 71 | void hostnameChanged(const QString& hostname); | 71 | void hostnameChanged(const QString& hostname); |
| 72 | void connectedToDomain(const QString& hostname); | 72 | void connectedToDomain(const QString& hostname); |
| 73 | void disconnectedFromDomain(); | ||
| 73 | 74 | ||
| 74 | void settingsReceived(const QJsonObject& domainSettingsObject); | 75 | void settingsReceived(const QJsonObject& domainSettingsObject); |
| 75 | void settingsReceiveFail(); | 76 | void settingsReceiveFail(); |
| @@ -82,8 +82,8 @@ LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short · 81 unmodified lines | |||
| 82 | qDebug() << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort(); | 82 | qDebug() << "NodeList DTLS socket is listening on" << _dtlsSocket->localPort(); |
| 83 | } | 83 | } |
| 84 | 84 | ||
| 85 | const int LARGER_SNDBUF_SIZE = 1048576; | 85 | const int LARGER_BUFFER_SIZE = 1048576; |
| 86 | changeSendSocketBufferSize(LARGER_SNDBUF_SIZE); | 86 | changeSocketBufferSizes(LARGER_BUFFER_SIZE); |
| 87 | 87 | ||
| 88 | _packetStatTimer.start(); | 88 | _packetStatTimer.start(); |
| 89 | } | 89 | } |
| @@ -129,7 +129,7 @@ QUdpSocket& LimitedNodeList::getDTLSSocket() { · 39 unmodified lines | |||
| 129 | return *_dtlsSocket; | 129 | return *_dtlsSocket; |
| 130 | } | 130 | } |
| 131 | 131 | ||
| 132 | void LimitedNodeList::changeSendSocketBufferSize(int numSendBytes) { | 132 | void LimitedNodeList::changeSocketBufferSizes(int numBytes) { |
| 133 | // change the socket send buffer size to be 1MB | 133 | // change the socket send buffer size to be 1MB |
| 134 | int oldBufferSize = 0; | 134 | int oldBufferSize = 0; |
| 135 | 135 | ||
| @@ -139,15 +139,28 @@ void LimitedNodeList::changeSendSocketBufferSize(int numSendBytes) { · 3 unmodified lines | |||
| 139 | unsigned int sizeOfInt = sizeof(oldBufferSize); | 139 | unsigned int sizeOfInt = sizeof(oldBufferSize); |
| 140 | #endif | 140 | #endif |
| 141 | 141 | ||
| 142 | getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>(&oldBufferSize), &sizeOfInt); | 142 | for (int i = 0; i < 2; i++) { |
| 143 | 143 | int bufferOpt = (i == 0) ? SO_SNDBUF : SO_RCVBUF; | |
| 144 | setsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, SO_SNDBUF, reinterpret_cast<const char*>(&numSendBytes), | 144 | |
| 145 | sizeof(numSendBytes)); | 145 | getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast<char*>(&oldBufferSize), &sizeOfInt); |
| 146 | 146 | ||
| 147 | int newBufferSize = 0; | 147 | setsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast<const char*>(&numBytes), |
| 148 | getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, SO_SNDBUF, reinterpret_cast<char*>(&newBufferSize), &sizeOfInt); | 148 | sizeof(numBytes)); |
| 149 | 149 | ||
| 150 | qDebug() << "Changed socket send buffer size from" << oldBufferSize << "to" << newBufferSize << "bytes"; | 150 | QString bufferTypeString = (i == 0) ? "send" : "receive"; |
| 151 | |||
| 152 | if (oldBufferSize < numBytes) { | ||
| 153 | int newBufferSize = 0; | ||
| 154 | getsockopt(_nodeSocket.socketDescriptor(), SOL_SOCKET, bufferOpt, reinterpret_cast<char*>(&newBufferSize), &sizeOfInt); | ||
| 155 | |||
| 156 | qDebug() << "Changed socket" << bufferTypeString << "buffer size from" << oldBufferSize << "to" | ||
| 157 | << newBufferSize << "bytes"; | ||
| 158 | } else { | ||
| 159 | // don't make the buffer smaller | ||
| 160 | qDebug() << "Did not change socket" << bufferTypeString << "buffer size from" << oldBufferSize | ||
| 161 | << "since it is larger than desired size of" << numBytes; | ||
| 162 | } | ||
| 163 | } | ||
| 151 | } | 164 | } |
| 152 | 165 | ||
| 153 | bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { | 166 | bool LimitedNodeList::packetVersionAndHashMatch(const QByteArray& packet) { |
| @@ -123,7 +123,7 @@ protected: · 122 unmodified lines | |||
| 123 | NodeHash::iterator killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill); | 123 | NodeHash::iterator killNodeAtHashIterator(NodeHash::iterator& nodeItemToKill); |
| 124 | 124 | ||
| 125 | 125 | ||
| 126 | void changeSendSocketBufferSize(int numSendBytes); | 126 | void changeSocketBufferSizes(int numBytes); |
| 127 | 127 | ||
| 128 | QUuid _sessionUUID; | 128 | QUuid _sessionUUID; |
| 129 | NodeHash _nodeHash; | 129 | NodeHash _nodeHash; |
| @@ -80,6 +80,8 @@ PacketVersion versionForPacketType(PacketType type) { · 79 unmodified lines | |||
| 80 | return 2; | 80 | return 2; |
| 81 | case PacketTypeAudioStreamStats: | 81 | case PacketTypeAudioStreamStats: |
| 82 | return 1; | 82 | return 1; |
| 83 | case PacketTypeMetavoxelData: | ||
| 84 | return 1; | ||
| 83 | default: | 85 | default: |
| 84 | return 0; | 86 | return 0; |
| 85 | } | 87 | } |
| @@ -39,10 +39,6 @@ public: · 38 unmodified lines | |||
| 39 | ~PacketSender(); | 39 | ~PacketSender(); |
| 40 | 40 | ||
| 41 | /// Add packet to outbound queue. | 41 | /// Add packet to outbound queue. |
| 42 | /// \param HifiSockAddr& address the destination address | ||
| 43 | /// \param packetData pointer to data | ||
| 44 | /// \param ssize_t packetLength size of data | ||
| 45 | /// \thread any thread, typically the application thread | ||
| 46 | void queuePacketForSending(const SharedNodePointer& destinationNode, const QByteArray& packet); | 42 | void queuePacketForSending(const SharedNodePointer& destinationNode, const QByteArray& packet); |
| 47 | 43 | ||
| 48 | void setPacketsPerSecond(int packetsPerSecond); | 44 | void setPacketsPerSecond(int packetsPerSecond); |
| @@ -24,10 +24,6 @@ public: · 23 unmodified lines | |||
| 24 | ReceivedPacketProcessor() { } | 24 | ReceivedPacketProcessor() { } |
| 25 | 25 | ||
| 26 | /// Add packet from network receive thread to the processing queue. | 26 | /// Add packet from network receive thread to the processing queue. |
| 27 | /// \param sockaddr& senderAddress the address of the sender | ||
| 28 | /// \param packetData pointer to received data | ||
| 29 | /// \param ssize_t packetLength size of received data | ||
| 30 | /// \thread network receive thread | ||
| 31 | void queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); | 27 | void queueReceivedPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); |
| 32 | 28 | ||
| 33 | /// Are there received packets waiting to be processed | 29 | /// Are there received packets waiting to be processed |
| @@ -253,14 +253,19 @@ PacketStreamStats SequenceNumberStats::getStatsForHistoryWindow() const { · 252 unmodified lines | |||
| 253 | } | 253 | } |
| 254 | 254 | ||
| 255 | // calculate difference between newest stats and oldest stats to get window stats | 255 | // calculate difference between newest stats and oldest stats to get window stats |
| 256 | PacketStreamStats windowStats; | 256 | return *newestStats - *oldestStats; |
| 257 | windowStats._received = newestStats->_received - oldestStats->_received; | ||
| 258 | windowStats._unreasonable = newestStats->_unreasonable - oldestStats->_unreasonable; | ||
| 259 | windowStats._early = newestStats->_early - oldestStats->_early; | ||
| 260 | windowStats._late = newestStats->_late - oldestStats->_late; | ||
| 261 | windowStats._lost = newestStats->_lost - oldestStats->_lost; | ||
| 262 | windowStats._recovered = newestStats->_recovered - oldestStats->_recovered; | ||
| 263 | windowStats._expectedReceived = newestStats->_expectedReceived - oldestStats->_expectedReceived; | ||
| 264 | |||
| 265 | return windowStats; | ||
| 266 | } | 257 | } |
| 258 | |||
| 259 | PacketStreamStats SequenceNumberStats::getStatsForLastHistoryInterval() const { | ||
| 260 | |||
| 261 | const PacketStreamStats* newestStats = _statsHistory.getNewestEntry(); | ||
| 262 | const PacketStreamStats* secondNewestStats = _statsHistory.get(1); | ||
| 263 | |||
| 264 | // this catches cases where history is length 1 or 0 (both are NULL in case of 0) | ||
| 265 | if (newestStats == NULL || secondNewestStats == NULL) { | ||
| 266 | return PacketStreamStats(); | ||
| 267 | } | ||
| 268 | |||
| 269 | return *newestStats - *secondNewestStats; | ||
| 270 | } | ||
| 271 | |||
| @@ -31,6 +31,18 @@ public: · 30 unmodified lines | |||
| 31 | _expectedReceived(0) | 31 | _expectedReceived(0) |
| 32 | {} | 32 | {} |
| 33 | 33 | ||
| 34 | PacketStreamStats operator-(const PacketStreamStats& rhs) const { | ||
| 35 | PacketStreamStats diff; | ||
| 36 | diff._received = _received - rhs._received; | ||
| 37 | diff._unreasonable = _unreasonable - rhs._unreasonable; | ||
| 38 | diff._early = _early - rhs._early; | ||
| 39 | diff._late = _late - rhs._late; | ||
| 40 | diff._lost = _lost - rhs._lost; | ||
| 41 | diff._recovered = _recovered - rhs._recovered; | ||
| 42 | diff._expectedReceived = _expectedReceived - rhs._expectedReceived; | ||
| 43 | return diff; | ||
| 44 | } | ||
| 45 | |||
| 34 | float getLostRate() const { return (float)_lost / _expectedReceived; } | 46 | float getLostRate() const { return (float)_lost / _expectedReceived; } |
| 35 | 47 | ||
| 36 | quint32 _received; | 48 | quint32 _received; |
| @@ -76,6 +88,7 @@ public: · 39 unmodified lines | |||
| 76 | 88 | ||
| 77 | const PacketStreamStats& getStats() const { return _stats; } | 89 | const PacketStreamStats& getStats() const { return _stats; } |
| 78 | PacketStreamStats getStatsForHistoryWindow() const; | 90 | PacketStreamStats getStatsForHistoryWindow() const; |
| 91 | PacketStreamStats getStatsForLastHistoryInterval() const; | ||
| 79 | const QSet<quint16>& getMissingSet() const { return _missingSet; } | 92 | const QSet<quint16>& getMissingSet() const { return _missingSet; } |
| 80 | 93 | ||
| 81 | private: | 94 | private: |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | #include <QtCore/QCoreApplication> | 12 | #include <QtCore/QCoreApplication> |
| 13 | #include <QtCore/QJsonObject> | 13 | #include <QtCore/QJsonObject> |
| 14 | #include <QtCore/QThread> | ||
| 14 | #include <QtCore/QTimer> | 15 | #include <QtCore/QTimer> |
| 15 | 16 | ||
| 16 | #include "Logging.h" | 17 | #include "Logging.h" |
| @@ -18,7 +19,8 @@ · 1 unmodified line | |||
| 18 | 19 | ||
| 19 | ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) : | 20 | ThreadedAssignment::ThreadedAssignment(const QByteArray& packet) : |
| 20 | Assignment(packet), | 21 | Assignment(packet), |
| 21 | _isFinished(false) | 22 | _isFinished(false), |
| 23 | _datagramProcessingThread(NULL) | ||
| 22 | { | 24 | { |
| 23 | 25 | ||
| 24 | } | 26 | } |
| @@ -28,10 +30,25 @@ void ThreadedAssignment::setFinished(bool isFinished) { · 3 unmodified lines | |||
| 28 | 30 | ||
| 29 | if (_isFinished) { | 31 | if (_isFinished) { |
| 30 | aboutToFinish(); | 32 | aboutToFinish(); |
| 31 | emit finished(); | 33 | |
| 34 | NodeList* nodeList = NodeList::getInstance(); | ||
| 35 | |||
| 36 | // if we have a datagram processing thread, quit it and wait on it to make sure that | ||
| 37 | // the node socket is back on the same thread as the NodeList | ||
| 38 | |||
| 39 | if (_datagramProcessingThread) { | ||
| 40 | // tell the datagram processing thread to quit and wait until it is done, then return the node socket to the NodeList | ||
| 41 | _datagramProcessingThread->quit(); | ||
| 42 | _datagramProcessingThread->wait(); | ||
| 43 | |||
| 44 | // set node socket parent back to NodeList | ||
| 45 | nodeList->getNodeSocket().setParent(nodeList); | ||
| 46 | } | ||
| 32 | 47 | ||
| 33 | // move the NodeList back to the QCoreApplication instance's thread | 48 | // move the NodeList back to the QCoreApplication instance's thread |
| 34 | NodeList::getInstance()->moveToThread(QCoreApplication::instance()->thread()); | 49 | nodeList->moveToThread(QCoreApplication::instance()->thread()); |
| 50 | |||
| 51 | emit finished(); | ||
| 35 | } | 52 | } |
| 36 | } | 53 | } |
| 37 | 54 | ||
| @@ -20,6 +20,7 @@ class ThreadedAssignment : public Assignment { · 19 unmodified lines | |||
| 20 | Q_OBJECT | 20 | Q_OBJECT |
| 21 | public: | 21 | public: |
| 22 | ThreadedAssignment(const QByteArray& packet); | 22 | ThreadedAssignment(const QByteArray& packet); |
| 23 | |||
| 23 | void setFinished(bool isFinished); | 24 | void setFinished(bool isFinished); |
| 24 | virtual void aboutToFinish() { }; | 25 | virtual void aboutToFinish() { }; |
| 25 | void addPacketStatsAndSendStatsPacket(QJsonObject& statsObject); | 26 | void addPacketStatsAndSendStatsPacket(QJsonObject& statsObject); |
| @@ -29,15 +30,18 @@ public slots: · 3 unmodified lines | |||
| 29 | virtual void run() = 0; | 30 | virtual void run() = 0; |
| 30 | virtual void readPendingDatagrams() = 0; | 31 | virtual void readPendingDatagrams() = 0; |
| 31 | virtual void sendStatsPacket(); | 32 | virtual void sendStatsPacket(); |
| 32 | 33 | signals: | |
| 34 | void finished(); | ||
| 35 | |||
| 33 | protected: | 36 | protected: |
| 34 | bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr); | 37 | bool readAvailableDatagram(QByteArray& destinationByteArray, HifiSockAddr& senderSockAddr); |
| 35 | void commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats = true); | 38 | void commonInit(const QString& targetName, NodeType_t nodeType, bool shouldSendStats = true); |
| 36 | bool _isFinished; | 39 | bool _isFinished; |
| 40 | QThread* _datagramProcessingThread; | ||
| 41 | |||
| 37 | private slots: | 42 | private slots: |
| 38 | void checkInWithDomainServerOrExit(); | 43 | void checkInWithDomainServerOrExit(); |
| 39 | signals: | 44 | |
| 40 | void finished(); | ||
| 41 | }; | 45 | }; |
| 42 | 46 | ||
| 43 | typedef QSharedPointer<ThreadedAssignment> SharedAssignmentPointer; | 47 | typedef QSharedPointer<ThreadedAssignment> SharedAssignmentPointer; |
| @@ -1,30 +1,19 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME octree) | 1 | set(TARGET_NAME octree) |
| 8 | 2 | ||
| 9 | find_package(Qt5Widgets REQUIRED) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 4 | setup_hifi_library() | ||
| 10 | 5 | ||
| 11 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | 6 | include_glm() |
| 12 | setup_hifi_library(${TARGET_NAME}) | ||
| 13 | 7 | ||
| 14 | include(${MACRO_DIR}/IncludeGLM.cmake) | 8 | link_hifi_libraries(shared networking) |
| 15 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 16 | 9 | ||
| 17 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 10 | # find ZLIB |
| 18 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | 11 | find_package(ZLIB REQUIRED) |
| 19 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 20 | |||
| 21 | # link ZLIB | ||
| 22 | find_package(ZLIB) | ||
| 23 | 12 | ||
| 24 | include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") | 13 | include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") |
| 25 | target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) | ||
| 26 | 14 | ||
| 27 | # add a definition for ssize_t so that windows doesn't bail | 15 | # append ZLIB and OpenSSL to our list of libraries to link |
| 28 | if (WIN32) | 16 | list(APPEND ${TARGET_NAME}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") |
| 29 | add_definitions(-Dssize_t=long) | 17 | |
| 30 | endif () | 18 | # call macro to link our dependencies and bubble them up via a property on our target |
| 19 | link_shared_dependencies() | ||
| @@ -20,7 +20,7 @@ EditPacketBuffer::EditPacketBuffer() : · 19 unmodified lines | |||
| 20 | 20 | ||
| 21 | } | 21 | } |
| 22 | 22 | ||
| 23 | EditPacketBuffer::EditPacketBuffer(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost, QUuid nodeUUID) : | 23 | EditPacketBuffer::EditPacketBuffer(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost, QUuid nodeUUID) : |
| 24 | _nodeUUID(nodeUUID), | 24 | _nodeUUID(nodeUUID), |
| 25 | _currentType(type), | 25 | _currentType(type), |
| 26 | _currentSize(length), | 26 | _currentSize(length), |
| @@ -21,13 +21,13 @@ · 20 unmodified lines | |||
| 21 | class EditPacketBuffer { | 21 | class EditPacketBuffer { |
| 22 | public: | 22 | public: |
| 23 | EditPacketBuffer(); | 23 | EditPacketBuffer(); |
| 24 | EditPacketBuffer(PacketType type, unsigned char* codeColorBuffer, ssize_t length, | 24 | EditPacketBuffer(PacketType type, unsigned char* codeColorBuffer, size_t length, |
| 25 | qint64 satoshiCost = 0, const QUuid nodeUUID = QUuid()); | 25 | qint64 satoshiCost = 0, const QUuid nodeUUID = QUuid()); |
| 26 | 26 | ||
| 27 | QUuid _nodeUUID; | 27 | QUuid _nodeUUID; |
| 28 | PacketType _currentType; | 28 | PacketType _currentType; |
| 29 | unsigned char _currentBuffer[MAX_PACKET_SIZE]; | 29 | unsigned char _currentBuffer[MAX_PACKET_SIZE]; |
| 30 | ssize_t _currentSize; | 30 | size_t _currentSize; |
| 31 | qint64 _satoshiCost; | 31 | qint64 _satoshiCost; |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| @@ -35,7 +35,7 @@ void JurisdictionListener::nodeKilled(SharedNodePointer node) { · 34 unmodified lines | |||
| 35 | bool JurisdictionListener::queueJurisdictionRequest() { | 35 | bool JurisdictionListener::queueJurisdictionRequest() { |
| 36 | static unsigned char buffer[MAX_PACKET_SIZE]; | 36 | static unsigned char buffer[MAX_PACKET_SIZE]; |
| 37 | unsigned char* bufferOut = &buffer[0]; | 37 | unsigned char* bufferOut = &buffer[0]; |
| 38 | ssize_t sizeOut = populatePacketHeader(reinterpret_cast<char*>(bufferOut), PacketTypeJurisdictionRequest); | 38 | int sizeOut = populatePacketHeader(reinterpret_cast<char*>(bufferOut), PacketTypeJurisdictionRequest); |
| 39 | int nodeCount = 0; | 39 | int nodeCount = 0; |
| 40 | 40 | ||
| 41 | NodeList* nodeList = NodeList::getInstance(); | 41 | NodeList* nodeList = NodeList::getInstance(); |
| @@ -47,10 +47,6 @@ public slots: · 46 unmodified lines | |||
| 47 | protected: | 47 | protected: |
| 48 | /// Callback for processing of received packets. Will process any queued PacketType_JURISDICTION and update the | 48 | /// Callback for processing of received packets. Will process any queued PacketType_JURISDICTION and update the |
| 49 | /// jurisdiction map member variable | 49 | /// jurisdiction map member variable |
| 50 | /// \param sockaddr& senderAddress the address of the sender | ||
| 51 | /// \param packetData pointer to received data | ||
| 52 | /// \param ssize_t packetLength size of received data | ||
| 53 | /// \thread "this" individual processing thread | ||
| 54 | virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); | 50 | virtual void processPacket(const SharedNodePointer& sendingNode, const QByteArray& packet); |
| 55 | 51 | ||
| 56 | private: | 52 | private: |
| @@ -47,7 +47,7 @@ bool JurisdictionSender::process() { · 46 unmodified lines | |||
| 47 | // add our packet to our own queue, then let the PacketSender class do the rest of the work. | 47 | // add our packet to our own queue, then let the PacketSender class do the rest of the work. |
| 48 | static unsigned char buffer[MAX_PACKET_SIZE]; | 48 | static unsigned char buffer[MAX_PACKET_SIZE]; |
| 49 | unsigned char* bufferOut = &buffer[0]; | 49 | unsigned char* bufferOut = &buffer[0]; |
| 50 | ssize_t sizeOut = 0; | 50 | int sizeOut = 0; |
| 51 | 51 | ||
| 52 | if (_jurisdictionMap) { | 52 | if (_jurisdictionMap) { |
| 53 | sizeOut = _jurisdictionMap->packIntoMessage(bufferOut, MAX_PACKET_SIZE); | 53 | sizeOut = _jurisdictionMap->packIntoMessage(bufferOut, MAX_PACKET_SIZE); |
| @@ -83,7 +83,7 @@ bool OctreeEditPacketSender::serversExist() const { · 82 unmodified lines | |||
| 83 | // This method is called when the edit packet layer has determined that it has a fully formed packet destined for | 83 | // This method is called when the edit packet layer has determined that it has a fully formed packet destined for |
| 84 | // a known nodeID. | 84 | // a known nodeID. |
| 85 | void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, | 85 | void OctreeEditPacketSender::queuePacketToNode(const QUuid& nodeUUID, unsigned char* buffer, |
| 86 | ssize_t length, qint64 satoshiCost) { | 86 | size_t length, qint64 satoshiCost) { |
| 87 | 87 | ||
| 88 | bool wantDebug = false; | 88 | bool wantDebug = false; |
| 89 | if (wantDebug) { | 89 | if (wantDebug) { |
| @@ -171,7 +171,7 @@ void OctreeEditPacketSender::processPreServerExistsPackets() { · 81 unmodified lines | |||
| 171 | } | 171 | } |
| 172 | 172 | ||
| 173 | void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned char* buffer, | 173 | void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned char* buffer, |
| 174 | ssize_t length, qint64 satoshiCost) { | 174 | size_t length, qint64 satoshiCost) { |
| 175 | // If we're asked to save messages while waiting for voxel servers to arrive, then do so... | 175 | // If we're asked to save messages while waiting for voxel servers to arrive, then do so... |
| 176 | 176 | ||
| 177 | if (_maxPendingMessages > 0) { | 177 | if (_maxPendingMessages > 0) { |
| @@ -189,7 +189,7 @@ void OctreeEditPacketSender::queuePendingPacketToNodes(PacketType type, unsigned · 11 unmodified lines | |||
| 189 | } | 189 | } |
| 190 | } | 190 | } |
| 191 | 191 | ||
| 192 | void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, ssize_t length, qint64 satoshiCost) { | 192 | void OctreeEditPacketSender::queuePacketToNodes(unsigned char* buffer, size_t length, qint64 satoshiCost) { |
| 193 | if (!_shouldSend) { | 193 | if (!_shouldSend) { |
| 194 | return; // bail early | 194 | return; // bail early |
| 195 | } | 195 | } |
| @@ -30,7 +30,7 @@ public: · 29 unmodified lines | |||
| 30 | /// Queues a single edit message. Will potentially send a pending multi-command packet. Determines which server | 30 | /// Queues a single edit message. Will potentially send a pending multi-command packet. Determines which server |
| 31 | /// node or nodes the packet should be sent to. Can be called even before servers are known, in which case up to | 31 | /// node or nodes the packet should be sent to. Can be called even before servers are known, in which case up to |
| 32 | /// MaxPendingMessages will be buffered and processed when servers are known. | 32 | /// MaxPendingMessages will be buffered and processed when servers are known. |
| 33 | void queueOctreeEditMessage(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); | 33 | void queueOctreeEditMessage(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost = 0); |
| 34 | 34 | ||
| 35 | /// Releases all queued messages even if those messages haven't filled an MTU packet. This will move the packed message | 35 | /// Releases all queued messages even if those messages haven't filled an MTU packet. This will move the packed message |
| 36 | /// packets onto the send queue. If running in threaded mode, the caller does not need to do any further processing to | 36 | /// packets onto the send queue. If running in threaded mode, the caller does not need to do any further processing to |
| @@ -82,7 +82,7 @@ public: · 45 unmodified lines | |||
| 82 | // you must override these... | 82 | // you must override these... |
| 83 | virtual char getMyNodeType() const = 0; | 83 | virtual char getMyNodeType() const = 0; |
| 84 | virtual void adjustEditPacketForClockSkew(PacketType type, | 84 | virtual void adjustEditPacketForClockSkew(PacketType type, |
| 85 | unsigned char* editPacketBuffer, ssize_t length, int clockSkew) { }; | 85 | unsigned char* editPacketBuffer, size_t length, int clockSkew) { }; |
| 86 | 86 | ||
| 87 | bool hasDestinationWalletUUID() const { return !_destinationWalletUUID.isNull(); } | 87 | bool hasDestinationWalletUUID() const { return !_destinationWalletUUID.isNull(); } |
| 88 | void setDestinationWalletUUID(const QUuid& destinationWalletUUID) { _destinationWalletUUID = destinationWalletUUID; } | 88 | void setDestinationWalletUUID(const QUuid& destinationWalletUUID) { _destinationWalletUUID = destinationWalletUUID; } |
| @@ -98,9 +98,9 @@ signals: · 9 unmodified lines | |||
| 98 | 98 | ||
| 99 | protected: | 99 | protected: |
| 100 | bool _shouldSend; | 100 | bool _shouldSend; |
| 101 | void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); | 101 | void queuePacketToNode(const QUuid& nodeID, unsigned char* buffer, size_t length, qint64 satoshiCost = 0); |
| 102 | void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); | 102 | void queuePendingPacketToNodes(PacketType type, unsigned char* buffer, size_t length, qint64 satoshiCost = 0); |
| 103 | void queuePacketToNodes(unsigned char* buffer, ssize_t length, qint64 satoshiCost = 0); | 103 | void queuePacketToNodes(unsigned char* buffer, size_t length, qint64 satoshiCost = 0); |
| 104 | void initializePacket(EditPacketBuffer& packetBuffer, PacketType type); | 104 | void initializePacket(EditPacketBuffer& packetBuffer, PacketType type); |
| 105 | void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet | 105 | void releaseQueuedPacket(EditPacketBuffer& packetBuffer); // releases specific queued packet |
| 106 | 106 | ||
| @@ -9,7 +9,9 @@ · 8 unmodified lines | |||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | // | 10 | // |
| 11 | 11 | ||
| 12 | #include <GLMHelpers.h> | ||
| 12 | #include <PerfStat.h> | 13 | #include <PerfStat.h> |
| 14 | |||
| 13 | #include "OctreePacketData.h" | 15 | #include "OctreePacketData.h" |
| 14 | 16 | ||
| 15 | bool OctreePacketData::_debug = false; | 17 | bool OctreePacketData::_debug = false; |
| @@ -9,8 +9,9 @@ · 8 unmodified lines | |||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | // | 10 | // |
| 11 | 11 | ||
| 12 | #include <PacketHeaders.h> | 12 | //#include <PacketHeaders.h> |
| 13 | #include <SharedUtil.h> | 13 | //#include <SharedUtil.h> |
| 14 | #include <GLMHelpers.h> | ||
| 14 | 15 | ||
| 15 | #include "OctreeConstants.h" | 16 | #include "OctreeConstants.h" |
| 16 | #include "OctreeQuery.h" | 17 | #include "OctreeQuery.h" |
| @@ -1,33 +1,12 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME particles) | 1 | set(TARGET_NAME particles) |
| 8 | 2 | ||
| 9 | find_package(Qt5Widgets REQUIRED) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 10 | 4 | setup_hifi_library(Gui Network Script) | |
| 11 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | ||
| 12 | setup_hifi_library(${TARGET_NAME}) | ||
| 13 | |||
| 14 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 15 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 16 | |||
| 17 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | ||
| 18 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 19 | link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") | ||
| 20 | link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") | ||
| 21 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 22 | link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") | ||
| 23 | 5 | ||
| 24 | # link ZLIB | 6 | include_glm() |
| 25 | find_package(ZLIB) | ||
| 26 | 7 | ||
| 27 | include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") | 8 | link_hifi_libraries(shared octree fbx networking animation) |
| 28 | target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) | 9 | include_hifi_library_headers(script-engine) |
| 29 | 10 | ||
| 30 | # add a definition for ssize_t so that windows doesn't bail | 11 | # call macro to link our dependencies and bubble them up via a property on our target |
| 31 | if (WIN32) | 12 | link_shared_dependencies() |
| 32 | add_definitions(-Dssize_t=long) | ||
| 33 | endif () | ||
| @@ -13,7 +13,7 @@ · 12 unmodified lines | |||
| 13 | 13 | ||
| 14 | #include <Octree.h> | 14 | #include <Octree.h> |
| 15 | #include <RegisteredMetaTypes.h> | 15 | #include <RegisteredMetaTypes.h> |
| 16 | #include <SharedUtil.h> // usecTimestampNow() | 16 | #include <GLMHelpers.h> |
| 17 | #include <VoxelsScriptingInterface.h> | 17 | #include <VoxelsScriptingInterface.h> |
| 18 | #include <VoxelDetail.h> | 18 | #include <VoxelDetail.h> |
| 19 | 19 | ||
| @@ -22,7 +22,7 @@ · 2 unmodified lines | |||
| 22 | // I'm open to other potential solutions. Could we change cmake to allow libraries to reference each others | 22 | // I'm open to other potential solutions. Could we change cmake to allow libraries to reference each others |
| 23 | // headers, but not link to each other, this is essentially what this construct is doing, but would be | 23 | // headers, but not link to each other, this is essentially what this construct is doing, but would be |
| 24 | // better to add includes to the include path, but not link | 24 | // better to add includes to the include path, but not link |
| 25 | #include "../../script-engine/src/ScriptEngine.h" | 25 | #include <ScriptEngine.h> |
| 26 | 26 | ||
| 27 | #include "ParticlesScriptingInterface.h" | 27 | #include "ParticlesScriptingInterface.h" |
| 28 | #include "Particle.h" | 28 | #include "Particle.h" |
| @@ -856,7 +856,7 @@ bool Particle::encodeParticleEditMessageDetails(PacketType command, ParticleID i · 827 unmodified lines | |||
| 856 | } | 856 | } |
| 857 | 857 | ||
| 858 | // adjust any internal timestamps to fix clock skew for this server | 858 | // adjust any internal timestamps to fix clock skew for this server |
| 859 | void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { | 859 | void Particle::adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew) { |
| 860 | unsigned char* dataAt = codeColorBuffer; | 860 | unsigned char* dataAt = codeColorBuffer; |
| 861 | int octets = numberOfThreeBitSectionsInCode(dataAt); | 861 | int octets = numberOfThreeBitSectionsInCode(dataAt); |
| 862 | int lengthOfOctcode = bytesRequiredForCodeLength(octets); | 862 | int lengthOfOctcode = bytesRequiredForCodeLength(octets); |
| @@ -292,7 +292,7 @@ public: · 291 unmodified lines | |||
| 292 | static bool encodeParticleEditMessageDetails(PacketType command, ParticleID id, const ParticleProperties& details, | 292 | static bool encodeParticleEditMessageDetails(PacketType command, ParticleID id, const ParticleProperties& details, |
| 293 | unsigned char* bufferOut, int sizeIn, int& sizeOut); | 293 | unsigned char* bufferOut, int sizeIn, int& sizeOut); |
| 294 | 294 | ||
| 295 | static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, ssize_t length, int clockSkew); | 295 | static void adjustEditPacketForClockSkew(unsigned char* codeColorBuffer, size_t length, int clockSkew); |
| 296 | 296 | ||
| 297 | void applyHardCollision(const CollisionInfo& collisionInfo); | 297 | void applyHardCollision(const CollisionInfo& collisionInfo); |
| 298 | 298 | ||
| @@ -38,8 +38,8 @@ void ParticleEditPacketSender::sendEditParticleMessage(PacketType type, Particle · 37 unmodified lines | |||
| 38 | } | 38 | } |
| 39 | } | 39 | } |
| 40 | 40 | ||
| 41 | void ParticleEditPacketSender::adjustEditPacketForClockSkew(PacketType type, | 41 | void ParticleEditPacketSender::adjustEditPacketForClockSkew(PacketType type, |
| 42 | unsigned char* codeColorBuffer, ssize_t length, int clockSkew) { | 42 | unsigned char* codeColorBuffer, size_t length, int clockSkew) { |
| 43 | Particle::adjustEditPacketForClockSkew(codeColorBuffer, length, clockSkew); | 43 | Particle::adjustEditPacketForClockSkew(codeColorBuffer, length, clockSkew); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| @@ -31,6 +31,6 @@ public: · 30 unmodified lines | |||
| 31 | 31 | ||
| 32 | // My server type is the particle server | 32 | // My server type is the particle server |
| 33 | virtual char getMyNodeType() const { return NodeType::ParticleServer; } | 33 | virtual char getMyNodeType() const { return NodeType::ParticleServer; } |
| 34 | virtual void adjustEditPacketForClockSkew(PacketType type, unsigned char* codeColorBuffer, ssize_t length, int clockSkew); | 34 | virtual void adjustEditPacketForClockSkew(PacketType type, unsigned char* codeColorBuffer, size_t length, int clockSkew); |
| 35 | }; | 35 | }; |
| 36 | #endif // hifi_ParticleEditPacketSender_h | 36 | #endif // hifi_ParticleEditPacketSender_h |
| @@ -1,35 +1,11 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME script-engine) | 1 | set(TARGET_NAME script-engine) |
| 8 | 2 | ||
| 9 | find_package(Qt5Widgets REQUIRED) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 10 | 4 | setup_hifi_library(Gui Network Script Widgets) | |
| 11 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | ||
| 12 | setup_hifi_library(${TARGET_NAME}) | ||
| 13 | |||
| 14 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 15 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 16 | |||
| 17 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | ||
| 18 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 19 | link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") | ||
| 20 | link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 21 | link_hifi_library(fbx ${TARGET_NAME} "${ROOT_DIR}") | ||
| 22 | link_hifi_library(particles ${TARGET_NAME} "${ROOT_DIR}") | ||
| 23 | link_hifi_library(entities ${TARGET_NAME} "${ROOT_DIR}") | ||
| 24 | link_hifi_library(animation ${TARGET_NAME} "${ROOT_DIR}") | ||
| 25 | 5 | ||
| 26 | # link ZLIB | 6 | include_glm() |
| 27 | find_package(ZLIB) | ||
| 28 | 7 | ||
| 29 | include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") | 8 | link_hifi_libraries(shared octree voxels fbx particles entities animation) |
| 30 | target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets) | ||
| 31 | 9 | ||
| 32 | # add a definition for ssize_t so that windows doesn't bail | 10 | # call macro to link our dependencies and bubble them up via a property on our target |
| 33 | if (WIN32) | 11 | link_shared_dependencies() |
| 34 | add_definitions(-Dssize_t=long) | ||
| 35 | endif () | ||
| @@ -14,7 +14,7 @@ · 13 unmodified lines | |||
| 14 | #include <QDebug> | 14 | #include <QDebug> |
| 15 | 15 | ||
| 16 | #include <OctreeConstants.h> | 16 | #include <OctreeConstants.h> |
| 17 | #include <SharedUtil.h> | 17 | #include <GLMHelpers.h> |
| 18 | #include "Quat.h" | 18 | #include "Quat.h" |
| 19 | 19 | ||
| 20 | 20 | ||
| @@ -1,33 +1,7 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | set(TARGET_NAME shared) | 1 | set(TARGET_NAME shared) |
| 5 | project(${TARGET_NAME}) | ||
| 6 | |||
| 7 | find_package(Qt5 COMPONENTS Network Widgets Xml Script) | ||
| 8 | |||
| 9 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | ||
| 10 | setup_hifi_library(${TARGET_NAME}) | ||
| 11 | |||
| 12 | # include GLM | ||
| 13 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 14 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 15 | |||
| 16 | set(EXTERNAL_ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/external") | ||
| 17 | |||
| 18 | if (WIN32) | ||
| 19 | # include headers for external libraries and InterfaceConfig. | ||
| 20 | include_directories("${EXTERNAL_ROOT_DIR}") | ||
| 21 | endif (WIN32) | ||
| 22 | |||
| 23 | # link required libraries on UNIX | ||
| 24 | if (UNIX AND NOT APPLE) | ||
| 25 | find_package(Threads REQUIRED) | ||
| 26 | target_link_libraries(${TARGET_NAME} "${CMAKE_THREAD_LIBS_INIT}") | ||
| 27 | endif (UNIX AND NOT APPLE) | ||
| 28 | 2 | ||
| 29 | # There is something special (bug) about Qt5Scripts, that we have to explicitly add its include | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 30 | # directory when Qt5 (5.2.1) is compiled from source and is not in a standard place. | 4 | setup_hifi_library(Network Widgets) |
| 31 | include_directories(SYSTEM "${Qt5Script_INCLUDE_DIRS}") | ||
| 32 | 5 | ||
| 33 | target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets) | 6 | # call macro to link our dependencies and bubble them up via a property on our target |
| 7 | link_shared_dependencies() | ||
| @@ -1,1403 +0,0 @@ | |||
| 1 | /* This is an implementation of the threads API of POSIX 1003.1-2001. | ||
| 2 | * | ||
| 3 | * -------------------------------------------------------------------------- | ||
| 4 | * | ||
| 5 | * Pthreads-win32 - POSIX Threads Library for Win32 | ||
| 6 | * Copyright(C) 1998 John E. Bossom | ||
| 7 | * Copyright(C) 1999,2005 Pthreads-win32 contributors | ||
| 8 | * | ||
| 9 | * Contact Email: rpj@callisto.canberra.edu.au | ||
| 10 | * | ||
| 11 | * The current list of contributors is contained | ||
| 12 | * in the file CONTRIBUTORS included with the source | ||
| 13 | * code distribution. The list can also be seen at the | ||
| 14 | * following World Wide Web location: | ||
| 15 | * http://sources.redhat.com/pthreads-win32/contributors.html | ||
| 16 | * | ||
| 17 | * This library is free software; you can redistribute it and/or | ||
| 18 | * modify it under the terms of the GNU Lesser General Public | ||
| 19 | * License as published by the Free Software Foundation; either | ||
| 20 | * version 2 of the License, or (at your option) any later version. | ||
| 21 | * | ||
| 22 | * This library is distributed in the hope that it will be useful, | ||
| 23 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 24 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 25 | * Lesser General Public License for more details. | ||
| 26 | * | ||
| 27 | * You should have received a copy of the GNU Lesser General Public | ||
| 28 | * License along with this library in the file COPYING.LIB; | ||
| 29 | * if not, write to the Free Software Foundation, Inc., | ||
| 30 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 31 | */ | ||
| 32 | |||
| 33 | #if !defined( PTHREAD_H ) | ||
| 34 | #define PTHREAD_H | ||
| 35 | |||
| 36 | #define PTW32_STATIC_LIB | ||
| 37 | |||
| 38 | /* | ||
| 39 | * See the README file for an explanation of the pthreads-win32 version | ||
| 40 | * numbering scheme and how the DLL is named etc. | ||
| 41 | */ | ||
| 42 | #define PTW32_VERSION 2,10,0,0 | ||
| 43 | #define PTW32_VERSION_STRING "2, 10, 0, 0\0" | ||
| 44 | |||
| 45 | /* There are three implementations of cancel cleanup. | ||
| 46 | * Note that pthread.h is included in both application | ||
| 47 | * compilation units and also internally for the library. | ||
| 48 | * The code here and within the library aims to work | ||
| 49 | * for all reasonable combinations of environments. | ||
| 50 | * | ||
| 51 | * The three implementations are: | ||
| 52 | * | ||
| 53 | * WIN32 SEH | ||
| 54 | * C | ||
| 55 | * C++ | ||
| 56 | * | ||
| 57 | * Please note that exiting a push/pop block via | ||
| 58 | * "return", "exit", "break", or "continue" will | ||
| 59 | * lead to different behaviour amongst applications | ||
| 60 | * depending upon whether the library was built | ||
| 61 | * using SEH, C++, or C. For example, a library built | ||
| 62 | * with SEH will call the cleanup routine, while both | ||
| 63 | * C++ and C built versions will not. | ||
| 64 | */ | ||
| 65 | |||
| 66 | /* | ||
| 67 | * Define defaults for cleanup code. | ||
| 68 | * Note: Unless the build explicitly defines one of the following, then | ||
| 69 | * we default to standard C style cleanup. This style uses setjmp/longjmp | ||
| 70 | * in the cancellation and thread exit implementations and therefore won't | ||
| 71 | * do stack unwinding if linked to applications that have it (e.g. | ||
| 72 | * C++ apps). This is currently consistent with most/all commercial Unix | ||
| 73 | * POSIX threads implementations. | ||
| 74 | */ | ||
| 75 | #if !defined( __CLEANUP_SEH ) && !defined( __CLEANUP_CXX ) && !defined( __CLEANUP_C ) | ||
| 76 | /* | ||
| 77 | [i_a] fix for apps using pthreads-Win32: when they do not define __CLEANUP_SEH themselves, | ||
| 78 | they're screwed as they'll receive the '__CLEANUP_C' macros which do NOT work when | ||
| 79 | the pthreads library code itself has actually been build with __CLEANUP_SEH, | ||
| 80 | which is the case when building this stuff in MSVC. | ||
| 81 | |||
| 82 | Hence this section is made to 'sensibly autodetect' the cleanup mode, when it hasn't | ||
| 83 | been hardwired in the makefiles / project files. | ||
| 84 | |||
| 85 | After all, who expects he MUST define one of these __CLEANUP_XXX defines in his own | ||
| 86 | code when using pthreads-Win32, for whatever reason. | ||
| 87 | */ | ||
| 88 | #if (defined(_MSC_VER) || defined(PTW32_RC_MSC)) | ||
| 89 | #define __CLEANUP_SEH | ||
| 90 | #elif defined(__cplusplus) | ||
| 91 | #define __CLEANUP_CXX | ||
| 92 | #else | ||
| 93 | #define __CLEANUP_C | ||
| 94 | #endif | ||
| 95 | #endif | ||
| 96 | |||
| 97 | #if defined( __CLEANUP_SEH ) && ( !defined( _MSC_VER ) && !defined(PTW32_RC_MSC)) | ||
| 98 | #error ERROR [__FILE__, line __LINE__]: SEH is not supported for this compiler. | ||
| 99 | #endif | ||
| 100 | |||
| 101 | /* | ||
| 102 | * Stop here if we are being included by the resource compiler. | ||
| 103 | */ | ||
| 104 | #if !defined(RC_INVOKED) | ||
| 105 | |||
| 106 | #undef PTW32_LEVEL | ||
| 107 | |||
| 108 | #if defined(_POSIX_SOURCE) | ||
| 109 | #define PTW32_LEVEL 0 | ||
| 110 | /* Early POSIX */ | ||
| 111 | #endif | ||
| 112 | |||
| 113 | #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 | ||
| 114 | #undef PTW32_LEVEL | ||
| 115 | #define PTW32_LEVEL 1 | ||
| 116 | /* Include 1b, 1c and 1d */ | ||
| 117 | #endif | ||
| 118 | |||
| 119 | #if defined(INCLUDE_NP) | ||
| 120 | #undef PTW32_LEVEL | ||
| 121 | #define PTW32_LEVEL 2 | ||
| 122 | /* Include Non-Portable extensions */ | ||
| 123 | #endif | ||
| 124 | |||
| 125 | #define PTW32_LEVEL_MAX 3 | ||
| 126 | |||
| 127 | #if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_LEVEL) | ||
| 128 | #define PTW32_LEVEL PTW32_LEVEL_MAX | ||
| 129 | /* Include everything */ | ||
| 130 | #endif | ||
| 131 | |||
| 132 | #if defined(_UWIN) | ||
| 133 | # define HAVE_STRUCT_TIMESPEC 1 | ||
| 134 | # define HAVE_SIGNAL_H 1 | ||
| 135 | # undef HAVE_PTW32_CONFIG_H | ||
| 136 | # pragma comment(lib, "pthread") | ||
| 137 | #endif | ||
| 138 | |||
| 139 | #if defined(__MINGW32__) || defined(__MINGW64__) | ||
| 140 | # define PTW32_CONFIG_MINGW | ||
| 141 | #endif | ||
| 142 | #if defined(_MSC_VER) | ||
| 143 | # if _MSC_VER < 1300 | ||
| 144 | # define PTW32_CONFIG_MSVC6 | ||
| 145 | # endif | ||
| 146 | # if _MSC_VER < 1400 | ||
| 147 | # define PTW32_CONFIG_MSVC7 | ||
| 148 | # endif | ||
| 149 | #endif | ||
| 150 | |||
| 151 | /* | ||
| 152 | * ------------------------------------------------------------- | ||
| 153 | * | ||
| 154 | * | ||
| 155 | * Module: pthread.h | ||
| 156 | * | ||
| 157 | * Purpose: | ||
| 158 | * Provides an implementation of PThreads based upon the | ||
| 159 | * standard: | ||
| 160 | * | ||
| 161 | * POSIX 1003.1-2001 | ||
| 162 | * and | ||
| 163 | * The Single Unix Specification version 3 | ||
| 164 | * | ||
| 165 | * (these two are equivalent) | ||
| 166 | * | ||
| 167 | * in order to enhance code portability between Windows, | ||
| 168 | * various commercial Unix implementations, and Linux. | ||
| 169 | * | ||
| 170 | * See the ANNOUNCE file for a full list of conforming | ||
| 171 | * routines and defined constants, and a list of missing | ||
| 172 | * routines and constants not defined in this implementation. | ||
| 173 | * | ||
| 174 | * Authors: | ||
| 175 | * There have been many contributors to this library. | ||
| 176 | * The initial implementation was contributed by | ||
| 177 | * John Bossom, and several others have provided major | ||
| 178 | * sections or revisions of parts of the implementation. | ||
| 179 | * Often significant effort has been contributed to | ||
| 180 | * find and fix important bugs and other problems to | ||
| 181 | * improve the reliability of the library, which sometimes | ||
| 182 | * is not reflected in the amount of code which changed as | ||
| 183 | * result. | ||
| 184 | * As much as possible, the contributors are acknowledged | ||
| 185 | * in the ChangeLog file in the source code distribution | ||
| 186 | * where their changes are noted in detail. | ||
| 187 | * | ||
| 188 | * Contributors are listed in the CONTRIBUTORS file. | ||
| 189 | * | ||
| 190 | * As usual, all bouquets go to the contributors, and all | ||
| 191 | * brickbats go to the project maintainer. | ||
| 192 | * | ||
| 193 | * Maintainer: | ||
| 194 | * The code base for this project is coordinated and | ||
| 195 | * eventually pre-tested, packaged, and made available by | ||
| 196 | * | ||
| 197 | * Ross Johnson <rpj@callisto.canberra.edu.au> | ||
| 198 | * | ||
| 199 | * QA Testers: | ||
| 200 | * Ultimately, the library is tested in the real world by | ||
| 201 | * a host of competent and demanding scientists and | ||
| 202 | * engineers who report bugs and/or provide solutions | ||
| 203 | * which are then fixed or incorporated into subsequent | ||
| 204 | * versions of the library. Each time a bug is fixed, a | ||
| 205 | * test case is written to prove the fix and ensure | ||
| 206 | * that later changes to the code don't reintroduce the | ||
| 207 | * same error. The number of test cases is slowly growing | ||
| 208 | * and therefore so is the code reliability. | ||
| 209 | * | ||
| 210 | * Compliance: | ||
| 211 | * See the file ANNOUNCE for the list of implemented | ||
| 212 | * and not-implemented routines and defined options. | ||
| 213 | * Of course, these are all defined is this file as well. | ||
| 214 | * | ||
| 215 | * Web site: | ||
| 216 | * The source code and other information about this library | ||
| 217 | * are available from | ||
| 218 | * | ||
| 219 | * http://sources.redhat.com/pthreads-win32/ | ||
| 220 | * | ||
| 221 | * ------------------------------------------------------------- | ||
| 222 | */ | ||
| 223 | |||
| 224 | /* Try to avoid including windows.h */ | ||
| 225 | #if defined(PTW32_CONFIG_MINGW) && defined(__cplusplus) | ||
| 226 | #define PTW32_INCLUDE_WINDOWS_H | ||
| 227 | #endif | ||
| 228 | |||
| 229 | #if defined(PTW32_INCLUDE_WINDOWS_H) | ||
| 230 | #include <windows.h> | ||
| 231 | #endif | ||
| 232 | |||
| 233 | #if defined(PTW32_CONFIG_MSVC6) || defined(__DMC__) | ||
| 234 | /* | ||
| 235 | * VC++6.0 or early compiler's header has no DWORD_PTR type. | ||
| 236 | */ | ||
| 237 | typedef unsigned long DWORD_PTR; | ||
| 238 | typedef unsigned long ULONG_PTR; | ||
| 239 | #endif | ||
| 240 | /* | ||
| 241 | * ----------------- | ||
| 242 | * autoconf switches | ||
| 243 | * ----------------- | ||
| 244 | */ | ||
| 245 | |||
| 246 | #if defined(HAVE_PTW32_CONFIG_H) | ||
| 247 | #include "config.h" | ||
| 248 | #endif /* HAVE_PTW32_CONFIG_H */ | ||
| 249 | |||
| 250 | #if !defined(NEED_FTIME) | ||
| 251 | #include <time.h> | ||
| 252 | #else /* NEED_FTIME */ | ||
| 253 | /* use native WIN32 time API */ | ||
| 254 | #endif /* NEED_FTIME */ | ||
| 255 | |||
| 256 | #if defined(HAVE_SIGNAL_H) | ||
| 257 | #include <signal.h> | ||
| 258 | #endif /* HAVE_SIGNAL_H */ | ||
| 259 | |||
| 260 | #include <limits.h> | ||
| 261 | |||
| 262 | /* | ||
| 263 | * Boolean values to make us independent of system includes. | ||
| 264 | */ | ||
| 265 | enum { | ||
| 266 | PTW32_FALSE = 0, | ||
| 267 | PTW32_TRUE = (! PTW32_FALSE) | ||
| 268 | }; | ||
| 269 | |||
| 270 | /* | ||
| 271 | * This is a duplicate of what is in the autoconf config.h, | ||
| 272 | * which is only used when building the pthread-win32 libraries. | ||
| 273 | */ | ||
| 274 | |||
| 275 | #if !defined(PTW32_CONFIG_H) | ||
| 276 | # if defined(WINCE) | ||
| 277 | # define NEED_ERRNO | ||
| 278 | # define NEED_SEM | ||
| 279 | # endif | ||
| 280 | # if defined(__MINGW64__) | ||
| 281 | # define HAVE_STRUCT_TIMESPEC | ||
| 282 | # define HAVE_MODE_T | ||
| 283 | # elif defined(_UWIN) || defined(__MINGW32__) | ||
| 284 | # define HAVE_MODE_T | ||
| 285 | # endif | ||
| 286 | #endif | ||
| 287 | |||
| 288 | /* | ||
| 289 | * | ||
| 290 | */ | ||
| 291 | |||
| 292 | #if PTW32_LEVEL >= PTW32_LEVEL_MAX | ||
| 293 | #if defined(NEED_ERRNO) | ||
| 294 | #include "need_errno.h" | ||
| 295 | #else | ||
| 296 | #include <errno.h> | ||
| 297 | #endif | ||
| 298 | #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ | ||
| 299 | |||
| 300 | /* | ||
| 301 | * Several systems don't define some error numbers. | ||
| 302 | */ | ||
| 303 | #if !defined(ENOTSUP) | ||
| 304 | # define ENOTSUP 48 /* This is the value in Solaris. */ | ||
| 305 | #endif | ||
| 306 | |||
| 307 | #if !defined(ETIMEDOUT) | ||
| 308 | # define ETIMEDOUT 10060 /* Same as WSAETIMEDOUT */ | ||
| 309 | #endif | ||
| 310 | |||
| 311 | #if !defined(ENOSYS) | ||
| 312 | # define ENOSYS 140 /* Semi-arbitrary value */ | ||
| 313 | #endif | ||
| 314 | |||
| 315 | #if !defined(EDEADLK) | ||
| 316 | # if defined(EDEADLOCK) | ||
| 317 | # define EDEADLK EDEADLOCK | ||
| 318 | # else | ||
| 319 | # define EDEADLK 36 /* This is the value in MSVC. */ | ||
| 320 | # endif | ||
| 321 | #endif | ||
| 322 | |||
| 323 | /* POSIX 2008 - related to robust mutexes */ | ||
| 324 | #if !defined(EOWNERDEAD) | ||
| 325 | # define EOWNERDEAD 43 | ||
| 326 | #endif | ||
| 327 | #if !defined(ENOTRECOVERABLE) | ||
| 328 | # define ENOTRECOVERABLE 44 | ||
| 329 | #endif | ||
| 330 | |||
| 331 | #include <sched.h> | ||
| 332 | |||
| 333 | /* | ||
| 334 | * To avoid including windows.h we define only those things that we | ||
| 335 | * actually need from it. | ||
| 336 | */ | ||
| 337 | #if !defined(PTW32_INCLUDE_WINDOWS_H) | ||
| 338 | #if !defined(HANDLE) | ||
| 339 | # define PTW32__HANDLE_DEF | ||
| 340 | # define HANDLE void * | ||
| 341 | #endif | ||
| 342 | #if !defined(DWORD) | ||
| 343 | # define PTW32__DWORD_DEF | ||
| 344 | # define DWORD unsigned long | ||
| 345 | #endif | ||
| 346 | #endif | ||
| 347 | |||
| 348 | #if !defined(HAVE_STRUCT_TIMESPEC) | ||
| 349 | #define HAVE_STRUCT_TIMESPEC | ||
| 350 | #if !defined(_TIMESPEC_DEFINED) | ||
| 351 | #define _TIMESPEC_DEFINED | ||
| 352 | struct timespec { | ||
| 353 | time_t tv_sec; | ||
| 354 | long tv_nsec; | ||
| 355 | }; | ||
| 356 | #endif /* _TIMESPEC_DEFINED */ | ||
| 357 | #endif /* HAVE_STRUCT_TIMESPEC */ | ||
| 358 | |||
| 359 | #if !defined(SIG_BLOCK) | ||
| 360 | #define SIG_BLOCK 0 | ||
| 361 | #endif /* SIG_BLOCK */ | ||
| 362 | |||
| 363 | #if !defined(SIG_UNBLOCK) | ||
| 364 | #define SIG_UNBLOCK 1 | ||
| 365 | #endif /* SIG_UNBLOCK */ | ||
| 366 | |||
| 367 | #if !defined(SIG_SETMASK) | ||
| 368 | #define SIG_SETMASK 2 | ||
| 369 | #endif /* SIG_SETMASK */ | ||
| 370 | |||
| 371 | #if defined(__cplusplus) | ||
| 372 | extern "C" | ||
| 373 | { | ||
| 374 | #endif /* __cplusplus */ | ||
| 375 | |||
| 376 | /* | ||
| 377 | * ------------------------------------------------------------- | ||
| 378 | * | ||
| 379 | * POSIX 1003.1-2001 Options | ||
| 380 | * ========================= | ||
| 381 | * | ||
| 382 | * Options are normally set in <unistd.h>, which is not provided | ||
| 383 | * with pthreads-win32. | ||
| 384 | * | ||
| 385 | * For conformance with the Single Unix Specification (version 3), all of the | ||
| 386 | * options below are defined, and have a value of either -1 (not supported) | ||
| 387 | * or 200112L (supported). | ||
| 388 | * | ||
| 389 | * These options can neither be left undefined nor have a value of 0, because | ||
| 390 | * either indicates that sysconf(), which is not implemented, may be used at | ||
| 391 | * runtime to check the status of the option. | ||
| 392 | * | ||
| 393 | * _POSIX_THREADS (== 200112L) | ||
| 394 | * If == 200112L, you can use threads | ||
| 395 | * | ||
| 396 | * _POSIX_THREAD_ATTR_STACKSIZE (== 200112L) | ||
| 397 | * If == 200112L, you can control the size of a thread's | ||
| 398 | * stack | ||
| 399 | * pthread_attr_getstacksize | ||
| 400 | * pthread_attr_setstacksize | ||
| 401 | * | ||
| 402 | * _POSIX_THREAD_ATTR_STACKADDR (== -1) | ||
| 403 | * If == 200112L, you can allocate and control a thread's | ||
| 404 | * stack. If not supported, the following functions | ||
| 405 | * will return ENOSYS, indicating they are not | ||
| 406 | * supported: | ||
| 407 | * pthread_attr_getstackaddr | ||
| 408 | * pthread_attr_setstackaddr | ||
| 409 | * | ||
| 410 | * _POSIX_THREAD_PRIORITY_SCHEDULING (== -1) | ||
| 411 | * If == 200112L, you can use realtime scheduling. | ||
| 412 | * This option indicates that the behaviour of some | ||
| 413 | * implemented functions conforms to the additional TPS | ||
| 414 | * requirements in the standard. E.g. rwlocks favour | ||
| 415 | * writers over readers when threads have equal priority. | ||
| 416 | * | ||
| 417 | * _POSIX_THREAD_PRIO_INHERIT (== -1) | ||
| 418 | * If == 200112L, you can create priority inheritance | ||
| 419 | * mutexes. | ||
| 420 | * pthread_mutexattr_getprotocol + | ||
| 421 | * pthread_mutexattr_setprotocol + | ||
| 422 | * | ||
| 423 | * _POSIX_THREAD_PRIO_PROTECT (== -1) | ||
| 424 | * If == 200112L, you can create priority ceiling mutexes | ||
| 425 | * Indicates the availability of: | ||
| 426 | * pthread_mutex_getprioceiling | ||
| 427 | * pthread_mutex_setprioceiling | ||
| 428 | * pthread_mutexattr_getprioceiling | ||
| 429 | * pthread_mutexattr_getprotocol + | ||
| 430 | * pthread_mutexattr_setprioceiling | ||
| 431 | * pthread_mutexattr_setprotocol + | ||
| 432 | * | ||
| 433 | * _POSIX_THREAD_PROCESS_SHARED (== -1) | ||
| 434 | * If set, you can create mutexes and condition | ||
| 435 | * variables that can be shared with another | ||
| 436 | * process.If set, indicates the availability | ||
| 437 | * of: | ||
| 438 | * pthread_mutexattr_getpshared | ||
| 439 | * pthread_mutexattr_setpshared | ||
| 440 | * pthread_condattr_getpshared | ||
| 441 | * pthread_condattr_setpshared | ||
| 442 | * | ||
| 443 | * _POSIX_THREAD_SAFE_FUNCTIONS (== 200112L) | ||
| 444 | * If == 200112L you can use the special *_r library | ||
| 445 | * functions that provide thread-safe behaviour | ||
| 446 | * | ||
| 447 | * _POSIX_READER_WRITER_LOCKS (== 200112L) | ||
| 448 | * If == 200112L, you can use read/write locks | ||
| 449 | * | ||
| 450 | * _POSIX_SPIN_LOCKS (== 200112L) | ||
| 451 | * If == 200112L, you can use spin locks | ||
| 452 | * | ||
| 453 | * _POSIX_BARRIERS (== 200112L) | ||
| 454 | * If == 200112L, you can use barriers | ||
| 455 | * | ||
| 456 | * + These functions provide both 'inherit' and/or | ||
| 457 | * 'protect' protocol, based upon these macro | ||
| 458 | * settings. | ||
| 459 | * | ||
| 460 | * ------------------------------------------------------------- | ||
| 461 | */ | ||
| 462 | |||
| 463 | /* | ||
| 464 | * POSIX Options | ||
| 465 | */ | ||
| 466 | #undef _POSIX_THREADS | ||
| 467 | #define _POSIX_THREADS 200809L | ||
| 468 | |||
| 469 | #undef _POSIX_READER_WRITER_LOCKS | ||
| 470 | #define _POSIX_READER_WRITER_LOCKS 200809L | ||
| 471 | |||
| 472 | #undef _POSIX_SPIN_LOCKS | ||
| 473 | #define _POSIX_SPIN_LOCKS 200809L | ||
| 474 | |||
| 475 | #undef _POSIX_BARRIERS | ||
| 476 | #define _POSIX_BARRIERS 200809L | ||
| 477 | |||
| 478 | #undef _POSIX_THREAD_SAFE_FUNCTIONS | ||
| 479 | #define _POSIX_THREAD_SAFE_FUNCTIONS 200809L | ||
| 480 | |||
| 481 | #undef _POSIX_THREAD_ATTR_STACKSIZE | ||
| 482 | #define _POSIX_THREAD_ATTR_STACKSIZE 200809L | ||
| 483 | |||
| 484 | /* | ||
| 485 | * The following options are not supported | ||
| 486 | */ | ||
| 487 | #undef _POSIX_THREAD_ATTR_STACKADDR | ||
| 488 | #define _POSIX_THREAD_ATTR_STACKADDR -1 | ||
| 489 | |||
| 490 | #undef _POSIX_THREAD_PRIO_INHERIT | ||
| 491 | #define _POSIX_THREAD_PRIO_INHERIT -1 | ||
| 492 | |||
| 493 | #undef _POSIX_THREAD_PRIO_PROTECT | ||
| 494 | #define _POSIX_THREAD_PRIO_PROTECT -1 | ||
| 495 | |||
| 496 | /* TPS is not fully supported. */ | ||
| 497 | #undef _POSIX_THREAD_PRIORITY_SCHEDULING | ||
| 498 | #define _POSIX_THREAD_PRIORITY_SCHEDULING -1 | ||
| 499 | |||
| 500 | #undef _POSIX_THREAD_PROCESS_SHARED | ||
| 501 | #define _POSIX_THREAD_PROCESS_SHARED -1 | ||
| 502 | |||
| 503 | |||
| 504 | /* | ||
| 505 | * POSIX 1003.1-2001 Limits | ||
| 506 | * =========================== | ||
| 507 | * | ||
| 508 | * These limits are normally set in <limits.h>, which is not provided with | ||
| 509 | * pthreads-win32. | ||
| 510 | * | ||
| 511 | * PTHREAD_DESTRUCTOR_ITERATIONS | ||
| 512 | * Maximum number of attempts to destroy | ||
| 513 | * a thread's thread-specific data on | ||
| 514 | * termination (must be at least 4) | ||
| 515 | * | ||
| 516 | * PTHREAD_KEYS_MAX | ||
| 517 | * Maximum number of thread-specific data keys | ||
| 518 | * available per process (must be at least 128) | ||
| 519 | * | ||
| 520 | * PTHREAD_STACK_MIN | ||
| 521 | * Minimum supported stack size for a thread | ||
| 522 | * | ||
| 523 | * PTHREAD_THREADS_MAX | ||
| 524 | * Maximum number of threads supported per | ||
| 525 | * process (must be at least 64). | ||
| 526 | * | ||
| 527 | * SEM_NSEMS_MAX | ||
| 528 | * The maximum number of semaphores a process can have. | ||
| 529 | * (must be at least 256) | ||
| 530 | * | ||
| 531 | * SEM_VALUE_MAX | ||
| 532 | * The maximum value a semaphore can have. | ||
| 533 | * (must be at least 32767) | ||
| 534 | * | ||
| 535 | */ | ||
| 536 | #undef _POSIX_THREAD_DESTRUCTOR_ITERATIONS | ||
| 537 | #define _POSIX_THREAD_DESTRUCTOR_ITERATIONS 4 | ||
| 538 | |||
| 539 | #undef PTHREAD_DESTRUCTOR_ITERATIONS | ||
| 540 | #define PTHREAD_DESTRUCTOR_ITERATIONS _POSIX_THREAD_DESTRUCTOR_ITERATIONS | ||
| 541 | |||
| 542 | #undef _POSIX_THREAD_KEYS_MAX | ||
| 543 | #define _POSIX_THREAD_KEYS_MAX 128 | ||
| 544 | |||
| 545 | #undef PTHREAD_KEYS_MAX | ||
| 546 | #define PTHREAD_KEYS_MAX _POSIX_THREAD_KEYS_MAX | ||
| 547 | |||
| 548 | #undef PTHREAD_STACK_MIN | ||
| 549 | #define PTHREAD_STACK_MIN 0 | ||
| 550 | |||
| 551 | #undef _POSIX_THREAD_THREADS_MAX | ||
| 552 | #define _POSIX_THREAD_THREADS_MAX 64 | ||
| 553 | |||
| 554 | /* Arbitrary value */ | ||
| 555 | #undef PTHREAD_THREADS_MAX | ||
| 556 | #define PTHREAD_THREADS_MAX 2019 | ||
| 557 | |||
| 558 | #undef _POSIX_SEM_NSEMS_MAX | ||
| 559 | #define _POSIX_SEM_NSEMS_MAX 256 | ||
| 560 | |||
| 561 | /* Arbitrary value */ | ||
| 562 | #undef SEM_NSEMS_MAX | ||
| 563 | #define SEM_NSEMS_MAX 1024 | ||
| 564 | |||
| 565 | #undef _POSIX_SEM_VALUE_MAX | ||
| 566 | #define _POSIX_SEM_VALUE_MAX 32767 | ||
| 567 | |||
| 568 | #undef SEM_VALUE_MAX | ||
| 569 | #define SEM_VALUE_MAX INT_MAX | ||
| 570 | |||
| 571 | |||
| 572 | #if defined(__GNUC__) && !defined(__declspec) | ||
| 573 | # error Please upgrade your GNU compiler to one that supports __declspec. | ||
| 574 | #endif | ||
| 575 | |||
| 576 | /* | ||
| 577 | * When building the library, you should define PTW32_BUILD so that | ||
| 578 | * the variables/functions are exported correctly. When using the library, | ||
| 579 | * do NOT define PTW32_BUILD, and then the variables/functions will | ||
| 580 | * be imported correctly. | ||
| 581 | */ | ||
| 582 | #if !defined(PTW32_STATIC_LIB) | ||
| 583 | # if defined(PTW32_BUILD) | ||
| 584 | # define PTW32_DLLPORT __declspec (dllexport) | ||
| 585 | # else | ||
| 586 | # define PTW32_DLLPORT __declspec (dllimport) | ||
| 587 | # endif | ||
| 588 | #else | ||
| 589 | # define PTW32_DLLPORT | ||
| 590 | #endif | ||
| 591 | |||
| 592 | /* | ||
| 593 | * The Open Watcom C/C++ compiler uses a non-standard calling convention | ||
| 594 | * that passes function args in registers unless __cdecl is explicitly specified | ||
| 595 | * in exposed function prototypes. | ||
| 596 | * | ||
| 597 | * We force all calls to cdecl even though this could slow Watcom code down | ||
| 598 | * slightly. If you know that the Watcom compiler will be used to build both | ||
| 599 | * the DLL and application, then you can probably define this as a null string. | ||
| 600 | * Remember that pthread.h (this file) is used for both the DLL and application builds. | ||
| 601 | */ | ||
| 602 | #define PTW32_CDECL __cdecl | ||
| 603 | |||
| 604 | #if defined(_UWIN) && PTW32_LEVEL >= PTW32_LEVEL_MAX | ||
| 605 | # include <sys/types.h> | ||
| 606 | #else | ||
| 607 | /* | ||
| 608 | * Generic handle type - intended to extend uniqueness beyond | ||
| 609 | * that available with a simple pointer. It should scale for either | ||
| 610 | * IA-32 or IA-64. | ||
| 611 | */ | ||
| 612 | typedef struct { | ||
| 613 | void * p; /* Pointer to actual object */ | ||
| 614 | unsigned int x; /* Extra information - reuse count etc */ | ||
| 615 | } ptw32_handle_t; | ||
| 616 | |||
| 617 | typedef ptw32_handle_t pthread_t; | ||
| 618 | typedef struct pthread_attr_t_ * pthread_attr_t; | ||
| 619 | typedef struct pthread_once_t_ pthread_once_t; | ||
| 620 | typedef struct pthread_key_t_ * pthread_key_t; | ||
| 621 | typedef struct pthread_mutex_t_ * pthread_mutex_t; | ||
| 622 | typedef struct pthread_mutexattr_t_ * pthread_mutexattr_t; | ||
| 623 | typedef struct pthread_cond_t_ * pthread_cond_t; | ||
| 624 | typedef struct pthread_condattr_t_ * pthread_condattr_t; | ||
| 625 | #endif | ||
| 626 | typedef struct pthread_rwlock_t_ * pthread_rwlock_t; | ||
| 627 | typedef struct pthread_rwlockattr_t_ * pthread_rwlockattr_t; | ||
| 628 | typedef struct pthread_spinlock_t_ * pthread_spinlock_t; | ||
| 629 | typedef struct pthread_barrier_t_ * pthread_barrier_t; | ||
| 630 | typedef struct pthread_barrierattr_t_ * pthread_barrierattr_t; | ||
| 631 | |||
| 632 | /* | ||
| 633 | * ==================== | ||
| 634 | * ==================== | ||
| 635 | * POSIX Threads | ||
| 636 | * ==================== | ||
| 637 | * ==================== | ||
| 638 | */ | ||
| 639 | |||
| 640 | enum { | ||
| 641 | /* | ||
| 642 | * pthread_attr_{get,set}detachstate | ||
| 643 | */ | ||
| 644 | PTHREAD_CREATE_JOINABLE = 0, /* Default */ | ||
| 645 | PTHREAD_CREATE_DETACHED = 1, | ||
| 646 | |||
| 647 | /* | ||
| 648 | * pthread_attr_{get,set}inheritsched | ||
| 649 | */ | ||
| 650 | PTHREAD_INHERIT_SCHED = 0, | ||
| 651 | PTHREAD_EXPLICIT_SCHED = 1, /* Default */ | ||
| 652 | |||
| 653 | /* | ||
| 654 | * pthread_{get,set}scope | ||
| 655 | */ | ||
| 656 | PTHREAD_SCOPE_PROCESS = 0, | ||
| 657 | PTHREAD_SCOPE_SYSTEM = 1, /* Default */ | ||
| 658 | |||
| 659 | /* | ||
| 660 | * pthread_setcancelstate paramters | ||
| 661 | */ | ||
| 662 | PTHREAD_CANCEL_ENABLE = 0, /* Default */ | ||
| 663 | PTHREAD_CANCEL_DISABLE = 1, | ||
| 664 | |||
| 665 | /* | ||
| 666 | * pthread_setcanceltype parameters | ||
| 667 | */ | ||
| 668 | PTHREAD_CANCEL_ASYNCHRONOUS = 0, | ||
| 669 | PTHREAD_CANCEL_DEFERRED = 1, /* Default */ | ||
| 670 | |||
| 671 | /* | ||
| 672 | * pthread_mutexattr_{get,set}pshared | ||
| 673 | * pthread_condattr_{get,set}pshared | ||
| 674 | */ | ||
| 675 | PTHREAD_PROCESS_PRIVATE = 0, | ||
| 676 | PTHREAD_PROCESS_SHARED = 1, | ||
| 677 | |||
| 678 | /* | ||
| 679 | * pthread_mutexattr_{get,set}robust | ||
| 680 | */ | ||
| 681 | PTHREAD_MUTEX_STALLED = 0, /* Default */ | ||
| 682 | PTHREAD_MUTEX_ROBUST = 1, | ||
| 683 | |||
| 684 | /* | ||
| 685 | * pthread_barrier_wait | ||
| 686 | */ | ||
| 687 | PTHREAD_BARRIER_SERIAL_THREAD = -1 | ||
| 688 | }; | ||
| 689 | |||
| 690 | /* | ||
| 691 | * ==================== | ||
| 692 | * ==================== | ||
| 693 | * cancellation | ||
| 694 | * ==================== | ||
| 695 | * ==================== | ||
| 696 | */ | ||
| 697 | #define PTHREAD_CANCELED ((void *)(size_t) -1) | ||
| 698 | |||
| 699 | |||
| 700 | /* | ||
| 701 | * ==================== | ||
| 702 | * ==================== | ||
| 703 | * Once Key | ||
| 704 | * ==================== | ||
| 705 | * ==================== | ||
| 706 | */ | ||
| 707 | #define PTHREAD_ONCE_INIT { PTW32_FALSE, 0, 0, 0} | ||
| 708 | |||
| 709 | struct pthread_once_t_ | ||
| 710 | { | ||
| 711 | int done; /* indicates if user function has been executed */ | ||
| 712 | void * lock; | ||
| 713 | int reserved1; | ||
| 714 | int reserved2; | ||
| 715 | }; | ||
| 716 | |||
| 717 | |||
| 718 | /* | ||
| 719 | * ==================== | ||
| 720 | * ==================== | ||
| 721 | * Object initialisers | ||
| 722 | * ==================== | ||
| 723 | * ==================== | ||
| 724 | */ | ||
| 725 | #define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -1) | ||
| 726 | #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -2) | ||
| 727 | #define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER ((pthread_mutex_t)(size_t) -3) | ||
| 728 | |||
| 729 | /* | ||
| 730 | * Compatibility with LinuxThreads | ||
| 731 | */ | ||
| 732 | #define PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP PTHREAD_RECURSIVE_MUTEX_INITIALIZER | ||
| 733 | #define PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP PTHREAD_ERRORCHECK_MUTEX_INITIALIZER | ||
| 734 | |||
| 735 | #define PTHREAD_COND_INITIALIZER ((pthread_cond_t)(size_t) -1) | ||
| 736 | |||
| 737 | #define PTHREAD_RWLOCK_INITIALIZER ((pthread_rwlock_t)(size_t) -1) | ||
| 738 | |||
| 739 | #define PTHREAD_SPINLOCK_INITIALIZER ((pthread_spinlock_t)(size_t) -1) | ||
| 740 | |||
| 741 | |||
| 742 | /* | ||
| 743 | * Mutex types. | ||
| 744 | */ | ||
| 745 | enum | ||
| 746 | { | ||
| 747 | /* Compatibility with LinuxThreads */ | ||
| 748 | PTHREAD_MUTEX_FAST_NP, | ||
| 749 | PTHREAD_MUTEX_RECURSIVE_NP, | ||
| 750 | PTHREAD_MUTEX_ERRORCHECK_NP, | ||
| 751 | PTHREAD_MUTEX_TIMED_NP = PTHREAD_MUTEX_FAST_NP, | ||
| 752 | PTHREAD_MUTEX_ADAPTIVE_NP = PTHREAD_MUTEX_FAST_NP, | ||
| 753 | /* For compatibility with POSIX */ | ||
| 754 | PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_FAST_NP, | ||
| 755 | PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP, | ||
| 756 | PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP, | ||
| 757 | PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL | ||
| 758 | }; | ||
| 759 | |||
| 760 | |||
| 761 | typedef struct ptw32_cleanup_t ptw32_cleanup_t; | ||
| 762 | |||
| 763 | #if defined(_MSC_VER) | ||
| 764 | /* Disable MSVC 'anachronism used' warning */ | ||
| 765 | #pragma warning( disable : 4229 ) | ||
| 766 | #endif | ||
| 767 | |||
| 768 | typedef void (* PTW32_CDECL ptw32_cleanup_callback_t)(void *); | ||
| 769 | |||
| 770 | #if defined(_MSC_VER) | ||
| 771 | #pragma warning( default : 4229 ) | ||
| 772 | #endif | ||
| 773 | |||
| 774 | struct ptw32_cleanup_t | ||
| 775 | { | ||
| 776 | ptw32_cleanup_callback_t routine; | ||
| 777 | void *arg; | ||
| 778 | struct ptw32_cleanup_t *prev; | ||
| 779 | }; | ||
| 780 | |||
| 781 | #if defined(__CLEANUP_SEH) | ||
| 782 | /* | ||
| 783 | * WIN32 SEH version of cancel cleanup. | ||
| 784 | */ | ||
| 785 | |||
| 786 | #define pthread_cleanup_push( _rout, _arg ) \ | ||
| 787 | { \ | ||
| 788 | ptw32_cleanup_t _cleanup; \ | ||
| 789 | \ | ||
| 790 | _cleanup.routine = (ptw32_cleanup_callback_t)(_rout); \ | ||
| 791 | _cleanup.arg = (_arg); \ | ||
| 792 | __try \ | ||
| 793 | { \ | ||
| 794 | |||
| 795 | #define pthread_cleanup_pop( _execute ) \ | ||
| 796 | } \ | ||
| 797 | __finally \ | ||
| 798 | { \ | ||
| 799 | if( _execute || AbnormalTermination()) \ | ||
| 800 | { \ | ||
| 801 | (*(_cleanup.routine))( _cleanup.arg ); \ | ||
| 802 | } \ | ||
| 803 | } \ | ||
| 804 | } | ||
| 805 | |||
| 806 | #else /* __CLEANUP_SEH */ | ||
| 807 | |||
| 808 | #if defined(__CLEANUP_C) | ||
| 809 | |||
| 810 | /* | ||
| 811 | * C implementation of PThreads cancel cleanup | ||
| 812 | */ | ||
| 813 | |||
| 814 | #define pthread_cleanup_push( _rout, _arg ) \ | ||
| 815 | { \ | ||
| 816 | ptw32_cleanup_t _cleanup; \ | ||
| 817 | \ | ||
| 818 | ptw32_push_cleanup( &_cleanup, (ptw32_cleanup_callback_t) (_rout), (_arg) ); \ | ||
| 819 | |||
| 820 | #define pthread_cleanup_pop( _execute ) \ | ||
| 821 | (void) ptw32_pop_cleanup( _execute ); \ | ||
| 822 | } | ||
| 823 | |||
| 824 | #else /* __CLEANUP_C */ | ||
| 825 | |||
| 826 | #if defined(__CLEANUP_CXX) | ||
| 827 | |||
| 828 | /* | ||
| 829 | * C++ version of cancel cleanup. | ||
| 830 | * - John E. Bossom. | ||
| 831 | */ | ||
| 832 | |||
| 833 | class PThreadCleanup { | ||
| 834 | /* | ||
| 835 | * PThreadCleanup | ||
| 836 | * | ||
| 837 | * Purpose | ||
| 838 | * This class is a C++ helper class that is | ||
| 839 | * used to implement pthread_cleanup_push/ | ||
| 840 | * pthread_cleanup_pop. | ||
| 841 | * The destructor of this class automatically | ||
| 842 | * pops the pushed cleanup routine regardless | ||
| 843 | * of how the code exits the scope | ||
| 844 | * (i.e. such as by an exception) | ||
| 845 | */ | ||
| 846 | ptw32_cleanup_callback_t cleanUpRout; | ||
| 847 | void * obj; | ||
| 848 | int executeIt; | ||
| 849 | |||
| 850 | public: | ||
| 851 | PThreadCleanup() : | ||
| 852 | cleanUpRout( 0 ), | ||
| 853 | obj( 0 ), | ||
| 854 | executeIt( 0 ) | ||
| 855 | /* | ||
| 856 | * No cleanup performed | ||
| 857 | */ | ||
| 858 | { | ||
| 859 | } | ||
| 860 | |||
| 861 | PThreadCleanup( | ||
| 862 | ptw32_cleanup_callback_t routine, | ||
| 863 | void * arg ) : | ||
| 864 | cleanUpRout( routine ), | ||
| 865 | obj( arg ), | ||
| 866 | executeIt( 1 ) | ||
| 867 | /* | ||
| 868 | * Registers a cleanup routine for 'arg' | ||
| 869 | */ | ||
| 870 | { | ||
| 871 | } | ||
| 872 | |||
| 873 | ~PThreadCleanup() | ||
| 874 | { | ||
| 875 | if ( executeIt && ((void *) cleanUpRout != (void *) 0) ) | ||
| 876 | { | ||
| 877 | (void) (*cleanUpRout)( obj ); | ||
| 878 | } | ||
| 879 | } | ||
| 880 | |||
| 881 | void execute( int exec ) | ||
| 882 | { | ||
| 883 | executeIt = exec; | ||
| 884 | } | ||
| 885 | }; | ||
| 886 | |||
| 887 | /* | ||
| 888 | * C++ implementation of PThreads cancel cleanup; | ||
| 889 | * This implementation takes advantage of a helper | ||
| 890 | * class who's destructor automatically calls the | ||
| 891 | * cleanup routine if we exit our scope weirdly | ||
| 892 | */ | ||
| 893 | #define pthread_cleanup_push( _rout, _arg ) \ | ||
| 894 | { \ | ||
| 895 | PThreadCleanup cleanup((ptw32_cleanup_callback_t)(_rout), \ | ||
| 896 | (void *) (_arg) ); | ||
| 897 | |||
| 898 | #define pthread_cleanup_pop( _execute ) \ | ||
| 899 | cleanup.execute( _execute ); \ | ||
| 900 | } | ||
| 901 | |||
| 902 | #else | ||
| 903 | |||
| 904 | #error ERROR [__FILE__, line __LINE__]: Cleanup type undefined. | ||
| 905 | |||
| 906 | #endif /* __CLEANUP_CXX */ | ||
| 907 | |||
| 908 | #endif /* __CLEANUP_C */ | ||
| 909 | |||
| 910 | #endif /* __CLEANUP_SEH */ | ||
| 911 | |||
| 912 | /* | ||
| 913 | * =============== | ||
| 914 | * =============== | ||
| 915 | * Methods | ||
| 916 | * =============== | ||
| 917 | * =============== | ||
| 918 | */ | ||
| 919 | |||
| 920 | /* | ||
| 921 | * PThread Attribute Functions | ||
| 922 | */ | ||
| 923 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_init (pthread_attr_t * attr); | ||
| 924 | |||
| 925 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_destroy (pthread_attr_t * attr); | ||
| 926 | |||
| 927 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_getdetachstate (const pthread_attr_t * attr, | ||
| 928 | int *detachstate); | ||
| 929 | |||
| 930 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstackaddr (const pthread_attr_t * attr, | ||
| 931 | void **stackaddr); | ||
| 932 | |||
| 933 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_getstacksize (const pthread_attr_t * attr, | ||
| 934 | size_t * stacksize); | ||
| 935 | |||
| 936 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_setdetachstate (pthread_attr_t * attr, | ||
| 937 | int detachstate); | ||
| 938 | |||
| 939 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstackaddr (pthread_attr_t * attr, | ||
| 940 | void *stackaddr); | ||
| 941 | |||
| 942 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_setstacksize (pthread_attr_t * attr, | ||
| 943 | size_t stacksize); | ||
| 944 | |||
| 945 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedparam (const pthread_attr_t *attr, | ||
| 946 | struct sched_param *param); | ||
| 947 | |||
| 948 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedparam (pthread_attr_t *attr, | ||
| 949 | const struct sched_param *param); | ||
| 950 | |||
| 951 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_setschedpolicy (pthread_attr_t *, | ||
| 952 | int); | ||
| 953 | |||
| 954 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_getschedpolicy (const pthread_attr_t *, | ||
| 955 | int *); | ||
| 956 | |||
| 957 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_setinheritsched(pthread_attr_t * attr, | ||
| 958 | int inheritsched); | ||
| 959 | |||
| 960 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_getinheritsched(const pthread_attr_t * attr, | ||
| 961 | int * inheritsched); | ||
| 962 | |||
| 963 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_setscope (pthread_attr_t *, | ||
| 964 | int); | ||
| 965 | |||
| 966 | PTW32_DLLPORT int PTW32_CDECL pthread_attr_getscope (const pthread_attr_t *, | ||
| 967 | int *); | ||
| 968 | |||
| 969 | /* | ||
| 970 | * PThread Functions | ||
| 971 | */ | ||
| 972 | PTW32_DLLPORT int PTW32_CDECL pthread_create (pthread_t * tid, | ||
| 973 | const pthread_attr_t * attr, | ||
| 974 | void *(PTW32_CDECL *start) (void *), | ||
| 975 | void *arg); | ||
| 976 | |||
| 977 | PTW32_DLLPORT int PTW32_CDECL pthread_detach (pthread_t tid); | ||
| 978 | |||
| 979 | PTW32_DLLPORT int PTW32_CDECL pthread_equal (pthread_t t1, | ||
| 980 | pthread_t t2); | ||
| 981 | |||
| 982 | PTW32_DLLPORT void PTW32_CDECL pthread_exit (void *value_ptr); | ||
| 983 | |||
| 984 | PTW32_DLLPORT int PTW32_CDECL pthread_join (pthread_t thread, | ||
| 985 | void **value_ptr); | ||
| 986 | |||
| 987 | PTW32_DLLPORT pthread_t PTW32_CDECL pthread_self (void); | ||
| 988 | |||
| 989 | PTW32_DLLPORT int PTW32_CDECL pthread_cancel (pthread_t thread); | ||
| 990 | |||
| 991 | PTW32_DLLPORT int PTW32_CDECL pthread_setcancelstate (int state, | ||
| 992 | int *oldstate); | ||
| 993 | |||
| 994 | PTW32_DLLPORT int PTW32_CDECL pthread_setcanceltype (int type, | ||
| 995 | int *oldtype); | ||
| 996 | |||
| 997 | PTW32_DLLPORT void PTW32_CDECL pthread_testcancel (void); | ||
| 998 | |||
| 999 | PTW32_DLLPORT int PTW32_CDECL pthread_once (pthread_once_t * once_control, | ||
| 1000 | void (PTW32_CDECL *init_routine) (void)); | ||
| 1001 | |||
| 1002 | #if PTW32_LEVEL >= PTW32_LEVEL_MAX | ||
| 1003 | PTW32_DLLPORT ptw32_cleanup_t * PTW32_CDECL ptw32_pop_cleanup (int execute); | ||
| 1004 | |||
| 1005 | PTW32_DLLPORT void PTW32_CDECL ptw32_push_cleanup (ptw32_cleanup_t * cleanup, | ||
| 1006 | ptw32_cleanup_callback_t routine, | ||
| 1007 | void *arg); | ||
| 1008 | #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ | ||
| 1009 | |||
| 1010 | /* | ||
| 1011 | * Thread Specific Data Functions | ||
| 1012 | */ | ||
| 1013 | PTW32_DLLPORT int PTW32_CDECL pthread_key_create (pthread_key_t * key, | ||
| 1014 | void (PTW32_CDECL *destructor) (void *)); | ||
| 1015 | |||
| 1016 | PTW32_DLLPORT int PTW32_CDECL pthread_key_delete (pthread_key_t key); | ||
| 1017 | |||
| 1018 | PTW32_DLLPORT int PTW32_CDECL pthread_setspecific (pthread_key_t key, | ||
| 1019 | const void *value); | ||
| 1020 | |||
| 1021 | PTW32_DLLPORT void * PTW32_CDECL pthread_getspecific (pthread_key_t key); | ||
| 1022 | |||
| 1023 | |||
| 1024 | /* | ||
| 1025 | * Mutex Attribute Functions | ||
| 1026 | */ | ||
| 1027 | PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_init (pthread_mutexattr_t * attr); | ||
| 1028 | |||
| 1029 | PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_destroy (pthread_mutexattr_t * attr); | ||
| 1030 | |||
| 1031 | PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getpshared (const pthread_mutexattr_t | ||
| 1032 | * attr, | ||
| 1033 | int *pshared); | ||
| 1034 | |||
| 1035 | PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setpshared (pthread_mutexattr_t * attr, | ||
| 1036 | int pshared); | ||
| 1037 | |||
| 1038 | PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_settype (pthread_mutexattr_t * attr, int kind); | ||
| 1039 | PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_gettype (const pthread_mutexattr_t * attr, int *kind); | ||
| 1040 | |||
| 1041 | PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setrobust( | ||
| 1042 | pthread_mutexattr_t *attr, | ||
| 1043 | int robust); | ||
| 1044 | PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getrobust( | ||
| 1045 | const pthread_mutexattr_t * attr, | ||
| 1046 | int * robust); | ||
| 1047 | |||
| 1048 | /* | ||
| 1049 | * Barrier Attribute Functions | ||
| 1050 | */ | ||
| 1051 | PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_init (pthread_barrierattr_t * attr); | ||
| 1052 | |||
| 1053 | PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_destroy (pthread_barrierattr_t * attr); | ||
| 1054 | |||
| 1055 | PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_getpshared (const pthread_barrierattr_t | ||
| 1056 | * attr, | ||
| 1057 | int *pshared); | ||
| 1058 | |||
| 1059 | PTW32_DLLPORT int PTW32_CDECL pthread_barrierattr_setpshared (pthread_barrierattr_t * attr, | ||
| 1060 | int pshared); | ||
| 1061 | |||
| 1062 | /* | ||
| 1063 | * Mutex Functions | ||
| 1064 | */ | ||
| 1065 | PTW32_DLLPORT int PTW32_CDECL pthread_mutex_init (pthread_mutex_t * mutex, | ||
| 1066 | const pthread_mutexattr_t * attr); | ||
| 1067 | |||
| 1068 | PTW32_DLLPORT int PTW32_CDECL pthread_mutex_destroy (pthread_mutex_t * mutex); | ||
| 1069 | |||
| 1070 | PTW32_DLLPORT int PTW32_CDECL pthread_mutex_lock (pthread_mutex_t * mutex); | ||
| 1071 | |||
| 1072 | PTW32_DLLPORT int PTW32_CDECL pthread_mutex_timedlock(pthread_mutex_t * mutex, | ||
| 1073 | const struct timespec *abstime); | ||
| 1074 | |||
| 1075 | PTW32_DLLPORT int PTW32_CDECL pthread_mutex_trylock (pthread_mutex_t * mutex); | ||
| 1076 | |||
| 1077 | PTW32_DLLPORT int PTW32_CDECL pthread_mutex_unlock (pthread_mutex_t * mutex); | ||
| 1078 | |||
| 1079 | PTW32_DLLPORT int PTW32_CDECL pthread_mutex_consistent (pthread_mutex_t * mutex); | ||
| 1080 | |||
| 1081 | /* | ||
| 1082 | * Spinlock Functions | ||
| 1083 | */ | ||
| 1084 | PTW32_DLLPORT int PTW32_CDECL pthread_spin_init (pthread_spinlock_t * lock, int pshared); | ||
| 1085 | |||
| 1086 | PTW32_DLLPORT int PTW32_CDECL pthread_spin_destroy (pthread_spinlock_t * lock); | ||
| 1087 | |||
| 1088 | PTW32_DLLPORT int PTW32_CDECL pthread_spin_lock (pthread_spinlock_t * lock); | ||
| 1089 | |||
| 1090 | PTW32_DLLPORT int PTW32_CDECL pthread_spin_trylock (pthread_spinlock_t * lock); | ||
| 1091 | |||
| 1092 | PTW32_DLLPORT int PTW32_CDECL pthread_spin_unlock (pthread_spinlock_t * lock); | ||
| 1093 | |||
| 1094 | /* | ||
| 1095 | * Barrier Functions | ||
| 1096 | */ | ||
| 1097 | PTW32_DLLPORT int PTW32_CDECL pthread_barrier_init (pthread_barrier_t * barrier, | ||
| 1098 | const pthread_barrierattr_t * attr, | ||
| 1099 | unsigned int count); | ||
| 1100 | |||
| 1101 | PTW32_DLLPORT int PTW32_CDECL pthread_barrier_destroy (pthread_barrier_t * barrier); | ||
| 1102 | |||
| 1103 | PTW32_DLLPORT int PTW32_CDECL pthread_barrier_wait (pthread_barrier_t * barrier); | ||
| 1104 | |||
| 1105 | /* | ||
| 1106 | * Condition Variable Attribute Functions | ||
| 1107 | */ | ||
| 1108 | PTW32_DLLPORT int PTW32_CDECL pthread_condattr_init (pthread_condattr_t * attr); | ||
| 1109 | |||
| 1110 | PTW32_DLLPORT int PTW32_CDECL pthread_condattr_destroy (pthread_condattr_t * attr); | ||
| 1111 | |||
| 1112 | PTW32_DLLPORT int PTW32_CDECL pthread_condattr_getpshared (const pthread_condattr_t * attr, | ||
| 1113 | int *pshared); | ||
| 1114 | |||
| 1115 | PTW32_DLLPORT int PTW32_CDECL pthread_condattr_setpshared (pthread_condattr_t * attr, | ||
| 1116 | int pshared); | ||
| 1117 | |||
| 1118 | /* | ||
| 1119 | * Condition Variable Functions | ||
| 1120 | */ | ||
| 1121 | PTW32_DLLPORT int PTW32_CDECL pthread_cond_init (pthread_cond_t * cond, | ||
| 1122 | const pthread_condattr_t * attr); | ||
| 1123 | |||
| 1124 | PTW32_DLLPORT int PTW32_CDECL pthread_cond_destroy (pthread_cond_t * cond); | ||
| 1125 | |||
| 1126 | PTW32_DLLPORT int PTW32_CDECL pthread_cond_wait (pthread_cond_t * cond, | ||
| 1127 | pthread_mutex_t * mutex); | ||
| 1128 | |||
| 1129 | PTW32_DLLPORT int PTW32_CDECL pthread_cond_timedwait (pthread_cond_t * cond, | ||
| 1130 | pthread_mutex_t * mutex, | ||
| 1131 | const struct timespec *abstime); | ||
| 1132 | |||
| 1133 | PTW32_DLLPORT int PTW32_CDECL pthread_cond_signal (pthread_cond_t * cond); | ||
| 1134 | |||
| 1135 | PTW32_DLLPORT int PTW32_CDECL pthread_cond_broadcast (pthread_cond_t * cond); | ||
| 1136 | |||
| 1137 | /* | ||
| 1138 | * Scheduling | ||
| 1139 | */ | ||
| 1140 | PTW32_DLLPORT int PTW32_CDECL pthread_setschedparam (pthread_t thread, | ||
| 1141 | int policy, | ||
| 1142 | const struct sched_param *param); | ||
| 1143 | |||
| 1144 | PTW32_DLLPORT int PTW32_CDECL pthread_getschedparam (pthread_t thread, | ||
| 1145 | int *policy, | ||
| 1146 | struct sched_param *param); | ||
| 1147 | |||
| 1148 | PTW32_DLLPORT int PTW32_CDECL pthread_setconcurrency (int); | ||
| 1149 | |||
| 1150 | PTW32_DLLPORT int PTW32_CDECL pthread_getconcurrency (void); | ||
| 1151 | |||
| 1152 | /* | ||
| 1153 | * Read-Write Lock Functions | ||
| 1154 | */ | ||
| 1155 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_init(pthread_rwlock_t *lock, | ||
| 1156 | const pthread_rwlockattr_t *attr); | ||
| 1157 | |||
| 1158 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_destroy(pthread_rwlock_t *lock); | ||
| 1159 | |||
| 1160 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_tryrdlock(pthread_rwlock_t *); | ||
| 1161 | |||
| 1162 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_trywrlock(pthread_rwlock_t *); | ||
| 1163 | |||
| 1164 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_rdlock(pthread_rwlock_t *lock); | ||
| 1165 | |||
| 1166 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedrdlock(pthread_rwlock_t *lock, | ||
| 1167 | const struct timespec *abstime); | ||
| 1168 | |||
| 1169 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_wrlock(pthread_rwlock_t *lock); | ||
| 1170 | |||
| 1171 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_timedwrlock(pthread_rwlock_t *lock, | ||
| 1172 | const struct timespec *abstime); | ||
| 1173 | |||
| 1174 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlock_unlock(pthread_rwlock_t *lock); | ||
| 1175 | |||
| 1176 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_init (pthread_rwlockattr_t * attr); | ||
| 1177 | |||
| 1178 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_destroy (pthread_rwlockattr_t * attr); | ||
| 1179 | |||
| 1180 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_getpshared (const pthread_rwlockattr_t * attr, | ||
| 1181 | int *pshared); | ||
| 1182 | |||
| 1183 | PTW32_DLLPORT int PTW32_CDECL pthread_rwlockattr_setpshared (pthread_rwlockattr_t * attr, | ||
| 1184 | int pshared); | ||
| 1185 | |||
| 1186 | #if PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 | ||
| 1187 | |||
| 1188 | /* | ||
| 1189 | * Signal Functions. Should be defined in <signal.h> but MSVC and MinGW32 | ||
| 1190 | * already have signal.h that don't define these. | ||
| 1191 | */ | ||
| 1192 | PTW32_DLLPORT int PTW32_CDECL pthread_kill(pthread_t thread, int sig); | ||
| 1193 | |||
| 1194 | /* | ||
| 1195 | * Non-portable functions | ||
| 1196 | */ | ||
| 1197 | |||
| 1198 | /* | ||
| 1199 | * Compatibility with Linux. | ||
| 1200 | */ | ||
| 1201 | PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_setkind_np(pthread_mutexattr_t * attr, | ||
| 1202 | int kind); | ||
| 1203 | PTW32_DLLPORT int PTW32_CDECL pthread_mutexattr_getkind_np(pthread_mutexattr_t * attr, | ||
| 1204 | int *kind); | ||
| 1205 | PTW32_DLLPORT int PTW32_CDECL pthread_timedjoin_np(pthread_t thread, | ||
| 1206 | void **value_ptr, | ||
| 1207 | const struct timespec *abstime); | ||
| 1208 | |||
| 1209 | /* | ||
| 1210 | * Possibly supported by other POSIX threads implementations | ||
| 1211 | */ | ||
| 1212 | PTW32_DLLPORT int PTW32_CDECL pthread_delay_np (struct timespec * interval); | ||
| 1213 | PTW32_DLLPORT int PTW32_CDECL pthread_num_processors_np(void); | ||
| 1214 | PTW32_DLLPORT unsigned __int64 PTW32_CDECL pthread_getunique_np(pthread_t thread); | ||
| 1215 | |||
| 1216 | /* | ||
| 1217 | * Useful if an application wants to statically link | ||
| 1218 | * the lib rather than load the DLL at run-time. | ||
| 1219 | */ | ||
| 1220 | PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_attach_np(void); | ||
| 1221 | PTW32_DLLPORT int PTW32_CDECL pthread_win32_process_detach_np(void); | ||
| 1222 | PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_attach_np(void); | ||
| 1223 | PTW32_DLLPORT int PTW32_CDECL pthread_win32_thread_detach_np(void); | ||
| 1224 | |||
| 1225 | /* | ||
| 1226 | * Features that are auto-detected at load/run time. | ||
| 1227 | */ | ||
| 1228 | PTW32_DLLPORT int PTW32_CDECL pthread_win32_test_features_np(int); | ||
| 1229 | enum ptw32_features { | ||
| 1230 | PTW32_SYSTEM_INTERLOCKED_COMPARE_EXCHANGE = 0x0001, /* System provides it. */ | ||
| 1231 | PTW32_ALERTABLE_ASYNC_CANCEL = 0x0002 /* Can cancel blocked threads. */ | ||
| 1232 | }; | ||
| 1233 | |||
| 1234 | /* | ||
| 1235 | * Register a system time change with the library. | ||
| 1236 | * Causes the library to perform various functions | ||
| 1237 | * in response to the change. Should be called whenever | ||
| 1238 | * the application's top level window receives a | ||
| 1239 | * WM_TIMECHANGE message. It can be passed directly to | ||
| 1240 | * pthread_create() as a new thread if desired. | ||
| 1241 | */ | ||
| 1242 | PTW32_DLLPORT void * PTW32_CDECL pthread_timechange_handler_np(void *); | ||
| 1243 | |||
| 1244 | #endif /*PTW32_LEVEL >= PTW32_LEVEL_MAX - 1 */ | ||
| 1245 | |||
| 1246 | #if PTW32_LEVEL >= PTW32_LEVEL_MAX | ||
| 1247 | |||
| 1248 | /* | ||
| 1249 | * Returns the Win32 HANDLE for the POSIX thread. | ||
| 1250 | */ | ||
| 1251 | PTW32_DLLPORT HANDLE PTW32_CDECL pthread_getw32threadhandle_np(pthread_t thread); | ||
| 1252 | /* | ||
| 1253 | * Returns the win32 thread ID for POSIX thread. | ||
| 1254 | */ | ||
| 1255 | PTW32_DLLPORT DWORD PTW32_CDECL pthread_getw32threadid_np (pthread_t thread); | ||
| 1256 | |||
| 1257 | |||
| 1258 | /* | ||
| 1259 | * Protected Methods | ||
| 1260 | * | ||
| 1261 | * This function blocks until the given WIN32 handle | ||
| 1262 | * is signaled or pthread_cancel had been called. | ||
| 1263 | * This function allows the caller to hook into the | ||
| 1264 | * PThreads cancel mechanism. It is implemented using | ||
| 1265 | * | ||
| 1266 | * WaitForMultipleObjects | ||
| 1267 | * | ||
| 1268 | * on 'waitHandle' and a manually reset WIN32 Event | ||
| 1269 | * used to implement pthread_cancel. The 'timeout' | ||
| 1270 | * argument to TimedWait is simply passed to | ||
| 1271 | * WaitForMultipleObjects. | ||
| 1272 | */ | ||
| 1273 | PTW32_DLLPORT int PTW32_CDECL pthreadCancelableWait (HANDLE waitHandle); | ||
| 1274 | PTW32_DLLPORT int PTW32_CDECL pthreadCancelableTimedWait (HANDLE waitHandle, | ||
| 1275 | DWORD timeout); | ||
| 1276 | |||
| 1277 | #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ | ||
| 1278 | |||
| 1279 | /* | ||
| 1280 | * Thread-Safe C Runtime Library Mappings. | ||
| 1281 | */ | ||
| 1282 | #if !defined(_UWIN) | ||
| 1283 | # if defined(NEED_ERRNO) | ||
| 1284 | PTW32_DLLPORT int * PTW32_CDECL _errno( void ); | ||
| 1285 | # else | ||
| 1286 | # if !defined(errno) | ||
| 1287 | # if (defined(_MT) || defined(_DLL)) | ||
| 1288 | __declspec(dllimport) extern int * __cdecl _errno(void); | ||
| 1289 | # define errno (*_errno()) | ||
| 1290 | # endif | ||
| 1291 | # endif | ||
| 1292 | # endif | ||
| 1293 | #endif | ||
| 1294 | |||
| 1295 | /* | ||
| 1296 | * Some compiler environments don't define some things. | ||
| 1297 | */ | ||
| 1298 | #if defined(__BORLANDC__) | ||
| 1299 | # define _ftime ftime | ||
| 1300 | # define _timeb timeb | ||
| 1301 | #endif | ||
| 1302 | |||
| 1303 | #if defined(__cplusplus) | ||
| 1304 | |||
| 1305 | /* | ||
| 1306 | * Internal exceptions | ||
| 1307 | */ | ||
| 1308 | class ptw32_exception {}; | ||
| 1309 | class ptw32_exception_cancel : public ptw32_exception {}; | ||
| 1310 | class ptw32_exception_exit : public ptw32_exception {}; | ||
| 1311 | |||
| 1312 | #endif | ||
| 1313 | |||
| 1314 | #if PTW32_LEVEL >= PTW32_LEVEL_MAX | ||
| 1315 | |||
| 1316 | /* FIXME: This is only required if the library was built using SEH */ | ||
| 1317 | /* | ||
| 1318 | * Get internal SEH tag | ||
| 1319 | */ | ||
| 1320 | PTW32_DLLPORT DWORD PTW32_CDECL ptw32_get_exception_services_code(void); | ||
| 1321 | |||
| 1322 | #endif /* PTW32_LEVEL >= PTW32_LEVEL_MAX */ | ||
| 1323 | |||
| 1324 | #if !defined(PTW32_BUILD) | ||
| 1325 | |||
| 1326 | #if defined(__CLEANUP_SEH) | ||
| 1327 | |||
| 1328 | /* | ||
| 1329 | * Redefine the SEH __except keyword to ensure that applications | ||
| 1330 | * propagate our internal exceptions up to the library's internal handlers. | ||
| 1331 | */ | ||
| 1332 | #define __except( E ) \ | ||
| 1333 | __except( ( GetExceptionCode() == ptw32_get_exception_services_code() ) \ | ||
| 1334 | ? EXCEPTION_CONTINUE_SEARCH : ( E ) ) | ||
| 1335 | |||
| 1336 | #endif /* __CLEANUP_SEH */ | ||
| 1337 | |||
| 1338 | #if defined(__CLEANUP_CXX) | ||
| 1339 | |||
| 1340 | /* | ||
| 1341 | * Redefine the C++ catch keyword to ensure that applications | ||
| 1342 | * propagate our internal exceptions up to the library's internal handlers. | ||
| 1343 | */ | ||
| 1344 | #if defined(_MSC_VER) | ||
| 1345 | /* | ||
| 1346 | * WARNING: Replace any 'catch( ... )' with 'PtW32CatchAll' | ||
| 1347 | * if you want Pthread-Win32 cancellation and pthread_exit to work. | ||
| 1348 | */ | ||
| 1349 | |||
| 1350 | #if !defined(PtW32NoCatchWarn) | ||
| 1351 | |||
| 1352 | #pragma message("Specify \"/DPtW32NoCatchWarn\" compiler flag to skip this message.") | ||
| 1353 | #pragma message("------------------------------------------------------------------") | ||
| 1354 | #pragma message("When compiling applications with MSVC++ and C++ exception handling:") | ||
| 1355 | #pragma message(" Replace any 'catch( ... )' in routines called from POSIX threads") | ||
| 1356 | #pragma message(" with 'PtW32CatchAll' or 'CATCHALL' if you want POSIX thread") | ||
| 1357 | #pragma message(" cancellation and pthread_exit to work. For example:") | ||
| 1358 | #pragma message("") | ||
| 1359 | #pragma message(" #if defined(PtW32CatchAll)") | ||
| 1360 | #pragma message(" PtW32CatchAll") | ||
| 1361 | #pragma message(" #else") | ||
| 1362 | #pragma message(" catch(...)") | ||
| 1363 | #pragma message(" #endif") | ||
| 1364 | #pragma message(" {") | ||
| 1365 | #pragma message(" /* Catchall block processing */") | ||
| 1366 | #pragma message(" }") | ||
| 1367 | #pragma message("------------------------------------------------------------------") | ||
| 1368 | |||
| 1369 | #endif | ||
| 1370 | |||
| 1371 | #define PtW32CatchAll \ | ||
| 1372 | catch( ptw32_exception & ) { throw; } \ | ||
| 1373 | catch( ... ) | ||
| 1374 | |||
| 1375 | #else /* _MSC_VER */ | ||
| 1376 | |||
| 1377 | #define catch( E ) \ | ||
| 1378 | catch( ptw32_exception & ) { throw; } \ | ||
| 1379 | catch( E ) | ||
| 1380 | |||
| 1381 | #endif /* _MSC_VER */ | ||
| 1382 | |||
| 1383 | #endif /* __CLEANUP_CXX */ | ||
| 1384 | |||
| 1385 | #endif /* ! PTW32_BUILD */ | ||
| 1386 | |||
| 1387 | #if defined(__cplusplus) | ||
| 1388 | } /* End of extern "C" */ | ||
| 1389 | #endif /* __cplusplus */ | ||
| 1390 | |||
| 1391 | #if defined(PTW32__HANDLE_DEF) | ||
| 1392 | # undef HANDLE | ||
| 1393 | #endif | ||
| 1394 | #if defined(PTW32__DWORD_DEF) | ||
| 1395 | # undef DWORD | ||
| 1396 | #endif | ||
| 1397 | |||
| 1398 | #undef PTW32_LEVEL | ||
| 1399 | #undef PTW32_LEVEL_MAX | ||
| 1400 | |||
| 1401 | #endif /* ! RC_INVOKED */ | ||
| 1402 | |||
| 1403 | #endif /* PTHREAD_H */ | ||
| @@ -1,189 +0,0 @@ | |||
| 1 | /* | ||
| 2 | * Module: sched.h | ||
| 3 | * | ||
| 4 | * Purpose: | ||
| 5 | * Provides an implementation of POSIX realtime extensions | ||
| 6 | * as defined in | ||
| 7 | * | ||
| 8 | * POSIX 1003.1b-1993 (POSIX.1b) | ||
| 9 | * | ||
| 10 | * -------------------------------------------------------------------------- | ||
| 11 | * | ||
| 12 | * Pthreads-win32 - POSIX Threads Library for Win32 | ||
| 13 | * Copyright(C) 1998 John E. Bossom | ||
| 14 | * Copyright(C) 1999,2005 Pthreads-win32 contributors | ||
| 15 | * | ||
| 16 | * Contact Email: rpj@callisto.canberra.edu.au | ||
| 17 | * | ||
| 18 | * The current list of contributors is contained | ||
| 19 | * in the file CONTRIBUTORS included with the source | ||
| 20 | * code distribution. The list can also be seen at the | ||
| 21 | * following World Wide Web location: | ||
| 22 | * http://sources.redhat.com/pthreads-win32/contributors.html | ||
| 23 | * | ||
| 24 | * This library is free software; you can redistribute it and/or | ||
| 25 | * modify it under the terms of the GNU Lesser General Public | ||
| 26 | * License as published by the Free Software Foundation; either | ||
| 27 | * version 2 of the License, or (at your option) any later version. | ||
| 28 | * | ||
| 29 | * This library is distributed in the hope that it will be useful, | ||
| 30 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 31 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
| 32 | * Lesser General Public License for more details. | ||
| 33 | * | ||
| 34 | * You should have received a copy of the GNU Lesser General Public | ||
| 35 | * License along with this library in the file COPYING.LIB; | ||
| 36 | * if not, write to the Free Software Foundation, Inc., | ||
| 37 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA | ||
| 38 | */ | ||
| 39 | #if !defined(_SCHED_H) | ||
| 40 | #define _SCHED_H | ||
| 41 | |||
| 42 | #undef PTW32_SCHED_LEVEL | ||
| 43 | |||
| 44 | #if defined(_POSIX_SOURCE) | ||
| 45 | #define PTW32_SCHED_LEVEL 0 | ||
| 46 | /* Early POSIX */ | ||
| 47 | #endif | ||
| 48 | |||
| 49 | #if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309 | ||
| 50 | #undef PTW32_SCHED_LEVEL | ||
| 51 | #define PTW32_SCHED_LEVEL 1 | ||
| 52 | /* Include 1b, 1c and 1d */ | ||
| 53 | #endif | ||
| 54 | |||
| 55 | #if defined(INCLUDE_NP) | ||
| 56 | #undef PTW32_SCHED_LEVEL | ||
| 57 | #define PTW32_SCHED_LEVEL 2 | ||
| 58 | /* Include Non-Portable extensions */ | ||
| 59 | #endif | ||
| 60 | |||
| 61 | #define PTW32_SCHED_LEVEL_MAX 3 | ||
| 62 | |||
| 63 | #if ( defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112 ) || !defined(PTW32_SCHED_LEVEL) | ||
| 64 | #define PTW32_SCHED_LEVEL PTW32_SCHED_LEVEL_MAX | ||
| 65 | /* Include everything */ | ||
| 66 | #endif | ||
| 67 | |||
| 68 | |||
| 69 | #if defined(__GNUC__) && !defined(__declspec) | ||
| 70 | # error Please upgrade your GNU compiler to one that supports __declspec. | ||
| 71 | #endif | ||
| 72 | |||
| 73 | /* | ||
| 74 | * When building the library, you should define PTW32_BUILD so that | ||
| 75 | * the variables/functions are exported correctly. When using the library, | ||
| 76 | * do NOT define PTW32_BUILD, and then the variables/functions will | ||
| 77 | * be imported correctly. | ||
| 78 | */ | ||
| 79 | #if !defined(PTW32_STATIC_LIB) | ||
| 80 | # if defined(PTW32_BUILD) | ||
| 81 | # define PTW32_DLLPORT __declspec (dllexport) | ||
| 82 | # else | ||
| 83 | # define PTW32_DLLPORT __declspec (dllimport) | ||
| 84 | # endif | ||
| 85 | #else | ||
| 86 | # define PTW32_DLLPORT | ||
| 87 | #endif | ||
| 88 | |||
| 89 | /* | ||
| 90 | * This is a duplicate of what is in the autoconf config.h, | ||
| 91 | * which is only used when building the pthread-win32 libraries. | ||
| 92 | */ | ||
| 93 | |||
| 94 | #if !defined(PTW32_CONFIG_H) | ||
| 95 | # if defined(WINCE) | ||
| 96 | # define NEED_ERRNO | ||
| 97 | # define NEED_SEM | ||
| 98 | # endif | ||
| 99 | # if defined(__MINGW64__) | ||
| 100 | # define HAVE_STRUCT_TIMESPEC | ||
| 101 | # define HAVE_MODE_T | ||
| 102 | # elif defined(_UWIN) || defined(__MINGW32__) | ||
| 103 | # define HAVE_MODE_T | ||
| 104 | # endif | ||
| 105 | #endif | ||
| 106 | |||
| 107 | /* | ||
| 108 | * | ||
| 109 | */ | ||
| 110 | |||
| 111 | #if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX | ||
| 112 | #if defined(NEED_ERRNO) | ||
| 113 | #include "need_errno.h" | ||
| 114 | #else | ||
| 115 | #include <errno.h> | ||
| 116 | #endif | ||
| 117 | #endif /* PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX */ | ||
| 118 | |||
| 119 | #if (defined(__MINGW64__) || defined(__MINGW32__)) || defined(_UWIN) | ||
| 120 | # if PTW32_SCHED_LEVEL >= PTW32_SCHED_LEVEL_MAX | ||
| 121 | /* For pid_t */ | ||
| 122 | # include <sys/types.h> | ||
| 123 | /* Required by Unix 98 */ | ||
| 124 | # include <time.h> | ||
| 125 | # else | ||
| 126 | typedef int pid_t; | ||
| 127 | # endif | ||
| 128 | #else | ||
| 129 | /* [i_a] fix for using pthread_win32 with mongoose code, which #define's its own pid_t akin to typedef HANDLE pid_t; */ | ||
| 130 | #undef pid_t | ||
| 131 | # if defined(_MSC_VER) | ||
| 132 | typedef void *pid_t; | ||
| 133 | # else | ||
| 134 | typedef int pid_t; | ||
| 135 | # endif | ||
| 136 | #endif | ||
| 137 | |||
| 138 | /* Thread scheduling policies */ | ||
| 139 | |||
| 140 | enum { | ||
| 141 | SCHED_OTHER = 0, | ||
| 142 | SCHED_FIFO, | ||
| 143 | SCHED_RR, | ||
| 144 | SCHED_MIN = SCHED_OTHER, | ||
| 145 | SCHED_MAX = SCHED_RR | ||
| 146 | }; | ||
| 147 | |||
| 148 | struct sched_param { | ||
| 149 | int sched_priority; | ||
| 150 | }; | ||
| 151 | |||
| 152 | #if defined(__cplusplus) | ||
| 153 | extern "C" | ||
| 154 | { | ||
| 155 | #endif /* __cplusplus */ | ||
| 156 | |||
| 157 | PTW32_DLLPORT int __cdecl sched_yield (void); | ||
| 158 | |||
| 159 | PTW32_DLLPORT int __cdecl sched_get_priority_min (int policy); | ||
| 160 | |||
| 161 | PTW32_DLLPORT int __cdecl sched_get_priority_max (int policy); | ||
| 162 | |||
| 163 | PTW32_DLLPORT int __cdecl sched_setscheduler (pid_t pid, int policy); | ||
| 164 | |||
| 165 | PTW32_DLLPORT int __cdecl sched_getscheduler (pid_t pid); | ||
| 166 | |||
| 167 | /* | ||
| 168 | * Note that this macro returns ENOTSUP rather than | ||
| 169 | * ENOSYS as might be expected. However, returning ENOSYS | ||
| 170 | * should mean that sched_get_priority_{min,max} are | ||
| 171 | * not implemented as well as sched_rr_get_interval. | ||
| 172 | * This is not the case, since we just don't support | ||
| 173 | * round-robin scheduling. Therefore I have chosen to | ||
| 174 | * return the same value as sched_setscheduler when | ||
| 175 | * SCHED_RR is passed to it. | ||
| 176 | */ | ||
| 177 | #define sched_rr_get_interval(_pid, _interval) \ | ||
| 178 | ( errno = ENOTSUP, (int) -1 ) | ||
| 179 | |||
| 180 | |||
| 181 | #if defined(__cplusplus) | ||
| 182 | } /* End of extern "C" */ | ||
| 183 | #endif /* __cplusplus */ | ||
| 184 | |||
| 185 | #undef PTW32_SCHED_LEVEL | ||
| 186 | #undef PTW32_SCHED_LEVEL_MAX | ||
| 187 | |||
| 188 | #endif /* !_SCHED_H */ | ||
| 189 | |||
| @@ -11,8 +11,9 @@ · 10 unmodified lines | |||
| 11 | 11 | ||
| 12 | #include <glm/gtx/norm.hpp> | 12 | #include <glm/gtx/norm.hpp> |
| 13 | 13 | ||
| 14 | #include "GLMHelpers.h" | ||
| 15 | |||
| 14 | #include "AngularConstraint.h" | 16 | #include "AngularConstraint.h" |
| 15 | #include "SharedUtil.h" | ||
| 16 | 17 | ||
| 17 | // helper function | 18 | // helper function |
| 18 | /// \param angle radian angle to be clamped within angleMin and angleMax | 19 | /// \param angle radian angle to be clamped within angleMin and angleMax |
| @@ -14,7 +14,6 @@ · 13 unmodified lines | |||
| 14 | 14 | ||
| 15 | #include <glm/glm.hpp> | 15 | #include <glm/glm.hpp> |
| 16 | 16 | ||
| 17 | |||
| 18 | class AngularConstraint { | 17 | class AngularConstraint { |
| 19 | public: | 18 | public: |
| 20 | /// \param minAngles minumum euler angles for the constraint | 19 | /// \param minAngles minumum euler angles for the constraint |
| @@ -13,56 +13,128 @@ · 12 unmodified lines | |||
| 13 | #include "Shape.h" | 13 | #include "Shape.h" |
| 14 | #include "SharedUtil.h" | 14 | #include "SharedUtil.h" |
| 15 | 15 | ||
| 16 | ContactPoint::ContactPoint() : _lastFrame(0), _shapeA(NULL), _shapeB(NULL), | 16 | // This parameter helps keep the actual point of contact slightly inside each shape |
| 17 | _offsetA(0.0f), _offsetB(0.0f), _normal(0.0f) { | 17 | // which allows the collisions to happen almost every frame for more frequent updates. |
| 18 | const float CONTACT_PENETRATION_ALLOWANCE = 0.005f; | ||
| 19 | |||
| 20 | ContactPoint::ContactPoint() : | ||
| 21 | _lastFrame(0), _shapeA(NULL), _shapeB(NULL), | ||
| 22 | _offsetA(0.0f), _offsetB(0.0f), | ||
| 23 | _relativeMassA(0.5f), _relativeMassB(0.5f), | ||
| 24 | _numPointsA(0), _numPoints(0), _normal(0.0f) { | ||
| 18 | } | 25 | } |
| 19 | 26 | ||
| 20 | ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : _lastFrame(frame), | 27 | ContactPoint::ContactPoint(const CollisionInfo& collision, quint32 frame) : |
| 21 | _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), _offsetA(0.0f), _offsetB(0.0f), | 28 | _lastFrame(frame), _shapeA(collision.getShapeA()), _shapeB(collision.getShapeB()), |
| 29 | _offsetA(0.0f), _offsetB(0.0f), | ||
| 30 | _relativeMassA(0.5f), _relativeMassB(0.5f), | ||
| 22 | _numPointsA(0), _numPoints(0), _normal(0.0f) { | 31 | _numPointsA(0), _numPoints(0), _normal(0.0f) { |
| 23 | 32 | ||
| 24 | _contactPoint = collision._contactPoint - 0.5f * collision._penetration; | 33 | glm::vec3 pointA = collision._contactPoint; |
| 25 | _offsetA = collision._contactPoint - _shapeA->getTranslation(); | 34 | glm::vec3 pointB = collision._contactPoint - collision._penetration; |
| 26 | _offsetB = collision._contactPoint - collision._penetration - _shapeB->getTranslation(); | 35 | |
| 27 | float pLength = glm::length(collision._penetration); | 36 | float pLength = glm::length(collision._penetration); |
| 28 | if (pLength > EPSILON) { | 37 | if (pLength > EPSILON) { |
| 29 | _normal = collision._penetration / pLength; | 38 | _normal = collision._penetration / pLength; |
| 30 | } | 39 | } |
| 31 | |||
| 32 | if (_shapeA->getID() > _shapeB->getID()) { | 40 | if (_shapeA->getID() > _shapeB->getID()) { |
| 33 | // swap so that _shapeA always has lower ID | 41 | // swap so that _shapeA always has lower ID |
| 34 | _shapeA = collision.getShapeB(); | 42 | _shapeA = collision.getShapeB(); |
| 35 | _shapeB = collision.getShapeA(); | 43 | _shapeB = collision.getShapeA(); |
| 36 | |||
| 37 | glm::vec3 temp = _offsetA; | ||
| 38 | _offsetA = _offsetB; | ||
| 39 | _offsetB = temp; | ||
| 40 | _normal = - _normal; | 44 | _normal = - _normal; |
| 45 | pointA = pointB; | ||
| 46 | pointB = collision._contactPoint; | ||
| 41 | } | 47 | } |
| 42 | 48 | ||
| 49 | // bring the contact points inside the shapes to help maintain collision updates | ||
| 50 | pointA -= CONTACT_PENETRATION_ALLOWANCE * _normal; | ||
| 51 | pointB += CONTACT_PENETRATION_ALLOWANCE * _normal; | ||
| 52 | |||
| 53 | _offsetA = pointA - _shapeA->getTranslation(); | ||
| 54 | _offsetB = pointB - _shapeB->getTranslation(); | ||
| 55 | |||
| 43 | _shapeA->getVerletPoints(_points); | 56 | _shapeA->getVerletPoints(_points); |
| 44 | _numPointsA = _points.size(); | 57 | _numPointsA = _points.size(); |
| 45 | _shapeB->getVerletPoints(_points); | 58 | _shapeB->getVerletPoints(_points); |
| 46 | _numPoints = _points.size(); | 59 | _numPoints = _points.size(); |
| 47 | 60 | ||
| 61 | // compute and cache relative masses | ||
| 62 | float massA = EPSILON; | ||
| 63 | for (int i = 0; i < _numPointsA; ++i) { | ||
| 64 | massA += _points[i]->getMass(); | ||
| 65 | } | ||
| 66 | float massB = EPSILON; | ||
| 67 | for (int i = _numPointsA; i < _numPoints; ++i) { | ||
| 68 | massB += _points[i]->getMass(); | ||
| 69 | } | ||
| 70 | float invTotalMass = 1.0f / (massA + massB); | ||
| 71 | _relativeMassA = massA * invTotalMass; | ||
| 72 | _relativeMassB = massB * invTotalMass; | ||
| 73 | |||
| 74 | // _contactPoint will be the weighted average of the two | ||
| 75 | _contactPoint = _relativeMassA * pointA + _relativeMassB * pointB; | ||
| 76 | |||
| 48 | // compute offsets for shapeA | 77 | // compute offsets for shapeA |
| 49 | for (int i = 0; i < _numPointsA; ++i) { | 78 | for (int i = 0; i < _numPointsA; ++i) { |
| 50 | glm::vec3 offset = _points[i]->_position - collision._contactPoint; | 79 | glm::vec3 offset = _points[i]->_position - pointA; |
| 51 | _offsets.push_back(offset); | 80 | _offsets.push_back(offset); |
| 52 | _distances.push_back(glm::length(offset)); | 81 | _distances.push_back(glm::length(offset)); |
| 53 | } | 82 | } |
| 54 | // compute offsets for shapeB | 83 | // compute offsets for shapeB |
| 55 | for (int i = _numPointsA; i < _numPoints; ++i) { | 84 | for (int i = _numPointsA; i < _numPoints; ++i) { |
| 56 | glm::vec3 offset = _points[i]->_position - collision._contactPoint + collision._penetration; | 85 | glm::vec3 offset = _points[i]->_position - pointB; |
| 57 | _offsets.push_back(offset); | 86 | _offsets.push_back(offset); |
| 58 | _distances.push_back(glm::length(offset)); | 87 | _distances.push_back(glm::length(offset)); |
| 59 | } | 88 | } |
| 60 | } | 89 | } |
| 61 | 90 | ||
| 62 | // virtual | ||
| 63 | float ContactPoint::enforce() { | 91 | float ContactPoint::enforce() { |
| 64 | int numPoints = _points.size(); | 92 | glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; |
| 65 | for (int i = 0; i < numPoints; ++i) { | 93 | glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; |
| 94 | glm::vec3 penetration = pointA - pointB; | ||
| 95 | float pDotN = glm::dot(penetration, _normal); | ||
| 96 | bool constraintViolation = (pDotN > CONTACT_PENETRATION_ALLOWANCE); | ||
| 97 | |||
| 98 | // the contact point will be the average of the two points on the shapes | ||
| 99 | _contactPoint = 0.5f * (pointA + pointB); | ||
| 100 | |||
| 101 | if (constraintViolation) { | ||
| 102 | for (int i = 0; i < _numPoints; ++i) { | ||
| 103 | VerletPoint* point = _points[i]; | ||
| 104 | glm::vec3 offset = _offsets[i]; | ||
| 105 | |||
| 106 | // split delta into parallel and perpendicular components | ||
| 107 | glm::vec3 delta = _contactPoint + offset - point->_position; | ||
| 108 | glm::vec3 paraDelta = glm::dot(delta, _normal) * _normal; | ||
| 109 | glm::vec3 perpDelta = delta - paraDelta; | ||
| 110 | |||
| 111 | // use the relative sizes of the components to decide how much perpenducular delta to use | ||
| 112 | // perpendicular < parallel ==> static friction ==> perpFactor = 1.0 | ||
| 113 | // perpendicular > parallel ==> dynamic friction ==> cap to length of paraDelta ==> perpFactor < 1.0 | ||
| 114 | float paraLength = glm::length(paraDelta); | ||
| 115 | float perpLength = glm::length(perpDelta); | ||
| 116 | float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f; | ||
| 117 | |||
| 118 | // recombine the two components to get the final delta | ||
| 119 | delta = paraDelta + perpFactor * perpDelta; | ||
| 120 | |||
| 121 | glm::vec3 targetPosition = point->_position + delta; | ||
| 122 | _distances[i] = glm::distance(_contactPoint, targetPosition); | ||
| 123 | point->_position += delta; | ||
| 124 | } | ||
| 125 | } else { | ||
| 126 | for (int i = 0; i < _numPoints; ++i) { | ||
| 127 | _distances[i] = glm::length(glm::length(_offsets[i])); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | return 0.0f; | ||
| 131 | } | ||
| 132 | |||
| 133 | // virtual | ||
| 134 | void ContactPoint::applyFriction() { | ||
| 135 | // TODO: Andrew to re-implement this in a different way | ||
| 136 | /* | ||
| 137 | for (int i = 0; i < _numPoints; ++i) { | ||
| 66 | glm::vec3& position = _points[i]->_position; | 138 | glm::vec3& position = _points[i]->_position; |
| 67 | // TODO: use a fast distance approximation | 139 | // TODO: use a fast distance approximation |
| 68 | float newDistance = glm::distance(_contactPoint, position); | 140 | float newDistance = glm::distance(_contactPoint, position); |
| @@ -75,60 +147,17 @@ float ContactPoint::enforce() { · 6 unmodified lines | |||
| 75 | position = center - (0.5f * constrainedDistance) * direction; | 147 | position = center - (0.5f * constrainedDistance) * direction; |
| 76 | } | 148 | } |
| 77 | } | 149 | } |
| 78 | return 0.0f; | 150 | */ |
| 79 | } | ||
| 80 | |||
| 81 | void ContactPoint::buildConstraints() { | ||
| 82 | glm::vec3 pointA = _shapeA->getTranslation() + _offsetA; | ||
| 83 | glm::vec3 pointB = _shapeB->getTranslation() + _offsetB; | ||
| 84 | glm::vec3 penetration = pointA - pointB; | ||
| 85 | float pDotN = glm::dot(penetration, _normal); | ||
| 86 | bool actuallyMovePoints = (pDotN > EPSILON); | ||
| 87 | |||
| 88 | // the contact point will be the average of the two points on the shapes | ||
| 89 | _contactPoint = 0.5f * (pointA + pointB); | ||
| 90 | |||
| 91 | // TODO: Andrew to compute more correct lagrangian weights that provide a more realistic response. | ||
| 92 | // | ||
| 93 | // HACK: since the weights are naively equal for all points (which is what the above TODO is about) we | ||
| 94 | // don't want to use the full-strength delta because otherwise there can be annoying oscillations. We | ||
| 95 | // reduce this problem by in the short-term by attenuating the delta that is applied, the tradeoff is | ||
| 96 | // that this makes it easier for limbs to tunnel through during collisions. | ||
| 97 | const float HACK_STRENGTH = 0.5f; | ||
| 98 | |||
| 99 | int numPoints = _points.size(); | ||
| 100 | for (int i = 0; i < numPoints; ++i) { | ||
| 101 | VerletPoint* point = _points[i]; | ||
| 102 | glm::vec3 offset = _offsets[i]; | ||
| 103 | |||
| 104 | // split delta into parallel and perpendicular components | ||
| 105 | glm::vec3 delta = _contactPoint + offset - point->_position; | ||
| 106 | glm::vec3 paraDelta = glm::dot(delta, _normal) * _normal; | ||
| 107 | glm::vec3 perpDelta = delta - paraDelta; | ||
| 108 | |||
| 109 | // use the relative sizes of the components to decide how much perpenducular delta to use | ||
| 110 | // perpendicular < parallel ==> static friciton ==> perpFactor = 1.0 | ||
| 111 | // perpendicular > parallel ==> dynamic friciton ==> cap to length of paraDelta ==> perpFactor < 1.0 | ||
| 112 | float paraLength = glm::length(paraDelta); | ||
| 113 | float perpLength = glm::length(perpDelta); | ||
| 114 | float perpFactor = (perpLength > paraLength && perpLength > EPSILON) ? (paraLength / perpLength) : 1.0f; | ||
| 115 | |||
| 116 | // recombine the two components to get the final delta | ||
| 117 | delta = paraDelta + perpFactor * perpDelta; | ||
| 118 | |||
| 119 | glm::vec3 targetPosition = point->_position + delta; | ||
| 120 | _distances[i] = glm::distance(_contactPoint, targetPosition); | ||
| 121 | if (actuallyMovePoints) { | ||
| 122 | point->_position += HACK_STRENGTH * delta; | ||
| 123 | } | ||
| 124 | } | ||
| 125 | } | 151 | } |
| 126 | 152 | ||
| 127 | void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) { | 153 | void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) { |
| 128 | _lastFrame = frame; | 154 | _lastFrame = frame; |
| 129 | _contactPoint = collision._contactPoint - 0.5f * collision._penetration; | 155 | |
| 130 | _offsetA = collision._contactPoint - collision._shapeA->getTranslation(); | 156 | // compute contact points on surface of each shape |
| 131 | _offsetB = collision._contactPoint - collision._penetration - collision._shapeB->getTranslation(); | 157 | glm::vec3 pointA = collision._contactPoint; |
| 158 | glm::vec3 pointB = pointA - collision._penetration; | ||
| 159 | |||
| 160 | // compute the normal (which points from A into B) | ||
| 132 | float pLength = glm::length(collision._penetration); | 161 | float pLength = glm::length(collision._penetration); |
| 133 | if (pLength > EPSILON) { | 162 | if (pLength > EPSILON) { |
| 134 | _normal = collision._penetration / pLength; | 163 | _normal = collision._penetration / pLength; |
| @@ -138,19 +167,26 @@ void ContactPoint::updateContact(const CollisionInfo& collision, quint32 frame) · 3 unmodified lines | |||
| 138 | 167 | ||
| 139 | if (collision._shapeA->getID() > collision._shapeB->getID()) { | 168 | if (collision._shapeA->getID() > collision._shapeB->getID()) { |
| 140 | // our _shapeA always has lower ID | 169 | // our _shapeA always has lower ID |
| 141 | glm::vec3 temp = _offsetA; | ||
| 142 | _offsetA = _offsetB; | ||
| 143 | _offsetB = temp; | ||
| 144 | _normal = - _normal; | 170 | _normal = - _normal; |
| 171 | pointA = pointB; | ||
| 172 | pointB = collision._contactPoint; | ||
| 145 | } | 173 | } |
| 174 | |||
| 175 | // bring the contact points inside the shapes to help maintain collision updates | ||
| 176 | pointA -= CONTACT_PENETRATION_ALLOWANCE * _normal; | ||
| 177 | pointB += CONTACT_PENETRATION_ALLOWANCE * _normal; | ||
| 178 | |||
| 179 | // compute relative offsets to per-shape contact points | ||
| 180 | _offsetA = pointA - collision._shapeA->getTranslation(); | ||
| 181 | _offsetB = pointB - collision._shapeB->getTranslation(); | ||
| 146 | 182 | ||
| 147 | // compute offsets for shapeA | 183 | // compute offsets for shapeA |
| 148 | assert(_offsets.size() == _numPoints); | 184 | assert(_offsets.size() == _numPoints); |
| 149 | for (int i = 0; i < _numPointsA; ++i) { | 185 | for (int i = 0; i < _numPointsA; ++i) { |
| 150 | _offsets[i] = (_points[i]->_position - collision._contactPoint); | 186 | _offsets[i] = _points[i]->_position - pointA; |
| 151 | } | 187 | } |
| 152 | // compute offsets for shapeB | 188 | // compute offsets for shapeB |
| 153 | for (int i = _numPointsA; i < _numPoints; ++i) { | 189 | for (int i = _numPointsA; i < _numPoints; ++i) { |
| 154 | _offsets[i] = (_points[i]->_position - collision._contactPoint + collision._penetration); | 190 | _offsets[i] = _points[i]->_position - pointB; |
| 155 | } | 191 | } |
| 156 | } | 192 | } |
| @@ -26,8 +26,8 @@ public: · 25 unmodified lines | |||
| 26 | ContactPoint(const CollisionInfo& collision, quint32 frame); | 26 | ContactPoint(const CollisionInfo& collision, quint32 frame); |
| 27 | 27 | ||
| 28 | virtual float enforce(); | 28 | virtual float enforce(); |
| 29 | 29 | ||
| 30 | void buildConstraints(); | 30 | void applyFriction(); |
| 31 | void updateContact(const CollisionInfo& collision, quint32 frame); | 31 | void updateContact(const CollisionInfo& collision, quint32 frame); |
| 32 | quint32 getLastFrame() const { return _lastFrame; } | 32 | quint32 getLastFrame() const { return _lastFrame; } |
| 33 | 33 | ||
| @@ -41,6 +41,8 @@ protected: · 7 unmodified lines | |||
| 41 | glm::vec3 _offsetA; // contact point relative to A's center | 41 | glm::vec3 _offsetA; // contact point relative to A's center |
| 42 | glm::vec3 _offsetB; // contact point relative to B's center | 42 | glm::vec3 _offsetB; // contact point relative to B's center |
| 43 | glm::vec3 _contactPoint; // a "virtual" point that is added to the simulation | 43 | glm::vec3 _contactPoint; // a "virtual" point that is added to the simulation |
| 44 | float _relativeMassA; // massA / totalMass | ||
| 45 | float _relativeMassB; // massB / totalMass | ||
| 44 | int _numPointsA; // number of VerletPoints that belong to _shapeA | 46 | int _numPointsA; // number of VerletPoints that belong to _shapeA |
| 45 | int _numPoints; // total number of VerletPoints | 47 | int _numPoints; // total number of VerletPoints |
| 46 | QVector<VerletPoint*> _points; // points that belong to colliding shapes | 48 | QVector<VerletPoint*> _points; // points that belong to colliding shapes |
| @@ -0,0 +1,299 @@ | |||
| 1 | // | ||
| 2 | // GLMHelpers.cpp | ||
| 3 | // libraries/shared/src | ||
| 4 | // | ||
| 5 | // Created by Stephen Birarda on 2014-08-07. | ||
| 6 | // Copyright 2014 High Fidelity, Inc. | ||
| 7 | // | ||
| 8 | // Distributed under the Apache License, Version 2.0. | ||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | // | ||
| 11 | |||
| 12 | #include "GLMHelpers.h" | ||
| 13 | |||
| 14 | // Safe version of glm::mix; based on the code in Nick Bobick's article, | ||
| 15 | // http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde, | ||
| 16 | // https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) | ||
| 17 | glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) { | ||
| 18 | float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; | ||
| 19 | float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1; | ||
| 20 | |||
| 21 | // adjust signs if necessary | ||
| 22 | if (cosa < 0.0f) { | ||
| 23 | cosa = -cosa; | ||
| 24 | ox = -ox; | ||
| 25 | oy = -oy; | ||
| 26 | oz = -oz; | ||
| 27 | ow = -ow; | ||
| 28 | } | ||
| 29 | |||
| 30 | // calculate coefficients; if the angle is too close to zero, we must fall back | ||
| 31 | // to linear interpolation | ||
| 32 | if ((1.0f - cosa) > EPSILON) { | ||
| 33 | float angle = acosf(cosa), sina = sinf(angle); | ||
| 34 | s0 = sinf((1.0f - proportion) * angle) / sina; | ||
| 35 | s1 = sinf(proportion * angle) / sina; | ||
| 36 | |||
| 37 | } else { | ||
| 38 | s0 = 1.0f - proportion; | ||
| 39 | s1 = proportion; | ||
| 40 | } | ||
| 41 | |||
| 42 | return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz)); | ||
| 43 | } | ||
| 44 | |||
| 45 | // Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc | ||
| 46 | int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix) { | ||
| 47 | int16_t outVal = (int16_t)(scalar * (float)(1 << radix)); | ||
| 48 | memcpy(buffer, &outVal, sizeof(uint16_t)); | ||
| 49 | return sizeof(uint16_t); | ||
| 50 | } | ||
| 51 | |||
| 52 | int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix) { | ||
| 53 | *destinationPointer = *byteFixedPointer / (float)(1 << radix); | ||
| 54 | return sizeof(int16_t); | ||
| 55 | } | ||
| 56 | |||
| 57 | int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix) { | ||
| 58 | const unsigned char* startPosition = destBuffer; | ||
| 59 | destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.x, radix); | ||
| 60 | destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.y, radix); | ||
| 61 | destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.z, radix); | ||
| 62 | return destBuffer - startPosition; | ||
| 63 | } | ||
| 64 | |||
| 65 | int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix) { | ||
| 66 | const unsigned char* startPosition = sourceBuffer; | ||
| 67 | sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.x), radix); | ||
| 68 | sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.y), radix); | ||
| 69 | sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.z), radix); | ||
| 70 | return sourceBuffer - startPosition; | ||
| 71 | } | ||
| 72 | |||
| 73 | |||
| 74 | int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) { | ||
| 75 | const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.f); | ||
| 76 | |||
| 77 | uint16_t angleHolder = floorf((degrees + 180.f) * ANGLE_CONVERSION_RATIO); | ||
| 78 | memcpy(buffer, &angleHolder, sizeof(uint16_t)); | ||
| 79 | |||
| 80 | return sizeof(uint16_t); | ||
| 81 | } | ||
| 82 | |||
| 83 | int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer) { | ||
| 84 | *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits<uint16_t>::max()) * 360.f - 180.f; | ||
| 85 | return sizeof(uint16_t); | ||
| 86 | } | ||
| 87 | |||
| 88 | int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput) { | ||
| 89 | const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 2.f); | ||
| 90 | uint16_t quatParts[4]; | ||
| 91 | quatParts[0] = floorf((quatInput.x + 1.f) * QUAT_PART_CONVERSION_RATIO); | ||
| 92 | quatParts[1] = floorf((quatInput.y + 1.f) * QUAT_PART_CONVERSION_RATIO); | ||
| 93 | quatParts[2] = floorf((quatInput.z + 1.f) * QUAT_PART_CONVERSION_RATIO); | ||
| 94 | quatParts[3] = floorf((quatInput.w + 1.f) * QUAT_PART_CONVERSION_RATIO); | ||
| 95 | |||
| 96 | memcpy(buffer, &quatParts, sizeof(quatParts)); | ||
| 97 | return sizeof(quatParts); | ||
| 98 | } | ||
| 99 | |||
| 100 | int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput) { | ||
| 101 | uint16_t quatParts[4]; | ||
| 102 | memcpy(&quatParts, buffer, sizeof(quatParts)); | ||
| 103 | |||
| 104 | quatOutput.x = ((quatParts[0] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f; | ||
| 105 | quatOutput.y = ((quatParts[1] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f; | ||
| 106 | quatOutput.z = ((quatParts[2] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f; | ||
| 107 | quatOutput.w = ((quatParts[3] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f; | ||
| 108 | |||
| 109 | return sizeof(quatParts); | ||
| 110 | } | ||
| 111 | |||
| 112 | // Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's | ||
| 113 | // http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde, | ||
| 114 | // https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) | ||
| 115 | glm::vec3 safeEulerAngles(const glm::quat& q) { | ||
| 116 | float sy = 2.0f * (q.y * q.w - q.x * q.z); | ||
| 117 | glm::vec3 eulers; | ||
| 118 | if (sy < 1.0f - EPSILON) { | ||
| 119 | if (sy > -1.0f + EPSILON) { | ||
| 120 | eulers = glm::vec3( | ||
| 121 | atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)), | ||
| 122 | asinf(sy), | ||
| 123 | atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z))); | ||
| 124 | |||
| 125 | } else { | ||
| 126 | // not a unique solution; x + z = atan2(-m21, m11) | ||
| 127 | eulers = glm::vec3( | ||
| 128 | 0.0f, | ||
| 129 | - PI_OVER_TWO, | ||
| 130 | atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); | ||
| 131 | } | ||
| 132 | } else { | ||
| 133 | // not a unique solution; x - z = atan2(-m21, m11) | ||
| 134 | eulers = glm::vec3( | ||
| 135 | 0.0f, | ||
| 136 | PI_OVER_TWO, | ||
| 137 | -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); | ||
| 138 | } | ||
| 139 | |||
| 140 | // adjust so that z, rather than y, is in [-pi/2, pi/2] | ||
| 141 | if (eulers.z < -PI_OVER_TWO) { | ||
| 142 | if (eulers.x < 0.0f) { | ||
| 143 | eulers.x += PI; | ||
| 144 | } else { | ||
| 145 | eulers.x -= PI; | ||
| 146 | } | ||
| 147 | eulers.y = -eulers.y; | ||
| 148 | if (eulers.y < 0.0f) { | ||
| 149 | eulers.y += PI; | ||
| 150 | } else { | ||
| 151 | eulers.y -= PI; | ||
| 152 | } | ||
| 153 | eulers.z += PI; | ||
| 154 | |||
| 155 | } else if (eulers.z > PI_OVER_TWO) { | ||
| 156 | if (eulers.x < 0.0f) { | ||
| 157 | eulers.x += PI; | ||
| 158 | } else { | ||
| 159 | eulers.x -= PI; | ||
| 160 | } | ||
| 161 | eulers.y = -eulers.y; | ||
| 162 | if (eulers.y < 0.0f) { | ||
| 163 | eulers.y += PI; | ||
| 164 | } else { | ||
| 165 | eulers.y -= PI; | ||
| 166 | } | ||
| 167 | eulers.z -= PI; | ||
| 168 | } | ||
| 169 | return eulers; | ||
| 170 | } | ||
| 171 | |||
| 172 | // Helper function returns the positive angle (in radians) between two 3D vectors | ||
| 173 | float angleBetween(const glm::vec3& v1, const glm::vec3& v2) { | ||
| 174 | return acosf((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2))); | ||
| 175 | } | ||
| 176 | |||
| 177 | // Helper function return the rotation from the first vector onto the second | ||
| 178 | glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { | ||
| 179 | float angle = angleBetween(v1, v2); | ||
| 180 | if (glm::isnan(angle) || angle < EPSILON) { | ||
| 181 | return glm::quat(); | ||
| 182 | } | ||
| 183 | glm::vec3 axis; | ||
| 184 | if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis | ||
| 185 | axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f)); | ||
| 186 | float axisLength = glm::length(axis); | ||
| 187 | if (axisLength < EPSILON) { // parallel to x; y will work | ||
| 188 | axis = glm::normalize(glm::cross(v1, glm::vec3(0.0f, 1.0f, 0.0f))); | ||
| 189 | } else { | ||
| 190 | axis /= axisLength; | ||
| 191 | } | ||
| 192 | } else { | ||
| 193 | axis = glm::normalize(glm::cross(v1, v2)); | ||
| 194 | // It is possible for axis to be nan even when angle is not less than EPSILON. | ||
| 195 | // For example when angle is small but not tiny but v1 and v2 and have very short lengths. | ||
| 196 | if (glm::isnan(glm::dot(axis, axis))) { | ||
| 197 | // set angle and axis to values that will generate an identity rotation | ||
| 198 | angle = 0.0f; | ||
| 199 | axis = glm::vec3(1.0f, 0.0f, 0.0f); | ||
| 200 | } | ||
| 201 | } | ||
| 202 | return glm::angleAxis(angle, axis); | ||
| 203 | } | ||
| 204 | |||
| 205 | glm::vec3 extractTranslation(const glm::mat4& matrix) { | ||
| 206 | return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]); | ||
| 207 | } | ||
| 208 | |||
| 209 | void setTranslation(glm::mat4& matrix, const glm::vec3& translation) { | ||
| 210 | matrix[3][0] = translation.x; | ||
| 211 | matrix[3][1] = translation.y; | ||
| 212 | matrix[3][2] = translation.z; | ||
| 213 | } | ||
| 214 | |||
| 215 | glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { | ||
| 216 | // uses the iterative polar decomposition algorithm described by Ken Shoemake at | ||
| 217 | // http://www.cs.wisc.edu/graphics/Courses/838-s2002/Papers/polar-decomp.pdf | ||
| 218 | // code adapted from Clyde, https://github.com/threerings/clyde/blob/master/core/src/main/java/com/threerings/math/Matrix4f.java | ||
| 219 | // start with the contents of the upper 3x3 portion of the matrix | ||
| 220 | glm::mat3 upper = glm::mat3(matrix); | ||
| 221 | if (!assumeOrthogonal) { | ||
| 222 | for (int i = 0; i < 10; i++) { | ||
| 223 | // store the results of the previous iteration | ||
| 224 | glm::mat3 previous = upper; | ||
| 225 | |||
| 226 | // compute average of the matrix with its inverse transpose | ||
| 227 | float sd00 = previous[1][1] * previous[2][2] - previous[2][1] * previous[1][2]; | ||
| 228 | float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2]; | ||
| 229 | float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2]; | ||
| 230 | float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10; | ||
| 231 | if (fabs(det) == 0.0f) { | ||
| 232 | // determinant is zero; matrix is not invertible | ||
| 233 | break; | ||
| 234 | } | ||
| 235 | float hrdet = 0.5f / det; | ||
| 236 | upper[0][0] = +sd00 * hrdet + previous[0][0] * 0.5f; | ||
| 237 | upper[1][0] = -sd10 * hrdet + previous[1][0] * 0.5f; | ||
| 238 | upper[2][0] = +sd20 * hrdet + previous[2][0] * 0.5f; | ||
| 239 | |||
| 240 | upper[0][1] = -(previous[1][0] * previous[2][2] - previous[2][0] * previous[1][2]) * hrdet + previous[0][1] * 0.5f; | ||
| 241 | upper[1][1] = +(previous[0][0] * previous[2][2] - previous[2][0] * previous[0][2]) * hrdet + previous[1][1] * 0.5f; | ||
| 242 | upper[2][1] = -(previous[0][0] * previous[1][2] - previous[1][0] * previous[0][2]) * hrdet + previous[2][1] * 0.5f; | ||
| 243 | |||
| 244 | upper[0][2] = +(previous[1][0] * previous[2][1] - previous[2][0] * previous[1][1]) * hrdet + previous[0][2] * 0.5f; | ||
| 245 | upper[1][2] = -(previous[0][0] * previous[2][1] - previous[2][0] * previous[0][1]) * hrdet + previous[1][2] * 0.5f; | ||
| 246 | upper[2][2] = +(previous[0][0] * previous[1][1] - previous[1][0] * previous[0][1]) * hrdet + previous[2][2] * 0.5f; | ||
| 247 | |||
| 248 | // compute the difference; if it's small enough, we're done | ||
| 249 | glm::mat3 diff = upper - previous; | ||
| 250 | if (diff[0][0] * diff[0][0] + diff[1][0] * diff[1][0] + diff[2][0] * diff[2][0] + diff[0][1] * diff[0][1] + | ||
| 251 | diff[1][1] * diff[1][1] + diff[2][1] * diff[2][1] + diff[0][2] * diff[0][2] + diff[1][2] * diff[1][2] + | ||
| 252 | diff[2][2] * diff[2][2] < EPSILON) { | ||
| 253 | break; | ||
| 254 | } | ||
| 255 | } | ||
| 256 | } | ||
| 257 | |||
| 258 | // now that we have a nice orthogonal matrix, we can extract the rotation quaternion | ||
| 259 | // using the method described in http://en.wikipedia.org/wiki/Rotation_matrix#Conversions | ||
| 260 | float x2 = fabs(1.0f + upper[0][0] - upper[1][1] - upper[2][2]); | ||
| 261 | float y2 = fabs(1.0f - upper[0][0] + upper[1][1] - upper[2][2]); | ||
| 262 | float z2 = fabs(1.0f - upper[0][0] - upper[1][1] + upper[2][2]); | ||
| 263 | float w2 = fabs(1.0f + upper[0][0] + upper[1][1] + upper[2][2]); | ||
| 264 | return glm::normalize(glm::quat(0.5f * sqrtf(w2), | ||
| 265 | 0.5f * sqrtf(x2) * (upper[1][2] >= upper[2][1] ? 1.0f : -1.0f), | ||
| 266 | 0.5f * sqrtf(y2) * (upper[2][0] >= upper[0][2] ? 1.0f : -1.0f), | ||
| 267 | 0.5f * sqrtf(z2) * (upper[0][1] >= upper[1][0] ? 1.0f : -1.0f))); | ||
| 268 | } | ||
| 269 | |||
| 270 | glm::vec3 extractScale(const glm::mat4& matrix) { | ||
| 271 | return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2])); | ||
| 272 | } | ||
| 273 | |||
| 274 | float extractUniformScale(const glm::mat4& matrix) { | ||
| 275 | return extractUniformScale(extractScale(matrix)); | ||
| 276 | } | ||
| 277 | |||
| 278 | float extractUniformScale(const glm::vec3& scale) { | ||
| 279 | return (scale.x + scale.y + scale.z) / 3.0f; | ||
| 280 | } | ||
| 281 | |||
| 282 | QByteArray createByteArray(const glm::vec3& vector) { | ||
| 283 | return QByteArray::number(vector.x) + ',' + QByteArray::number(vector.y) + ',' + QByteArray::number(vector.z); | ||
| 284 | } | ||
| 285 | |||
| 286 | bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB, float similarEnough) { | ||
| 287 | // Compute the angular distance between the two orientations | ||
| 288 | float angleOrientation = orientionA == orientionB ? 0.0f : glm::degrees(glm::angle(orientionA * glm::inverse(orientionB))); | ||
| 289 | if (isNaN(angleOrientation)) { | ||
| 290 | angleOrientation = 0.0f; | ||
| 291 | } | ||
| 292 | return (angleOrientation <= similarEnough); | ||
| 293 | } | ||
| 294 | |||
| 295 | bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough) { | ||
| 296 | // Compute the distance between the two points | ||
| 297 | float positionDistance = glm::distance(positionA, positionB); | ||
| 298 | return (positionDistance <= similarEnough); | ||
| 299 | } | ||
| @@ -0,0 +1,89 @@ | |||
| 1 | // | ||
| 2 | // GLMHelpers.h | ||
| 3 | // libraries/shared/src | ||
| 4 | // | ||
| 5 | // Created by Stephen Birarda on 2014-08-07. | ||
| 6 | // Copyright 2014 High Fidelity, Inc. | ||
| 7 | // | ||
| 8 | // Distributed under the Apache License, Version 2.0. | ||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | ||
| 10 | // | ||
| 11 | |||
| 12 | #ifndef hifi_GLMHelpers_h | ||
| 13 | #define hifi_GLMHelpers_h | ||
| 14 | |||
| 15 | #include <stdint.h> | ||
| 16 | |||
| 17 | #include <glm/glm.hpp> | ||
| 18 | #include <glm/gtc/quaternion.hpp> | ||
| 19 | |||
| 20 | #include <QtCore/QByteArray> | ||
| 21 | |||
| 22 | #include "SharedUtil.h" | ||
| 23 | |||
| 24 | glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); | ||
| 25 | |||
| 26 | // These pack/unpack functions are designed to start specific known types in as efficient a manner | ||
| 27 | // as possible. Taking advantage of the known characteristics of the semantic types. | ||
| 28 | |||
| 29 | // Angles are known to be between 0 and 360 degrees, this allows us to encode in 16bits with great accuracy | ||
| 30 | int packFloatAngleToTwoByte(unsigned char* buffer, float degrees); | ||
| 31 | int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer); | ||
| 32 | |||
| 33 | // Orientation Quats are known to have 4 normalized components be between -1.0 and 1.0 | ||
| 34 | // this allows us to encode each component in 16bits with great accuracy | ||
| 35 | int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput); | ||
| 36 | int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput); | ||
| 37 | |||
| 38 | // Ratios need the be highly accurate when less than 10, but not very accurate above 10, and they | ||
| 39 | // are never greater than 1000 to 1, this allows us to encode each component in 16bits | ||
| 40 | int packFloatRatioToTwoByte(unsigned char* buffer, float ratio); | ||
| 41 | int unpackFloatRatioFromTwoByte(const unsigned char* buffer, float& ratio); | ||
| 42 | |||
| 43 | // Near/Far Clip values need the be highly accurate when less than 10, but only integer accuracy above 10 and | ||
| 44 | // they are never greater than 16,000, this allows us to encode each component in 16bits | ||
| 45 | int packClipValueToTwoByte(unsigned char* buffer, float clipValue); | ||
| 46 | int unpackClipValueFromTwoByte(const unsigned char* buffer, float& clipValue); | ||
| 47 | |||
| 48 | // Positive floats that don't need to be very precise | ||
| 49 | int packFloatToByte(unsigned char* buffer, float value, float scaleBy); | ||
| 50 | int unpackFloatFromByte(const unsigned char* buffer, float& value, float scaleBy); | ||
| 51 | |||
| 52 | // Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc | ||
| 53 | int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix); | ||
| 54 | int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix); | ||
| 55 | |||
| 56 | // A convenience for sending vec3's as fixed-point floats | ||
| 57 | int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix); | ||
| 58 | int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix); | ||
| 59 | |||
| 60 | /// \return vec3 with euler angles in radians | ||
| 61 | glm::vec3 safeEulerAngles(const glm::quat& q); | ||
| 62 | |||
| 63 | float angleBetween(const glm::vec3& v1, const glm::vec3& v2); | ||
| 64 | |||
| 65 | glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); | ||
| 66 | |||
| 67 | glm::vec3 extractTranslation(const glm::mat4& matrix); | ||
| 68 | |||
| 69 | void setTranslation(glm::mat4& matrix, const glm::vec3& translation); | ||
| 70 | |||
| 71 | glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal = false); | ||
| 72 | |||
| 73 | glm::vec3 extractScale(const glm::mat4& matrix); | ||
| 74 | |||
| 75 | float extractUniformScale(const glm::mat4& matrix); | ||
| 76 | |||
| 77 | float extractUniformScale(const glm::vec3& scale); | ||
| 78 | |||
| 79 | QByteArray createByteArray(const glm::vec3& vector); | ||
| 80 | |||
| 81 | /// \return bool are two orientations similar to each other | ||
| 82 | const float ORIENTATION_SIMILAR_ENOUGH = 5.0f; // 10 degrees in any direction | ||
| 83 | bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB, | ||
| 84 | float similarEnough = ORIENTATION_SIMILAR_ENOUGH); | ||
| 85 | const float POSITION_SIMILAR_ENOUGH = 0.1f; // 0.1 meter | ||
| 86 | bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough = POSITION_SIMILAR_ENOUGH); | ||
| 87 | |||
| 88 | |||
| 89 | #endif // hifi_GLMHelpers_h | ||
| @@ -12,6 +12,7 @@ · 11 unmodified lines | |||
| 12 | #ifndef hifi_MovingMinMaxAvg_h | 12 | #ifndef hifi_MovingMinMaxAvg_h |
| 13 | #define hifi_MovingMinMaxAvg_h | 13 | #define hifi_MovingMinMaxAvg_h |
| 14 | 14 | ||
| 15 | #include <cassert> | ||
| 15 | #include <limits> | 16 | #include <limits> |
| 16 | 17 | ||
| 17 | #include "RingBufferHistory.h" | 18 | #include "RingBufferHistory.h" |
| @@ -47,12 +47,12 @@ PhysicsSimulation::~PhysicsSimulation() { · 46 unmodified lines | |||
| 47 | void PhysicsSimulation::setRagdoll(Ragdoll* ragdoll) { | 47 | void PhysicsSimulation::setRagdoll(Ragdoll* ragdoll) { |
| 48 | if (_ragdoll != ragdoll) { | 48 | if (_ragdoll != ragdoll) { |
| 49 | if (_ragdoll) { | 49 | if (_ragdoll) { |
| 50 | _ragdoll->_ragdollSimulation = NULL; | 50 | _ragdoll->_simulation = NULL; |
| 51 | } | 51 | } |
| 52 | _ragdoll = ragdoll; | 52 | _ragdoll = ragdoll; |
| 53 | if (_ragdoll) { | 53 | if (_ragdoll) { |
| 54 | assert(!(_ragdoll->_ragdollSimulation)); | 54 | assert(!(_ragdoll->_simulation)); |
| 55 | _ragdoll->_ragdollSimulation = this; | 55 | _ragdoll->_simulation = this; |
| 56 | } | 56 | } |
| 57 | } | 57 | } |
| 58 | } | 58 | } |
| @@ -144,7 +144,7 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { · 85 unmodified lines | |||
| 144 | // list is full | 144 | // list is full |
| 145 | return false; | 145 | return false; |
| 146 | } | 146 | } |
| 147 | if (doll->_ragdollSimulation == this) { | 147 | if (doll->_simulation == this) { |
| 148 | for (int i = 0; i < numDolls; ++i) { | 148 | for (int i = 0; i < numDolls; ++i) { |
| 149 | if (doll == _otherRagdolls[i]) { | 149 | if (doll == _otherRagdolls[i]) { |
| 150 | // already in list | 150 | // already in list |
| @@ -153,8 +153,8 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { · 2 unmodified lines | |||
| 153 | } | 153 | } |
| 154 | } | 154 | } |
| 155 | // add to list | 155 | // add to list |
| 156 | assert(!(doll->_ragdollSimulation)); | 156 | assert(!(doll->_simulation)); |
| 157 | doll->_ragdollSimulation = this; | 157 | doll->_simulation = this; |
| 158 | _otherRagdolls.push_back(doll); | 158 | _otherRagdolls.push_back(doll); |
| 159 | 159 | ||
| 160 | // set the massScale of otherRagdolls artificially high | 160 | // set the massScale of otherRagdolls artificially high |
| @@ -164,7 +164,7 @@ bool PhysicsSimulation::addRagdoll(Ragdoll* doll) { · 3 unmodified lines | |||
| 164 | 164 | ||
| 165 | void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { | 165 | void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { |
| 166 | int numDolls = _otherRagdolls.size(); | 166 | int numDolls = _otherRagdolls.size(); |
| 167 | if (doll->_ragdollSimulation != this) { | 167 | if (doll->_simulation != this) { |
| 168 | return; | 168 | return; |
| 169 | } | 169 | } |
| 170 | for (int i = 0; i < numDolls; ++i) { | 170 | for (int i = 0; i < numDolls; ++i) { |
| @@ -178,7 +178,7 @@ void PhysicsSimulation::removeRagdoll(Ragdoll* doll) { · 7 unmodified lines | |||
| 178 | _otherRagdolls.pop_back(); | 178 | _otherRagdolls.pop_back(); |
| 179 | _otherRagdolls[i] = lastDoll; | 179 | _otherRagdolls[i] = lastDoll; |
| 180 | } | 180 | } |
| 181 | doll->_ragdollSimulation = NULL; | 181 | doll->_simulation = NULL; |
| 182 | doll->setMassScale(1.0f); | 182 | doll->setMassScale(1.0f); |
| 183 | break; | 183 | break; |
| 184 | } | 184 | } |
| @@ -195,13 +195,13 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter · 10 unmodified lines | |||
| 195 | quint64 expiry = startTime + maxUsec; | 195 | quint64 expiry = startTime + maxUsec; |
| 196 | 196 | ||
| 197 | moveRagdolls(deltaTime); | 197 | moveRagdolls(deltaTime); |
| 198 | buildContactConstraints(); | 198 | enforceContacts(); |
| 199 | int numDolls = _otherRagdolls.size(); | 199 | int numDolls = _otherRagdolls.size(); |
| 200 | { | 200 | { |
| 201 | PerformanceTimer perfTimer("enforce"); | 201 | PerformanceTimer perfTimer("enforce"); |
| 202 | _ragdoll->enforceRagdollConstraints(); | 202 | _ragdoll->enforceConstraints(); |
| 203 | for (int i = 0; i < numDolls; ++i) { | 203 | for (int i = 0; i < numDolls; ++i) { |
| 204 | _otherRagdolls[i]->enforceRagdollConstraints(); | 204 | _otherRagdolls[i]->enforceConstraints(); |
| 205 | } | 205 | } |
| 206 | } | 206 | } |
| 207 | 207 | ||
| @@ -214,12 +214,12 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter · 6 unmodified lines | |||
| 214 | 214 | ||
| 215 | { // enforce constraints | 215 | { // enforce constraints |
| 216 | PerformanceTimer perfTimer("enforce"); | 216 | PerformanceTimer perfTimer("enforce"); |
| 217 | error = _ragdoll->enforceRagdollConstraints(); | 217 | error = _ragdoll->enforceConstraints(); |
| 218 | for (int i = 0; i < numDolls; ++i) { | 218 | for (int i = 0; i < numDolls; ++i) { |
| 219 | error = glm::max(error, _otherRagdolls[i]->enforceRagdollConstraints()); | 219 | error = glm::max(error, _otherRagdolls[i]->enforceConstraints()); |
| 220 | } | 220 | } |
| 221 | } | 221 | } |
| 222 | enforceContactConstraints(); | 222 | applyContactFriction(); |
| 223 | ++iterations; | 223 | ++iterations; |
| 224 | 224 | ||
| 225 | now = usecTimestampNow(); | 225 | now = usecTimestampNow(); |
| @@ -230,10 +230,10 @@ void PhysicsSimulation::stepForward(float deltaTime, float minError, int maxIter · 4 unmodified lines | |||
| 230 | 230 | ||
| 231 | void PhysicsSimulation::moveRagdolls(float deltaTime) { | 231 | void PhysicsSimulation::moveRagdolls(float deltaTime) { |
| 232 | PerformanceTimer perfTimer("integrate"); | 232 | PerformanceTimer perfTimer("integrate"); |
| 233 | _ragdoll->stepRagdollForward(deltaTime); | 233 | _ragdoll->stepForward(deltaTime); |
| 234 | int numDolls = _otherRagdolls.size(); | 234 | int numDolls = _otherRagdolls.size(); |
| 235 | for (int i = 0; i < numDolls; ++i) { | 235 | for (int i = 0; i < numDolls; ++i) { |
| 236 | _otherRagdolls[i]->stepRagdollForward(deltaTime); | 236 | _otherRagdolls[i]->stepForward(deltaTime); |
| 237 | } | 237 | } |
| 238 | } | 238 | } |
| 239 | 239 | ||
| @@ -288,20 +288,20 @@ void PhysicsSimulation::resolveCollisions() { · 48 unmodified lines | |||
| 288 | } | 288 | } |
| 289 | } | 289 | } |
| 290 | 290 | ||
| 291 | void PhysicsSimulation::buildContactConstraints() { | 291 | void PhysicsSimulation::enforceContacts() { |
| 292 | PerformanceTimer perfTimer("contacts"); | 292 | PerformanceTimer perfTimer("contacts"); |
| 293 | QMap<quint64, ContactPoint>::iterator itr = _contacts.begin(); | 293 | QMap<quint64, ContactPoint>::iterator itr = _contacts.begin(); |
| 294 | while (itr != _contacts.end()) { | 294 | while (itr != _contacts.end()) { |
| 295 | itr.value().buildConstraints(); | 295 | itr.value().enforce(); |
| 296 | ++itr; | 296 | ++itr; |
| 297 | } | 297 | } |
| 298 | } | 298 | } |
| 299 | 299 | ||
| 300 | void PhysicsSimulation::enforceContactConstraints() { | 300 | void PhysicsSimulation::applyContactFriction() { |
| 301 | PerformanceTimer perfTimer("contacts"); | 301 | PerformanceTimer perfTimer("contacts"); |
| 302 | QMap<quint64, ContactPoint>::iterator itr = _contacts.begin(); | 302 | QMap<quint64, ContactPoint>::iterator itr = _contacts.begin(); |
| 303 | while (itr != _contacts.end()) { | 303 | while (itr != _contacts.end()) { |
| 304 | itr.value().enforce(); | 304 | itr.value().applyFriction(); |
| 305 | ++itr; | 305 | ++itr; |
| 306 | } | 306 | } |
| 307 | } | 307 | } |
| @@ -56,8 +56,8 @@ protected: · 55 unmodified lines | |||
| 56 | void computeCollisions(); | 56 | void computeCollisions(); |
| 57 | void resolveCollisions(); | 57 | void resolveCollisions(); |
| 58 | 58 | ||
| 59 | void buildContactConstraints(); | 59 | void enforceContacts(); |
| 60 | void enforceContactConstraints(); | 60 | void applyContactFriction(); |
| 61 | void updateContacts(); | 61 | void updateContacts(); |
| 62 | void pruneContacts(); | 62 | void pruneContacts(); |
| 63 | 63 | ||
| @@ -19,24 +19,27 @@ · 18 unmodified lines | |||
| 19 | #include "PhysicsSimulation.h" | 19 | #include "PhysicsSimulation.h" |
| 20 | #include "SharedUtil.h" // for EPSILON | 20 | #include "SharedUtil.h" // for EPSILON |
| 21 | 21 | ||
| 22 | Ragdoll::Ragdoll() : _massScale(1.0f), _ragdollTranslation(0.0f), _translationInSimulationFrame(0.0f), _ragdollSimulation(NULL) { | 22 | Ragdoll::Ragdoll() : _massScale(1.0f), _translation(0.0f), _translationInSimulationFrame(0.0f), _simulation(NULL) { |
| 23 | } | 23 | } |
| 24 | 24 | ||
| 25 | Ragdoll::~Ragdoll() { | 25 | Ragdoll::~Ragdoll() { |
| 26 | clearRagdollConstraintsAndPoints(); | 26 | clearConstraintsAndPoints(); |
| 27 | if (_simulation) { | ||
| 28 | _simulation->removeRagdoll(this); | ||
| 29 | } | ||
| 27 | } | 30 | } |
| 28 | 31 | ||
| 29 | void Ragdoll::stepRagdollForward(float deltaTime) { | 32 | void Ragdoll::stepForward(float deltaTime) { |
| 30 | if (_ragdollSimulation) { | 33 | if (_simulation) { |
| 31 | updateSimulationTransforms(_ragdollTranslation - _ragdollSimulation->getTranslation(), _ragdollRotation); | 34 | updateSimulationTransforms(_translation - _simulation->getTranslation(), _rotation); |
| 32 | } | 35 | } |
| 33 | int numPoints = _ragdollPoints.size(); | 36 | int numPoints = _points.size(); |
| 34 | for (int i = 0; i < numPoints; ++i) { | 37 | for (int i = 0; i < numPoints; ++i) { |
| 35 | _ragdollPoints[i].integrateForward(); | 38 | _points[i].integrateForward(); |
| 36 | } | 39 | } |
| 37 | } | 40 | } |
| 38 | 41 | ||
| 39 | void Ragdoll::clearRagdollConstraintsAndPoints() { | 42 | void Ragdoll::clearConstraintsAndPoints() { |
| 40 | int numConstraints = _boneConstraints.size(); | 43 | int numConstraints = _boneConstraints.size(); |
| 41 | for (int i = 0; i < numConstraints; ++i) { | 44 | for (int i = 0; i < numConstraints; ++i) { |
| 42 | delete _boneConstraints[i]; | 45 | delete _boneConstraints[i]; |
| @@ -47,10 +50,10 @@ void Ragdoll::clearRagdollConstraintsAndPoints() { · 4 unmodified lines | |||
| 47 | delete _fixedConstraints[i]; | 50 | delete _fixedConstraints[i]; |
| 48 | } | 51 | } |
| 49 | _fixedConstraints.clear(); | 52 | _fixedConstraints.clear(); |
| 50 | _ragdollPoints.clear(); | 53 | _points.clear(); |
| 51 | } | 54 | } |
| 52 | 55 | ||
| 53 | float Ragdoll::enforceRagdollConstraints() { | 56 | float Ragdoll::enforceConstraints() { |
| 54 | float maxDistance = 0.0f; | 57 | float maxDistance = 0.0f; |
| 55 | // enforce the bone constraints first | 58 | // enforce the bone constraints first |
| 56 | int numConstraints = _boneConstraints.size(); | 59 | int numConstraints = _boneConstraints.size(); |
| @@ -65,16 +68,16 @@ float Ragdoll::enforceRagdollConstraints() { · 8 unmodified lines | |||
| 65 | return maxDistance; | 68 | return maxDistance; |
| 66 | } | 69 | } |
| 67 | 70 | ||
| 68 | void Ragdoll::initRagdollTransform() { | 71 | void Ragdoll::initTransform() { |
| 69 | _ragdollTranslation = glm::vec3(0.0f); | 72 | _translation = glm::vec3(0.0f); |
| 70 | _ragdollRotation = glm::quat(); | 73 | _rotation = glm::quat(); |
| 71 | _translationInSimulationFrame = glm::vec3(0.0f); | 74 | _translationInSimulationFrame = glm::vec3(0.0f); |
| 72 | _rotationInSimulationFrame = glm::quat(); | 75 | _rotationInSimulationFrame = glm::quat(); |
| 73 | } | 76 | } |
| 74 | 77 | ||
| 75 | void Ragdoll::setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation) { | 78 | void Ragdoll::setTransform(const glm::vec3& translation, const glm::quat& rotation) { |
| 76 | _ragdollTranslation = translation; | 79 | _translation = translation; |
| 77 | _ragdollRotation = rotation; | 80 | _rotation = rotation; |
| 78 | } | 81 | } |
| 79 | 82 | ||
| 80 | void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation) { | 83 | void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation) { |
| @@ -90,9 +93,9 @@ void Ragdoll::updateSimulationTransforms(const glm::vec3& translation, const glm · 9 unmodified lines | |||
| 90 | glm::quat deltaRotation = rotation * glm::inverse(_rotationInSimulationFrame); | 93 | glm::quat deltaRotation = rotation * glm::inverse(_rotationInSimulationFrame); |
| 91 | 94 | ||
| 92 | // apply the deltas to all ragdollPoints | 95 | // apply the deltas to all ragdollPoints |
| 93 | int numPoints = _ragdollPoints.size(); | 96 | int numPoints = _points.size(); |
| 94 | for (int i = 0; i < numPoints; ++i) { | 97 | for (int i = 0; i < numPoints; ++i) { |
| 95 | _ragdollPoints[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame); | 98 | _points[i].move(deltaPosition, deltaRotation, _translationInSimulationFrame); |
| 96 | } | 99 | } |
| 97 | 100 | ||
| 98 | // remember the current transform | 101 | // remember the current transform |
| @@ -106,9 +109,9 @@ void Ragdoll::setMassScale(float scale) { · 7 unmodified lines | |||
| 106 | scale = glm::clamp(glm::abs(scale), MIN_SCALE, MAX_SCALE); | 109 | scale = glm::clamp(glm::abs(scale), MIN_SCALE, MAX_SCALE); |
| 107 | if (scale != _massScale) { | 110 | if (scale != _massScale) { |
| 108 | float rescale = scale / _massScale; | 111 | float rescale = scale / _massScale; |
| 109 | int numPoints = _ragdollPoints.size(); | 112 | int numPoints = _points.size(); |
| 110 | for (int i = 0; i < numPoints; ++i) { | 113 | for (int i = 0; i < numPoints; ++i) { |
| 111 | _ragdollPoints[i].setMass(rescale * _ragdollPoints[i].getMass()); | 114 | _points[i].setMass(rescale * _points[i].getMass()); |
| 112 | } | 115 | } |
| 113 | _massScale = scale; | 116 | _massScale = scale; |
| 114 | } | 117 | } |
| @@ -33,44 +33,44 @@ public: · 32 unmodified lines | |||
| 33 | Ragdoll(); | 33 | Ragdoll(); |
| 34 | virtual ~Ragdoll(); | 34 | virtual ~Ragdoll(); |
| 35 | 35 | ||
| 36 | virtual void stepRagdollForward(float deltaTime); | 36 | virtual void stepForward(float deltaTime); |
| 37 | 37 | ||
| 38 | /// \return max distance of point movement | 38 | /// \return max distance of point movement |
| 39 | float enforceRagdollConstraints(); | 39 | float enforceConstraints(); |
| 40 | 40 | ||
| 41 | // both const and non-const getPoints() | 41 | // both const and non-const getPoints() |
| 42 | const QVector<VerletPoint>& getRagdollPoints() const { return _ragdollPoints; } | 42 | const QVector<VerletPoint>& getPoints() const { return _points; } |
| 43 | QVector<VerletPoint>& getRagdollPoints() { return _ragdollPoints; } | 43 | QVector<VerletPoint>& getPoints() { return _points; } |
| 44 | 44 | ||
| 45 | void initRagdollTransform(); | 45 | void initTransform(); |
| 46 | 46 | ||
| 47 | /// set the translation and rotation of the Ragdoll and adjust all VerletPoints. | 47 | /// set the translation and rotation of the Ragdoll and adjust all VerletPoints. |
| 48 | void setRagdollTransform(const glm::vec3& translation, const glm::quat& rotation); | 48 | void setTransform(const glm::vec3& translation, const glm::quat& rotation); |
| 49 | 49 | ||
| 50 | const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; } | 50 | const glm::vec3& getTranslationInSimulationFrame() const { return _translationInSimulationFrame; } |
| 51 | 51 | ||
| 52 | void setMassScale(float scale); | 52 | void setMassScale(float scale); |
| 53 | float getMassScale() const { return _massScale; } | 53 | float getMassScale() const { return _massScale; } |
| 54 | 54 | ||
| 55 | protected: | 55 | void clearConstraintsAndPoints(); |
| 56 | void clearRagdollConstraintsAndPoints(); | 56 | virtual void initPoints() = 0; |
| 57 | virtual void initRagdollPoints() = 0; | 57 | virtual void buildConstraints() = 0; |
| 58 | virtual void buildRagdollConstraints() = 0; | ||
| 59 | 58 | ||
| 59 | protected: | ||
| 60 | float _massScale; | 60 | float _massScale; |
| 61 | glm::vec3 _ragdollTranslation; // world-frame | 61 | glm::vec3 _translation; // world-frame |
| 62 | glm::quat _ragdollRotation; // world-frame | 62 | glm::quat _rotation; // world-frame |
| 63 | glm::vec3 _translationInSimulationFrame; | 63 | glm::vec3 _translationInSimulationFrame; |
| 64 | glm::quat _rotationInSimulationFrame; | 64 | glm::quat _rotationInSimulationFrame; |
| 65 | 65 | ||
| 66 | QVector<VerletPoint> _ragdollPoints; | 66 | QVector<VerletPoint> _points; |
| 67 | QVector<DistanceConstraint*> _boneConstraints; | 67 | QVector<DistanceConstraint*> _boneConstraints; |
| 68 | QVector<FixedConstraint*> _fixedConstraints; | 68 | QVector<FixedConstraint*> _fixedConstraints; |
| 69 | private: | 69 | private: |
| 70 | void updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation); | 70 | void updateSimulationTransforms(const glm::vec3& translation, const glm::quat& rotation); |
| 71 | 71 | ||
| 72 | friend class PhysicsSimulation; | 72 | friend class PhysicsSimulation; |
| 73 | PhysicsSimulation* _ragdollSimulation; | 73 | PhysicsSimulation* _simulation; |
| 74 | }; | 74 | }; |
| 75 | 75 | ||
| 76 | #endif // hifi_Ragdoll_h | 76 | #endif // hifi_Ragdoll_h |
| @@ -9,6 +9,7 @@ · 8 unmodified lines | |||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | // | 10 | // |
| 11 | 11 | ||
| 12 | #include <cassert> | ||
| 12 | #include <cstdlib> | 13 | #include <cstdlib> |
| 13 | #include <cstdio> | 14 | #include <cstdio> |
| 14 | #include <cstring> | 15 | #include <cstring> |
| @@ -79,40 +80,6 @@ bool shouldDo(float desiredInterval, float deltaTime) { · 64 unmodified lines | |||
| 79 | return randFloat() < deltaTime / desiredInterval; | 80 | return randFloat() < deltaTime / desiredInterval; |
| 80 | } | 81 | } |
| 81 | 82 | ||
| 82 | // Safe version of glm::mix; based on the code in Nick Bobick's article, | ||
| 83 | // http://www.gamasutra.com/features/19980703/quaternions_01.htm (via Clyde, | ||
| 84 | // https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) | ||
| 85 | glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float proportion) { | ||
| 86 | float cosa = q1.x * q2.x + q1.y * q2.y + q1.z * q2.z + q1.w * q2.w; | ||
| 87 | float ox = q2.x, oy = q2.y, oz = q2.z, ow = q2.w, s0, s1; | ||
| 88 | |||
| 89 | // adjust signs if necessary | ||
| 90 | if (cosa < 0.0f) { | ||
| 91 | cosa = -cosa; | ||
| 92 | ox = -ox; | ||
| 93 | oy = -oy; | ||
| 94 | oz = -oz; | ||
| 95 | ow = -ow; | ||
| 96 | } | ||
| 97 | |||
| 98 | // calculate coefficients; if the angle is too close to zero, we must fall back | ||
| 99 | // to linear interpolation | ||
| 100 | if ((1.0f - cosa) > EPSILON) { | ||
| 101 | float angle = acosf(cosa), sina = sinf(angle); | ||
| 102 | s0 = sinf((1.0f - proportion) * angle) / sina; | ||
| 103 | s1 = sinf(proportion * angle) / sina; | ||
| 104 | |||
| 105 | } else { | ||
| 106 | s0 = 1.0f - proportion; | ||
| 107 | s1 = proportion; | ||
| 108 | } | ||
| 109 | |||
| 110 | return glm::normalize(glm::quat(s0 * q1.w + s1 * ow, s0 * q1.x + s1 * ox, s0 * q1.y + s1 * oy, s0 * q1.z + s1 * oz)); | ||
| 111 | } | ||
| 112 | |||
| 113 | |||
| 114 | |||
| 115 | |||
| 116 | void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) { | 83 | void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug) { |
| 117 | for (int i = 0; i < length; i++) { | 84 | for (int i = 0; i < length; i++) { |
| 118 | outputBits(buffer[i], continuedDebug); | 85 | outputBits(buffer[i], continuedDebug); |
| @@ -489,73 +456,6 @@ int removeFromSortedArrays(void* value, void** valueArray, float* keyArray, int* · 370 unmodified lines | |||
| 489 | return -1; // error case | 456 | return -1; // error case |
| 490 | } | 457 | } |
| 491 | 458 | ||
| 492 | // Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc | ||
| 493 | int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix) { | ||
| 494 | int16_t outVal = (int16_t)(scalar * (float)(1 << radix)); | ||
| 495 | memcpy(buffer, &outVal, sizeof(uint16_t)); | ||
| 496 | return sizeof(uint16_t); | ||
| 497 | } | ||
| 498 | |||
| 499 | int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix) { | ||
| 500 | *destinationPointer = *byteFixedPointer / (float)(1 << radix); | ||
| 501 | return sizeof(int16_t); | ||
| 502 | } | ||
| 503 | |||
| 504 | int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix) { | ||
| 505 | const unsigned char* startPosition = destBuffer; | ||
| 506 | destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.x, radix); | ||
| 507 | destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.y, radix); | ||
| 508 | destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.z, radix); | ||
| 509 | return destBuffer - startPosition; | ||
| 510 | } | ||
| 511 | |||
| 512 | int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix) { | ||
| 513 | const unsigned char* startPosition = sourceBuffer; | ||
| 514 | sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.x), radix); | ||
| 515 | sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.y), radix); | ||
| 516 | sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.z), radix); | ||
| 517 | return sourceBuffer - startPosition; | ||
| 518 | } | ||
| 519 | |||
| 520 | |||
| 521 | int packFloatAngleToTwoByte(unsigned char* buffer, float degrees) { | ||
| 522 | const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.f); | ||
| 523 | |||
| 524 | uint16_t angleHolder = floorf((degrees + 180.f) * ANGLE_CONVERSION_RATIO); | ||
| 525 | memcpy(buffer, &angleHolder, sizeof(uint16_t)); | ||
| 526 | |||
| 527 | return sizeof(uint16_t); | ||
| 528 | } | ||
| 529 | |||
| 530 | int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer) { | ||
| 531 | *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits<uint16_t>::max()) * 360.f - 180.f; | ||
| 532 | return sizeof(uint16_t); | ||
| 533 | } | ||
| 534 | |||
| 535 | int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput) { | ||
| 536 | const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 2.f); | ||
| 537 | uint16_t quatParts[4]; | ||
| 538 | quatParts[0] = floorf((quatInput.x + 1.f) * QUAT_PART_CONVERSION_RATIO); | ||
| 539 | quatParts[1] = floorf((quatInput.y + 1.f) * QUAT_PART_CONVERSION_RATIO); | ||
| 540 | quatParts[2] = floorf((quatInput.z + 1.f) * QUAT_PART_CONVERSION_RATIO); | ||
| 541 | quatParts[3] = floorf((quatInput.w + 1.f) * QUAT_PART_CONVERSION_RATIO); | ||
| 542 | |||
| 543 | memcpy(buffer, &quatParts, sizeof(quatParts)); | ||
| 544 | return sizeof(quatParts); | ||
| 545 | } | ||
| 546 | |||
| 547 | int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput) { | ||
| 548 | uint16_t quatParts[4]; | ||
| 549 | memcpy(&quatParts, buffer, sizeof(quatParts)); | ||
| 550 | |||
| 551 | quatOutput.x = ((quatParts[0] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f; | ||
| 552 | quatOutput.y = ((quatParts[1] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f; | ||
| 553 | quatOutput.z = ((quatParts[2] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f; | ||
| 554 | quatOutput.w = ((quatParts[3] / (float) std::numeric_limits<uint16_t>::max()) * 2.f) - 1.f; | ||
| 555 | |||
| 556 | return sizeof(quatParts); | ||
| 557 | } | ||
| 558 | |||
| 559 | float SMALL_LIMIT = 10.f; | 459 | float SMALL_LIMIT = 10.f; |
| 560 | float LARGE_LIMIT = 1000.f; | 460 | float LARGE_LIMIT = 1000.f; |
| 561 | 461 | ||
| @@ -651,199 +551,10 @@ void debug::checkDeadBeef(void* memoryVoid, int size) { · 89 unmodified lines | |||
| 651 | assert(memcmp((unsigned char*)memoryVoid, DEADBEEF, std::min(size, DEADBEEF_SIZE)) != 0); | 551 | assert(memcmp((unsigned char*)memoryVoid, DEADBEEF, std::min(size, DEADBEEF_SIZE)) != 0); |
| 652 | } | 552 | } |
| 653 | 553 | ||
| 654 | // Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's | ||
| 655 | // http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde, | ||
| 656 | // https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) | ||
| 657 | glm::vec3 safeEulerAngles(const glm::quat& q) { | ||
| 658 | float sy = 2.0f * (q.y * q.w - q.x * q.z); | ||
| 659 | glm::vec3 eulers; | ||
| 660 | if (sy < 1.0f - EPSILON) { | ||
| 661 | if (sy > -1.0f + EPSILON) { | ||
| 662 | eulers = glm::vec3( | ||
| 663 | atan2f(q.y * q.z + q.x * q.w, 0.5f - (q.x * q.x + q.y * q.y)), | ||
| 664 | asinf(sy), | ||
| 665 | atan2f(q.x * q.y + q.z * q.w, 0.5f - (q.y * q.y + q.z * q.z))); | ||
| 666 | |||
| 667 | } else { | ||
| 668 | // not a unique solution; x + z = atan2(-m21, m11) | ||
| 669 | eulers = glm::vec3( | ||
| 670 | 0.0f, | ||
| 671 | - PI_OVER_TWO, | ||
| 672 | atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); | ||
| 673 | } | ||
| 674 | } else { | ||
| 675 | // not a unique solution; x - z = atan2(-m21, m11) | ||
| 676 | eulers = glm::vec3( | ||
| 677 | 0.0f, | ||
| 678 | PI_OVER_TWO, | ||
| 679 | -atan2f(q.x * q.w - q.y * q.z, 0.5f - (q.x * q.x + q.z * q.z))); | ||
| 680 | } | ||
| 681 | |||
| 682 | // adjust so that z, rather than y, is in [-pi/2, pi/2] | ||
| 683 | if (eulers.z < -PI_OVER_TWO) { | ||
| 684 | if (eulers.x < 0.0f) { | ||
| 685 | eulers.x += PI; | ||
| 686 | } else { | ||
| 687 | eulers.x -= PI; | ||
| 688 | } | ||
| 689 | eulers.y = -eulers.y; | ||
| 690 | if (eulers.y < 0.0f) { | ||
| 691 | eulers.y += PI; | ||
| 692 | } else { | ||
| 693 | eulers.y -= PI; | ||
| 694 | } | ||
| 695 | eulers.z += PI; | ||
| 696 | |||
| 697 | } else if (eulers.z > PI_OVER_TWO) { | ||
| 698 | if (eulers.x < 0.0f) { | ||
| 699 | eulers.x += PI; | ||
| 700 | } else { | ||
| 701 | eulers.x -= PI; | ||
| 702 | } | ||
| 703 | eulers.y = -eulers.y; | ||
| 704 | if (eulers.y < 0.0f) { | ||
| 705 | eulers.y += PI; | ||
| 706 | } else { | ||
| 707 | eulers.y -= PI; | ||
| 708 | } | ||
| 709 | eulers.z -= PI; | ||
| 710 | } | ||
| 711 | return eulers; | ||
| 712 | } | ||
| 713 | |||
| 714 | // Helper function returns the positive angle (in radians) between two 3D vectors | ||
| 715 | float angleBetween(const glm::vec3& v1, const glm::vec3& v2) { | ||
| 716 | return acosf((glm::dot(v1, v2)) / (glm::length(v1) * glm::length(v2))); | ||
| 717 | } | ||
| 718 | |||
| 719 | // Helper function return the rotation from the first vector onto the second | ||
| 720 | glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { | ||
| 721 | float angle = angleBetween(v1, v2); | ||
| 722 | if (glm::isnan(angle) || angle < EPSILON) { | ||
| 723 | return glm::quat(); | ||
| 724 | } | ||
| 725 | glm::vec3 axis; | ||
| 726 | if (angle > 179.99f * RADIANS_PER_DEGREE) { // 180 degree rotation; must use another axis | ||
| 727 | axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f)); | ||
| 728 | float axisLength = glm::length(axis); | ||
| 729 | if (axisLength < EPSILON) { // parallel to x; y will work | ||
| 730 | axis = glm::normalize(glm::cross(v1, glm::vec3(0.0f, 1.0f, 0.0f))); | ||
| 731 | } else { | ||
| 732 | axis /= axisLength; | ||
| 733 | } | ||
| 734 | } else { | ||
| 735 | axis = glm::normalize(glm::cross(v1, v2)); | ||
| 736 | // It is possible for axis to be nan even when angle is not less than EPSILON. | ||
| 737 | // For example when angle is small but not tiny but v1 and v2 and have very short lengths. | ||
| 738 | if (glm::isnan(glm::dot(axis, axis))) { | ||
| 739 | // set angle and axis to values that will generate an identity rotation | ||
| 740 | angle = 0.0f; | ||
| 741 | axis = glm::vec3(1.0f, 0.0f, 0.0f); | ||
| 742 | } | ||
| 743 | } | ||
| 744 | return glm::angleAxis(angle, axis); | ||
| 745 | } | ||
| 746 | |||
| 747 | glm::vec3 extractTranslation(const glm::mat4& matrix) { | ||
| 748 | return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]); | ||
| 749 | } | ||
| 750 | |||
| 751 | void setTranslation(glm::mat4& matrix, const glm::vec3& translation) { | ||
| 752 | matrix[3][0] = translation.x; | ||
| 753 | matrix[3][1] = translation.y; | ||
| 754 | matrix[3][2] = translation.z; | ||
| 755 | } | ||
| 756 | |||
| 757 | glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal) { | ||
| 758 | // uses the iterative polar decomposition algorithm described by Ken Shoemake at | ||
| 759 | // http://www.cs.wisc.edu/graphics/Courses/838-s2002/Papers/polar-decomp.pdf | ||
| 760 | // code adapted from Clyde, https://github.com/threerings/clyde/blob/master/core/src/main/java/com/threerings/math/Matrix4f.java | ||
| 761 | // start with the contents of the upper 3x3 portion of the matrix | ||
| 762 | glm::mat3 upper = glm::mat3(matrix); | ||
| 763 | if (!assumeOrthogonal) { | ||
| 764 | for (int i = 0; i < 10; i++) { | ||
| 765 | // store the results of the previous iteration | ||
| 766 | glm::mat3 previous = upper; | ||
| 767 | |||
| 768 | // compute average of the matrix with its inverse transpose | ||
| 769 | float sd00 = previous[1][1] * previous[2][2] - previous[2][1] * previous[1][2]; | ||
| 770 | float sd10 = previous[0][1] * previous[2][2] - previous[2][1] * previous[0][2]; | ||
| 771 | float sd20 = previous[0][1] * previous[1][2] - previous[1][1] * previous[0][2]; | ||
| 772 | float det = previous[0][0] * sd00 + previous[2][0] * sd20 - previous[1][0] * sd10; | ||
| 773 | if (fabs(det) == 0.0f) { | ||
| 774 | // determinant is zero; matrix is not invertible | ||
| 775 | break; | ||
| 776 | } | ||
| 777 | float hrdet = 0.5f / det; | ||
| 778 | upper[0][0] = +sd00 * hrdet + previous[0][0] * 0.5f; | ||
| 779 | upper[1][0] = -sd10 * hrdet + previous[1][0] * 0.5f; | ||
| 780 | upper[2][0] = +sd20 * hrdet + previous[2][0] * 0.5f; | ||
| 781 | |||
| 782 | upper[0][1] = -(previous[1][0] * previous[2][2] - previous[2][0] * previous[1][2]) * hrdet + previous[0][1] * 0.5f; | ||
| 783 | upper[1][1] = +(previous[0][0] * previous[2][2] - previous[2][0] * previous[0][2]) * hrdet + previous[1][1] * 0.5f; | ||
| 784 | upper[2][1] = -(previous[0][0] * previous[1][2] - previous[1][0] * previous[0][2]) * hrdet + previous[2][1] * 0.5f; | ||
| 785 | |||
| 786 | upper[0][2] = +(previous[1][0] * previous[2][1] - previous[2][0] * previous[1][1]) * hrdet + previous[0][2] * 0.5f; | ||
| 787 | upper[1][2] = -(previous[0][0] * previous[2][1] - previous[2][0] * previous[0][1]) * hrdet + previous[1][2] * 0.5f; | ||
| 788 | upper[2][2] = +(previous[0][0] * previous[1][1] - previous[1][0] * previous[0][1]) * hrdet + previous[2][2] * 0.5f; | ||
| 789 | |||
| 790 | // compute the difference; if it's small enough, we're done | ||
| 791 | glm::mat3 diff = upper - previous; | ||
| 792 | if (diff[0][0] * diff[0][0] + diff[1][0] * diff[1][0] + diff[2][0] * diff[2][0] + diff[0][1] * diff[0][1] + | ||
| 793 | diff[1][1] * diff[1][1] + diff[2][1] * diff[2][1] + diff[0][2] * diff[0][2] + diff[1][2] * diff[1][2] + | ||
| 794 | diff[2][2] * diff[2][2] < EPSILON) { | ||
| 795 | break; | ||
| 796 | } | ||
| 797 | } | ||
| 798 | } | ||
| 799 | |||
| 800 | // now that we have a nice orthogonal matrix, we can extract the rotation quaternion | ||
| 801 | // using the method described in http://en.wikipedia.org/wiki/Rotation_matrix#Conversions | ||
| 802 | float x2 = fabs(1.0f + upper[0][0] - upper[1][1] - upper[2][2]); | ||
| 803 | float y2 = fabs(1.0f - upper[0][0] + upper[1][1] - upper[2][2]); | ||
| 804 | float z2 = fabs(1.0f - upper[0][0] - upper[1][1] + upper[2][2]); | ||
| 805 | float w2 = fabs(1.0f + upper[0][0] + upper[1][1] + upper[2][2]); | ||
| 806 | return glm::normalize(glm::quat(0.5f * sqrtf(w2), | ||
| 807 | 0.5f * sqrtf(x2) * (upper[1][2] >= upper[2][1] ? 1.0f : -1.0f), | ||
| 808 | 0.5f * sqrtf(y2) * (upper[2][0] >= upper[0][2] ? 1.0f : -1.0f), | ||
| 809 | 0.5f * sqrtf(z2) * (upper[0][1] >= upper[1][0] ? 1.0f : -1.0f))); | ||
| 810 | } | ||
| 811 | |||
| 812 | glm::vec3 extractScale(const glm::mat4& matrix) { | ||
| 813 | return glm::vec3(glm::length(matrix[0]), glm::length(matrix[1]), glm::length(matrix[2])); | ||
| 814 | } | ||
| 815 | |||
| 816 | float extractUniformScale(const glm::mat4& matrix) { | ||
| 817 | return extractUniformScale(extractScale(matrix)); | ||
| 818 | } | ||
| 819 | |||
| 820 | float extractUniformScale(const glm::vec3& scale) { | ||
| 821 | return (scale.x + scale.y + scale.z) / 3.0f; | ||
| 822 | } | ||
| 823 | |||
| 824 | bool isNaN(float value) { | 554 | bool isNaN(float value) { |
| 825 | return value != value; | 555 | return value != value; |
| 826 | } | 556 | } |
| 827 | 557 | ||
| 828 | bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB, float similarEnough) { | ||
| 829 | // Compute the angular distance between the two orientations | ||
| 830 | float angleOrientation = orientionA == orientionB ? 0.0f : glm::degrees(glm::angle(orientionA * glm::inverse(orientionB))); | ||
| 831 | if (isNaN(angleOrientation)) { | ||
| 832 | angleOrientation = 0.0f; | ||
| 833 | } | ||
| 834 | return (angleOrientation <= similarEnough); | ||
| 835 | } | ||
| 836 | |||
| 837 | bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough) { | ||
| 838 | // Compute the distance between the two points | ||
| 839 | float positionDistance = glm::distance(positionA, positionB); | ||
| 840 | return (positionDistance <= similarEnough); | ||
| 841 | } | ||
| 842 | |||
| 843 | QByteArray createByteArray(const glm::vec3& vector) { | ||
| 844 | return QByteArray::number(vector.x) + ',' + QByteArray::number(vector.y) + ',' + QByteArray::number(vector.z); | ||
| 845 | } | ||
| 846 | |||
| 847 | QString formatUsecTime(float usecs, int prec) { | 558 | QString formatUsecTime(float usecs, int prec) { |
| 848 | static const quint64 SECONDS_PER_MINUTE = 60; | 559 | static const quint64 SECONDS_PER_MINUTE = 60; |
| 849 | static const quint64 USECS_PER_MINUTE = USECS_PER_SECOND * SECONDS_PER_MINUTE; | 560 | static const quint64 USECS_PER_MINUTE = USECS_PER_SECOND * SECONDS_PER_MINUTE; |
| @@ -19,9 +19,6 @@ · 18 unmodified lines | |||
| 19 | #include <unistd.h> // not on windows, not needed for mac or windows | 19 | #include <unistd.h> // not on windows, not needed for mac or windows |
| 20 | #endif | 20 | #endif |
| 21 | 21 | ||
| 22 | #include <glm/glm.hpp> | ||
| 23 | #include <glm/gtc/quaternion.hpp> | ||
| 24 | |||
| 25 | #include <QtCore/QDebug> | 22 | #include <QtCore/QDebug> |
| 26 | 23 | ||
| 27 | const int BYTES_PER_COLOR = 3; | 24 | const int BYTES_PER_COLOR = 3; |
| @@ -71,8 +68,6 @@ float randomSign(); /// \return -1.0 or 1.0 · 43 unmodified lines | |||
| 71 | unsigned char randomColorValue(int minimum = 0); | 68 | unsigned char randomColorValue(int minimum = 0); |
| 72 | bool randomBoolean(); | 69 | bool randomBoolean(); |
| 73 | 70 | ||
| 74 | glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); | ||
| 75 | |||
| 76 | bool shouldDo(float desiredInterval, float deltaTime); | 71 | bool shouldDo(float desiredInterval, float deltaTime); |
| 77 | 72 | ||
| 78 | void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug = NULL); | 73 | void outputBufferBits(const unsigned char* buffer, int length, QDebug* continuedDebug = NULL); |
| @@ -108,8 +103,6 @@ int insertIntoSortedArrays(void* value, float key, int originalIndex, · 29 unmodified lines | |||
| 108 | int removeFromSortedArrays(void* value, void** valueArray, float* keyArray, int* originalIndexArray, | 103 | int removeFromSortedArrays(void* value, void** valueArray, float* keyArray, int* originalIndexArray, |
| 109 | int currentCount, int maxCount); | 104 | int currentCount, int maxCount); |
| 110 | 105 | ||
| 111 | |||
| 112 | |||
| 113 | // Helper Class for debugging | 106 | // Helper Class for debugging |
| 114 | class debug { | 107 | class debug { |
| 115 | public: | 108 | public: |
| @@ -124,71 +117,9 @@ private: · 8 unmodified lines | |||
| 124 | bool isBetween(int64_t value, int64_t max, int64_t min); | 117 | bool isBetween(int64_t value, int64_t max, int64_t min); |
| 125 | 118 | ||
| 126 | 119 | ||
| 127 | // These pack/unpack functions are designed to start specific known types in as efficient a manner | ||
| 128 | // as possible. Taking advantage of the known characteristics of the semantic types. | ||
| 129 | |||
| 130 | // Angles are known to be between 0 and 360 degrees, this allows us to encode in 16bits with great accuracy | ||
| 131 | int packFloatAngleToTwoByte(unsigned char* buffer, float degrees); | ||
| 132 | int unpackFloatAngleFromTwoByte(const uint16_t* byteAnglePointer, float* destinationPointer); | ||
| 133 | |||
| 134 | // Orientation Quats are known to have 4 normalized components be between -1.0 and 1.0 | ||
| 135 | // this allows us to encode each component in 16bits with great accuracy | ||
| 136 | int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput); | ||
| 137 | int unpackOrientationQuatFromBytes(const unsigned char* buffer, glm::quat& quatOutput); | ||
| 138 | |||
| 139 | // Ratios need the be highly accurate when less than 10, but not very accurate above 10, and they | ||
| 140 | // are never greater than 1000 to 1, this allows us to encode each component in 16bits | ||
| 141 | int packFloatRatioToTwoByte(unsigned char* buffer, float ratio); | ||
| 142 | int unpackFloatRatioFromTwoByte(const unsigned char* buffer, float& ratio); | ||
| 143 | |||
| 144 | // Near/Far Clip values need the be highly accurate when less than 10, but only integer accuracy above 10 and | ||
| 145 | // they are never greater than 16,000, this allows us to encode each component in 16bits | ||
| 146 | int packClipValueToTwoByte(unsigned char* buffer, float clipValue); | ||
| 147 | int unpackClipValueFromTwoByte(const unsigned char* buffer, float& clipValue); | ||
| 148 | |||
| 149 | // Positive floats that don't need to be very precise | ||
| 150 | int packFloatToByte(unsigned char* buffer, float value, float scaleBy); | ||
| 151 | int unpackFloatFromByte(const unsigned char* buffer, float& value, float scaleBy); | ||
| 152 | |||
| 153 | // Allows sending of fixed-point numbers: radix 1 makes 15.1 number, radix 8 makes 8.8 number, etc | ||
| 154 | int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix); | ||
| 155 | int unpackFloatScalarFromSignedTwoByteFixed(const int16_t* byteFixedPointer, float* destinationPointer, int radix); | ||
| 156 | |||
| 157 | // A convenience for sending vec3's as fixed-point floats | ||
| 158 | int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix); | ||
| 159 | int unpackFloatVec3FromSignedTwoByteFixed(const unsigned char* sourceBuffer, glm::vec3& destination, int radix); | ||
| 160 | |||
| 161 | /// \return vec3 with euler angles in radians | ||
| 162 | glm::vec3 safeEulerAngles(const glm::quat& q); | ||
| 163 | |||
| 164 | float angleBetween(const glm::vec3& v1, const glm::vec3& v2); | ||
| 165 | |||
| 166 | glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); | ||
| 167 | |||
| 168 | glm::vec3 extractTranslation(const glm::mat4& matrix); | ||
| 169 | |||
| 170 | void setTranslation(glm::mat4& matrix, const glm::vec3& translation); | ||
| 171 | |||
| 172 | glm::quat extractRotation(const glm::mat4& matrix, bool assumeOrthogonal = false); | ||
| 173 | |||
| 174 | glm::vec3 extractScale(const glm::mat4& matrix); | ||
| 175 | |||
| 176 | float extractUniformScale(const glm::mat4& matrix); | ||
| 177 | |||
| 178 | float extractUniformScale(const glm::vec3& scale); | ||
| 179 | |||
| 180 | /// \return bool are two orientations similar to each other | ||
| 181 | const float ORIENTATION_SIMILAR_ENOUGH = 5.0f; // 10 degrees in any direction | ||
| 182 | bool isSimilarOrientation(const glm::quat& orientionA, const glm::quat& orientionB, | ||
| 183 | float similarEnough = ORIENTATION_SIMILAR_ENOUGH); | ||
| 184 | const float POSITION_SIMILAR_ENOUGH = 0.1f; // 0.1 meter | ||
| 185 | bool isSimilarPosition(const glm::vec3& positionA, const glm::vec3& positionB, float similarEnough = POSITION_SIMILAR_ENOUGH); | ||
| 186 | |||
| 187 | /// \return bool is the float NaN | 120 | /// \return bool is the float NaN |
| 188 | bool isNaN(float value); | 121 | bool isNaN(float value); |
| 189 | 122 | ||
| 190 | QByteArray createByteArray(const glm::vec3& vector); | ||
| 191 | |||
| 192 | QString formatUsecTime(float usecs, int prec = 3); | 123 | QString formatUsecTime(float usecs, int prec = 3); |
| 193 | 124 | ||
| 194 | 125 | ||
| @@ -1,31 +1,18 @@ | |||
| 1 | set(ROOT_DIR ../..) | ||
| 2 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 3 | |||
| 4 | # setup for find modules | ||
| 5 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 6 | |||
| 7 | set(TARGET_NAME voxels) | 1 | set(TARGET_NAME voxels) |
| 8 | 2 | ||
| 9 | find_package(Qt5 COMPONENTS Widgets Script) | 3 | # use setup_hifi_library macro to setup our project and link appropriate Qt modules |
| 10 | 4 | setup_hifi_library(Widgets Script) | |
| 11 | include(${MACRO_DIR}/SetupHifiLibrary.cmake) | ||
| 12 | setup_hifi_library(${TARGET_NAME}) | ||
| 13 | 5 | ||
| 14 | include(${MACRO_DIR}/IncludeGLM.cmake) | 6 | include_glm() |
| 15 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 16 | 7 | ||
| 17 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 8 | link_hifi_libraries(shared octree networking) |
| 18 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 19 | link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") | ||
| 20 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 21 | |||
| 22 | # link ZLIB | ||
| 23 | find_package(ZLIB) | ||
| 24 | 9 | ||
| 10 | # find ZLIB | ||
| 11 | find_package(ZLIB REQUIRED) | ||
| 25 | include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") | 12 | include_directories(SYSTEM "${ZLIB_INCLUDE_DIRS}") |
| 26 | target_link_libraries(${TARGET_NAME} "${ZLIB_LIBRARIES}" Qt5::Widgets Qt5::Script) | ||
| 27 | 13 | ||
| 28 | # add a definition for ssize_t so that windows doesn't bail | 14 | # add it to our list of libraries to link |
| 29 | if (WIN32) | 15 | list(APPEND ${TARGET}_LIBRARIES_TO_LINK "${ZLIB_LIBRARIES}") |
| 30 | add_definitions(-Dssize_t=long) | 16 | |
| 31 | endif () | 17 | # call macro to link our dependencies and bubble them up via a property on our target |
| 18 | link_shared_dependencies() | ||
| @@ -28,7 +28,7 @@ public: · 27 unmodified lines | |||
| 28 | /// Queues a single voxel edit message. Will potentially send a pending multi-command packet. Determines which voxel-server | 28 | /// Queues a single voxel edit message. Will potentially send a pending multi-command packet. Determines which voxel-server |
| 29 | /// node or nodes the packet should be sent to. Can be called even before voxel servers are known, in which case up to | 29 | /// node or nodes the packet should be sent to. Can be called even before voxel servers are known, in which case up to |
| 30 | /// MaxPendingMessages will be buffered and processed when voxel servers are known. | 30 | /// MaxPendingMessages will be buffered and processed when voxel servers are known. |
| 31 | void queueVoxelEditMessage(PacketType type, unsigned char* codeColorBuffer, ssize_t length) { | 31 | void queueVoxelEditMessage(PacketType type, unsigned char* codeColorBuffer, size_t length) { |
| 32 | queueOctreeEditMessage(type, codeColorBuffer, length); | 32 | queueOctreeEditMessage(type, codeColorBuffer, length); |
| 33 | } | 33 | } |
| 34 | 34 | ||
| @@ -1,34 +1,10 @@ | |||
| 1 | set(TARGET_NAME audio-tests) | 1 | set(TARGET_NAME audio-tests) |
| 2 | 2 | ||
| 3 | set(ROOT_DIR ../..) | 3 | setup_hifi_project() |
| 4 | set(MACRO_DIR ${ROOT_DIR}/cmake/macros) | ||
| 5 | 4 | ||
| 6 | # setup for find modules | 5 | include_glm() |
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 8 | |||
| 9 | #find_package(Qt5Network REQUIRED) | ||
| 10 | #find_package(Qt5Script REQUIRED) | ||
| 11 | #find_package(Qt5Widgets REQUIRED) | ||
| 12 | |||
| 13 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 14 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 15 | |||
| 16 | include(${MACRO_DIR}/AutoMTC.cmake) | ||
| 17 | auto_mtc(${TARGET_NAME} ${ROOT_DIR}) | ||
| 18 | |||
| 19 | #qt5_use_modules(${TARGET_NAME} Network Script Widgets) | ||
| 20 | |||
| 21 | #include glm | ||
| 22 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 23 | include_glm(${TARGET_NAME} ${ROOT_DIR}) | ||
| 24 | 6 | ||
| 25 | # link in the shared libraries | 7 | # link in the shared libraries |
| 26 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 8 | link_hifi_libraries(shared audio networking) |
| 27 | link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) | ||
| 28 | link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) | ||
| 29 | link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) | ||
| 30 | |||
| 31 | IF (WIN32) | ||
| 32 | target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 33 | ENDIF(WIN32) | ||
| 34 | 9 | ||
| 10 | link_shared_dependencies() | ||
| @@ -1,33 +1,8 @@ | |||
| 1 | set(TARGET_NAME jitter-tests) | 1 | set(TARGET_NAME jitter-tests) |
| 2 | 2 | ||
| 3 | set(ROOT_DIR ../..) | 3 | setup_hifi_project() |
| 4 | set(MACRO_DIR ${ROOT_DIR}/cmake/macros) | ||
| 5 | |||
| 6 | # setup for find modules | ||
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 8 | |||
| 9 | #find_package(Qt5Network REQUIRED) | ||
| 10 | #find_package(Qt5Script REQUIRED) | ||
| 11 | #find_package(Qt5Widgets REQUIRED) | ||
| 12 | |||
| 13 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 14 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 15 | |||
| 16 | #include(${MACRO_DIR}/AutoMTC.cmake) | ||
| 17 | #auto_mtc(${TARGET_NAME} ${ROOT_DIR}) | ||
| 18 | |||
| 19 | #qt5_use_modules(${TARGET_NAME} Network Script Widgets) | ||
| 20 | |||
| 21 | #include glm - because it's a dependency of shared utils... | ||
| 22 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 23 | include_glm(${TARGET_NAME} ${ROOT_DIR}) | ||
| 24 | 4 | ||
| 25 | # link in the shared libraries | 5 | # link in the shared libraries |
| 26 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 6 | link_hifi_libraries(shared networking) |
| 27 | link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) | ||
| 28 | link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) | ||
| 29 | |||
| 30 | IF (WIN32) | ||
| 31 | target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 32 | ENDIF(WIN32) | ||
| 33 | 7 | ||
| 8 | link_shared_dependencies() | ||
| @@ -13,12 +13,17 @@ · 12 unmodified lines | |||
| 13 | #include <sys/socket.h> | 13 | #include <sys/socket.h> |
| 14 | #include <arpa/inet.h> | 14 | #include <arpa/inet.h> |
| 15 | #endif | 15 | #endif |
| 16 | #include <cerrno> | ||
| 16 | #include <stdio.h> | 17 | #include <stdio.h> |
| 17 | 18 | ||
| 18 | #include <MovingMinMaxAvg.h> // for MovingMinMaxAvg | 19 | #include <MovingMinMaxAvg.h> |
| 20 | #include <SequenceNumberStats.h> | ||
| 19 | #include <SharedUtil.h> // for usecTimestampNow | 21 | #include <SharedUtil.h> // for usecTimestampNow |
| 22 | #include <SimpleMovingAverage.h> | ||
| 23 | #include <StdDev.h> | ||
| 20 | 24 | ||
| 21 | const quint64 MSEC_TO_USEC = 1000; | 25 | const quint64 MSEC_TO_USEC = 1000; |
| 26 | const quint64 LARGE_STATS_TIME = 500; // we don't expect stats calculation to take more than this many usecs | ||
| 22 | 27 | ||
| 23 | void runSend(const char* addressOption, int port, int gap, int size, int report); | 28 | void runSend(const char* addressOption, int port, int gap, int size, int report); |
| 24 | void runReceive(const char* addressOption, int port, int gap, int size, int report); | 29 | void runReceive(const char* addressOption, int port, int gap, int size, int report); |
| @@ -56,112 +61,315 @@ int main(int argc, const char * argv[]) { · 31 unmodified lines | |||
| 56 | void runSend(const char* addressOption, int port, int gap, int size, int report) { | 61 | void runSend(const char* addressOption, int port, int gap, int size, int report) { |
| 57 | std::cout << "runSend...\n"; | 62 | std::cout << "runSend...\n"; |
| 58 | 63 | ||
| 64 | #ifdef _WIN32 | ||
| 65 | WSADATA wsaData; | ||
| 66 | if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { | ||
| 67 | printf("WSAStartup failed with error %d\n", WSAGetLastError()); | ||
| 68 | return; | ||
| 69 | } | ||
| 70 | #endif | ||
| 71 | |||
| 59 | int sockfd; | 72 | int sockfd; |
| 60 | struct sockaddr_in servaddr; | 73 | struct sockaddr_in servaddr; |
| 61 | 74 | ||
| 62 | char* outputBuffer = new char[size]; | 75 | sockfd = socket(AF_INET, SOCK_DGRAM, 0); |
| 63 | memset(outputBuffer, 0, size); | 76 | |
| 64 | |||
| 65 | sockfd=socket(AF_INET,SOCK_DGRAM,0); | ||
| 66 | |||
| 67 | memset(&servaddr, 0, sizeof(servaddr)); | 77 | memset(&servaddr, 0, sizeof(servaddr)); |
| 68 | servaddr.sin_family = AF_INET; | 78 | servaddr.sin_family = AF_INET; |
| 69 | servaddr.sin_addr.s_addr=inet_addr(addressOption); | 79 | servaddr.sin_addr.s_addr = inet_addr(addressOption); |
| 70 | servaddr.sin_port=htons(port); | 80 | servaddr.sin_port = htons(port); |
| 71 | |||
| 72 | const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; | ||
| 73 | 81 | ||
| 82 | const int SAMPLES_FOR_SECOND = 1000000 / gap; | ||
| 83 | std::cout << "SAMPLES_FOR_SECOND:" << SAMPLES_FOR_SECOND << "\n"; | ||
| 84 | const int INTERVALS_PER_30_SECONDS = 30; | ||
| 85 | std::cout << "INTERVALS_PER_30_SECONDS:" << INTERVALS_PER_30_SECONDS << "\n"; | ||
| 86 | const int SAMPLES_FOR_30_SECONDS = 30 * SAMPLES_FOR_SECOND; | ||
| 74 | std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; | 87 | std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; |
| 88 | const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report; | ||
| 89 | std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n"; | ||
| 90 | |||
| 91 | int intervalsPerReport = report / MSEC_TO_USEC; | ||
| 92 | if (intervalsPerReport < 1) { | ||
| 93 | intervalsPerReport = 1; | ||
| 94 | } | ||
| 95 | std::cout << "intervalsPerReport:" << intervalsPerReport << "\n"; | ||
| 96 | MovingMinMaxAvg<int> timeGaps(SAMPLES_FOR_SECOND, INTERVALS_PER_30_SECONDS); | ||
| 97 | MovingMinMaxAvg<int> timeGapsPerReport(SAMPLES_FOR_SECOND, intervalsPerReport); | ||
| 98 | |||
| 99 | char* outputBuffer = new char[size]; | ||
| 100 | memset(outputBuffer, 0, size); | ||
| 101 | |||
| 102 | quint16 outgoingSequenceNumber = 0; | ||
| 103 | |||
| 104 | |||
| 105 | StDev stDevReportInterval; | ||
| 106 | StDev stDev30s; | ||
| 107 | StDev stDev; | ||
| 108 | |||
| 109 | SimpleMovingAverage averageNetworkTime(SAMPLES_FOR_30_SECONDS); | ||
| 110 | SimpleMovingAverage averageStatsCalcultionTime(SAMPLES_FOR_30_SECONDS); | ||
| 111 | float lastStatsCalculationTime = 0.0f; // we add out stats calculation time in the next calculation window | ||
| 112 | bool hasStatsCalculationTime = false; | ||
| 75 | 113 | ||
| 76 | MovingMinMaxAvg<int> timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats | ||
| 77 | |||
| 78 | quint64 last = usecTimestampNow(); | 114 | quint64 last = usecTimestampNow(); |
| 79 | quint64 lastReport = 0; | 115 | quint64 lastReport = 0; |
| 80 | 116 | ||
| 81 | while (true) { | 117 | while (true) { |
| 82 | 118 | ||
| 83 | quint64 now = usecTimestampNow(); | 119 | quint64 now = usecTimestampNow(); |
| 84 | int actualGap = now - last; | 120 | int actualGap = now - last; |
| 85 | 121 | ||
| 86 | 122 | ||
| 87 | if (actualGap >= gap) { | 123 | if (actualGap >= gap) { |
| 88 | sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); | 124 | |
| 89 | 125 | // pack seq num | |
| 126 | memcpy(outputBuffer, &outgoingSequenceNumber, sizeof(quint16)); | ||
| 127 | |||
| 128 | quint64 networkStart = usecTimestampNow(); | ||
| 129 | int n = sendto(sockfd, outputBuffer, size, 0, (struct sockaddr *)&servaddr, sizeof(servaddr)); | ||
| 130 | quint64 networkEnd = usecTimestampNow(); | ||
| 131 | float networkElapsed = (float)(networkEnd - networkStart); | ||
| 132 | |||
| 133 | if (n < 0) { | ||
| 134 | std::cout << "Send error: " << strerror(errno) << "\n"; | ||
| 135 | } | ||
| 136 | outgoingSequenceNumber++; | ||
| 137 | |||
| 138 | quint64 statsCalcultionStart = usecTimestampNow(); | ||
| 139 | |||
| 90 | int gapDifferece = actualGap - gap; | 140 | int gapDifferece = actualGap - gap; |
| 141 | |||
| 91 | timeGaps.update(gapDifferece); | 142 | timeGaps.update(gapDifferece); |
| 143 | timeGapsPerReport.update(gapDifferece); | ||
| 144 | stDev.addValue(gapDifferece); | ||
| 145 | stDev30s.addValue(gapDifferece); | ||
| 146 | stDevReportInterval.addValue(gapDifferece); | ||
| 92 | last = now; | 147 | last = now; |
| 148 | |||
| 149 | // track out network time and stats calculation times | ||
| 150 | averageNetworkTime.updateAverage(networkElapsed); | ||
| 151 | |||
| 152 | // for our stats calculation time, we actually delay the updating by one sample. | ||
| 153 | // we do this so that the calculation of the average timing for the stats calculation | ||
| 154 | // happen inside of the calculation processing. This ensures that tracking stats on | ||
| 155 | // stats calculation doesn't side effect the remaining running time. | ||
| 156 | if (hasStatsCalculationTime) { | ||
| 157 | averageStatsCalcultionTime.updateAverage(lastStatsCalculationTime); | ||
| 158 | } | ||
| 93 | 159 | ||
| 94 | if (now - lastReport >= (report * MSEC_TO_USEC)) { | 160 | if (now - lastReport >= (report * MSEC_TO_USEC)) { |
| 95 | std::cout << "SEND gap Difference From Expected " | 161 | |
| 96 | << "min: " << timeGaps.getMin() << " usecs, " | 162 | std::cout << "\n" |
| 97 | << "max: " << timeGaps.getMax() << " usecs, " | 163 | << "SEND gap Difference From Expected\n" |
| 98 | << "avg: " << timeGaps.getAverage() << " usecs, " | 164 | << "Overall:\n" |
| 99 | << "min last 30: " << timeGaps.getWindowMin() << " usecs, " | 165 | << "min: " << timeGaps.getMin() << " usecs, " |
| 100 | << "max last 30: " << timeGaps.getWindowMax() << " usecs, " | 166 | << "max: " << timeGaps.getMax() << " usecs, " |
| 101 | << "avg last 30: " << timeGaps.getWindowAverage() << " usecs " | 167 | << "avg: " << timeGaps.getAverage() << " usecs, " |
| 102 | << "\n"; | 168 | << "stdev: " << stDev.getStDev() << " usecs\n" |
| 169 | << "Last 30s:\n" | ||
| 170 | << "min: " << timeGaps.getWindowMin() << " usecs, " | ||
| 171 | << "max: " << timeGaps.getWindowMax() << " usecs, " | ||
| 172 | << "avg: " << timeGaps.getWindowAverage() << " usecs, " | ||
| 173 | << "stdev: " << stDev30s.getStDev() << " usecs\n" | ||
| 174 | << "Last report interval:\n" | ||
| 175 | << "min: " << timeGapsPerReport.getWindowMin() << " usecs, " | ||
| 176 | << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " | ||
| 177 | << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, " | ||
| 178 | << "stdev: " << stDevReportInterval.getStDev() << " usecs\n" | ||
| 179 | << "Average Execution Times Last 30s:\n" | ||
| 180 | << " network: " << averageNetworkTime.getAverage() << " usecs average\n" | ||
| 181 | << " stats: " << averageStatsCalcultionTime.getAverage() << " usecs average" | ||
| 182 | << "\n"; | ||
| 183 | |||
| 184 | stDevReportInterval.reset(); | ||
| 185 | if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) { | ||
| 186 | stDev30s.reset(); | ||
| 187 | } | ||
| 188 | |||
| 103 | lastReport = now; | 189 | lastReport = now; |
| 104 | } | 190 | } |
| 191 | |||
| 192 | quint64 statsCalcultionEnd = usecTimestampNow(); | ||
| 193 | lastStatsCalculationTime = (float)(statsCalcultionEnd - statsCalcultionStart); | ||
| 194 | if (lastStatsCalculationTime > LARGE_STATS_TIME) { | ||
| 195 | qDebug() << "WARNING -- unexpectedly large lastStatsCalculationTime=" << lastStatsCalculationTime; | ||
| 196 | } | ||
| 197 | hasStatsCalculationTime = true; | ||
| 198 | |||
| 105 | } | 199 | } |
| 106 | } | 200 | } |
| 201 | delete[] outputBuffer; | ||
| 202 | |||
| 203 | #ifdef _WIN32 | ||
| 204 | WSACleanup(); | ||
| 205 | #endif | ||
| 107 | } | 206 | } |
| 108 | 207 | ||
| 109 | void runReceive(const char* addressOption, int port, int gap, int size, int report) { | 208 | void runReceive(const char* addressOption, int port, int gap, int size, int report) { |
| 110 | std::cout << "runReceive...\n"; | 209 | std::cout << "runReceive...\n"; |
| 111 | 210 | ||
| 211 | #ifdef _WIN32 | ||
| 212 | WSADATA wsaData; | ||
| 213 | if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0) { | ||
| 214 | printf("WSAStartup failed with error %d\n", WSAGetLastError()); | ||
| 215 | return; | ||
| 216 | } | ||
| 217 | #endif | ||
| 112 | 218 | ||
| 113 | int sockfd,n; | 219 | int sockfd, n; |
| 114 | struct sockaddr_in myaddr; | 220 | struct sockaddr_in myaddr; |
| 115 | 221 | ||
| 116 | char* inputBuffer = new char[size]; | 222 | sockfd = socket(AF_INET, SOCK_DGRAM, 0); |
| 117 | memset(inputBuffer, 0, size); | 223 | |
| 118 | |||
| 119 | sockfd=socket(AF_INET, SOCK_DGRAM, 0); | ||
| 120 | |||
| 121 | memset(&myaddr, 0, sizeof(myaddr)); | 224 | memset(&myaddr, 0, sizeof(myaddr)); |
| 122 | myaddr.sin_family = AF_INET; | 225 | myaddr.sin_family = AF_INET; |
| 123 | myaddr.sin_addr.s_addr=htonl(INADDR_ANY); | 226 | myaddr.sin_addr.s_addr = htonl(INADDR_ANY); |
| 124 | myaddr.sin_port=htons(port); | 227 | myaddr.sin_port = htons(port); |
| 125 | 228 | ||
| 126 | const int SAMPLES_FOR_30_SECONDS = 30 * 1000000 / gap; | ||
| 127 | 229 | ||
| 230 | const int SAMPLES_FOR_SECOND = 1000000 / gap; | ||
| 231 | std::cout << "SAMPLES_FOR_SECOND:" << SAMPLES_FOR_SECOND << "\n"; | ||
| 232 | const int INTERVALS_PER_30_SECONDS = 30; | ||
| 233 | std::cout << "INTERVALS_PER_30_SECONDS:" << INTERVALS_PER_30_SECONDS << "\n"; | ||
| 234 | const int SAMPLES_FOR_30_SECONDS = 30 * SAMPLES_FOR_SECOND; | ||
| 128 | std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; | 235 | std::cout << "SAMPLES_FOR_30_SECONDS:" << SAMPLES_FOR_30_SECONDS << "\n"; |
| 236 | const int REPORTS_FOR_30_SECONDS = 30 * MSECS_PER_SECOND / report; | ||
| 237 | std::cout << "REPORTS_FOR_30_SECONDS:" << REPORTS_FOR_30_SECONDS << "\n"; | ||
| 238 | |||
| 239 | int intervalsPerReport = report / MSEC_TO_USEC; | ||
| 240 | if (intervalsPerReport < 1) { | ||
| 241 | intervalsPerReport = 1; | ||
| 242 | } | ||
| 243 | std::cout << "intervalsPerReport:" << intervalsPerReport << "\n"; | ||
| 244 | MovingMinMaxAvg<int> timeGaps(SAMPLES_FOR_SECOND, INTERVALS_PER_30_SECONDS); | ||
| 245 | MovingMinMaxAvg<int> timeGapsPerReport(SAMPLES_FOR_SECOND, intervalsPerReport); | ||
| 246 | |||
| 247 | char* inputBuffer = new char[size]; | ||
| 248 | memset(inputBuffer, 0, size); | ||
| 249 | |||
| 250 | |||
| 251 | SequenceNumberStats seqStats(REPORTS_FOR_30_SECONDS); | ||
| 252 | |||
| 253 | StDev stDevReportInterval; | ||
| 254 | StDev stDev30s; | ||
| 255 | StDev stDev; | ||
| 256 | |||
| 257 | SimpleMovingAverage averageNetworkTime(SAMPLES_FOR_30_SECONDS); | ||
| 258 | SimpleMovingAverage averageStatsCalcultionTime(SAMPLES_FOR_30_SECONDS); | ||
| 259 | float lastStatsCalculationTime = 0.0f; // we add out stats calculation time in the next calculation window | ||
| 260 | bool hasStatsCalculationTime = false; | ||
| 129 | 261 | ||
| 130 | MovingMinMaxAvg<int> timeGaps(1, SAMPLES_FOR_30_SECONDS); // stats | ||
| 131 | |||
| 132 | if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { | 262 | if (bind(sockfd, (struct sockaddr *)&myaddr, sizeof(myaddr)) < 0) { |
| 133 | std::cout << "bind failed\n"; | 263 | std::cout << "bind failed\n"; |
| 134 | return; | 264 | return; |
| 135 | } | 265 | } |
| 136 | 266 | ||
| 137 | quint64 last = 0; // first case | 267 | quint64 last = 0; // first case |
| 138 | quint64 lastReport = 0; | 268 | quint64 lastReport = 0; |
| 139 | 269 | ||
| 140 | while (true) { | 270 | while (true) { |
| 271 | |||
| 272 | quint64 networkStart = usecTimestampNow(); | ||
| 141 | n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from | 273 | n = recvfrom(sockfd, inputBuffer, size, 0, NULL, NULL); // we don't care about where it came from |
| 142 | 274 | quint64 networkEnd = usecTimestampNow(); | |
| 275 | float networkElapsed = (float)(networkEnd - networkStart); | ||
| 276 | |||
| 277 | if (n < 0) { | ||
| 278 | std::cout << "Receive error: " << strerror(errno) << "\n"; | ||
| 279 | } | ||
| 280 | |||
| 281 | // parse seq num | ||
| 282 | quint16 incomingSequenceNumber = *(reinterpret_cast<quint16*>(inputBuffer)); | ||
| 283 | seqStats.sequenceNumberReceived(incomingSequenceNumber); | ||
| 284 | |||
| 143 | if (last == 0) { | 285 | if (last == 0) { |
| 144 | last = usecTimestampNow(); | 286 | last = usecTimestampNow(); |
| 145 | std::cout << "first packet received\n"; | 287 | std::cout << "first packet received\n"; |
| 146 | } else { | 288 | } else { |
| 289 | |||
| 290 | quint64 statsCalcultionStart = usecTimestampNow(); | ||
| 147 | quint64 now = usecTimestampNow(); | 291 | quint64 now = usecTimestampNow(); |
| 148 | int actualGap = now - last; | 292 | int actualGap = now - last; |
| 293 | |||
| 149 | int gapDifferece = actualGap - gap; | 294 | int gapDifferece = actualGap - gap; |
| 150 | timeGaps.update(gapDifferece); | 295 | timeGaps.update(gapDifferece); |
| 296 | timeGapsPerReport.update(gapDifferece); | ||
| 297 | stDev.addValue(gapDifferece); | ||
| 298 | stDev30s.addValue(gapDifferece); | ||
| 299 | stDevReportInterval.addValue(gapDifferece); | ||
| 151 | last = now; | 300 | last = now; |
| 152 | 301 | ||
| 302 | // track out network time and stats calculation times | ||
| 303 | averageNetworkTime.updateAverage(networkElapsed); | ||
| 304 | |||
| 305 | // for our stats calculation time, we actually delay the updating by one sample. | ||
| 306 | // we do this so that the calculation of the average timing for the stats calculation | ||
| 307 | // happen inside of the calculation processing. This ensures that tracking stats on | ||
| 308 | // stats calculation doesn't side effect the remaining running time. | ||
| 309 | if (hasStatsCalculationTime) { | ||
| 310 | averageStatsCalcultionTime.updateAverage(lastStatsCalculationTime); | ||
| 311 | } | ||
| 312 | |||
| 153 | if (now - lastReport >= (report * MSEC_TO_USEC)) { | 313 | if (now - lastReport >= (report * MSEC_TO_USEC)) { |
| 154 | std::cout << "RECEIVE gap Difference From Expected " | 314 | |
| 155 | << "min: " << timeGaps.getMin() << " usecs, " | 315 | seqStats.pushStatsToHistory(); |
| 156 | << "max: " << timeGaps.getMax() << " usecs, " | 316 | |
| 157 | << "avg: " << timeGaps.getAverage() << " usecs, " | 317 | std::cout << "RECEIVE gap Difference From Expected\n" |
| 158 | << "min last 30: " << timeGaps.getWindowMin() << " usecs, " | 318 | << "Overall:\n" |
| 159 | << "max last 30: " << timeGaps.getWindowMax() << " usecs, " | 319 | << "min: " << timeGaps.getMin() << " usecs, " |
| 160 | << "avg last 30: " << timeGaps.getWindowAverage() << " usecs " | 320 | << "max: " << timeGaps.getMax() << " usecs, " |
| 161 | << "\n"; | 321 | << "avg: " << timeGaps.getAverage() << " usecs, " |
| 322 | << "stdev: " << stDev.getStDev() << " usecs\n" | ||
| 323 | << "Last 30s:\n" | ||
| 324 | << "min: " << timeGaps.getWindowMin() << " usecs, " | ||
| 325 | << "max: " << timeGaps.getWindowMax() << " usecs, " | ||
| 326 | << "avg: " << timeGaps.getWindowAverage() << " usecs, " | ||
| 327 | << "stdev: " << stDev30s.getStDev() << " usecs\n" | ||
| 328 | << "Last report interval:\n" | ||
| 329 | << "min: " << timeGapsPerReport.getWindowMin() << " usecs, " | ||
| 330 | << "max: " << timeGapsPerReport.getWindowMax() << " usecs, " | ||
| 331 | << "avg: " << timeGapsPerReport.getWindowAverage() << " usecs, " | ||
| 332 | << "stdev: " << stDevReportInterval.getStDev() << " usecs\n" | ||
| 333 | << "Average Execution Times Last 30s:\n" | ||
| 334 | << " network: " << averageNetworkTime.getAverage() << " usecs average\n" | ||
| 335 | << " stats: " << averageStatsCalcultionTime.getAverage() << " usecs average" | ||
| 336 | << "\n"; | ||
| 337 | stDevReportInterval.reset(); | ||
| 338 | |||
| 339 | if (stDev30s.getSamples() > SAMPLES_FOR_30_SECONDS) { | ||
| 340 | stDev30s.reset(); | ||
| 341 | } | ||
| 342 | |||
| 343 | PacketStreamStats packetStatsLast30s = seqStats.getStatsForHistoryWindow(); | ||
| 344 | PacketStreamStats packetStatsLastReportInterval = seqStats.getStatsForLastHistoryInterval(); | ||
| 345 | |||
| 346 | std::cout << "RECEIVE Packet Stats\n" | ||
| 347 | << "Overall:\n" | ||
| 348 | << "lost: " << seqStats.getLost() << ", " | ||
| 349 | << "lost %: " << seqStats.getStats().getLostRate() * 100.0f << "%\n" | ||
| 350 | << "Last 30s:\n" | ||
| 351 | << "lost: " << packetStatsLast30s._lost << ", " | ||
| 352 | << "lost %: " << packetStatsLast30s.getLostRate() * 100.0f << "%\n" | ||
| 353 | << "Last report interval:\n" | ||
| 354 | << "lost: " << packetStatsLastReportInterval._lost << ", " | ||
| 355 | << "lost %: " << packetStatsLastReportInterval.getLostRate() * 100.0f << "%\n" | ||
| 356 | << "\n\n"; | ||
| 357 | |||
| 162 | lastReport = now; | 358 | lastReport = now; |
| 163 | } | 359 | } |
| 360 | |||
| 361 | quint64 statsCalcultionEnd = usecTimestampNow(); | ||
| 362 | |||
| 363 | lastStatsCalculationTime = (float)(statsCalcultionEnd - statsCalcultionStart); | ||
| 364 | if (lastStatsCalculationTime > LARGE_STATS_TIME) { | ||
| 365 | qDebug() << "WARNING -- unexpectedly large lastStatsCalculationTime=" << lastStatsCalculationTime; | ||
| 366 | } | ||
| 367 | hasStatsCalculationTime = true; | ||
| 164 | } | 368 | } |
| 165 | } | 369 | } |
| 166 | } | 370 | delete[] inputBuffer; |
| 167 | 371 | ||
| 372 | #ifdef _WIN32 | ||
| 373 | WSACleanup(); | ||
| 374 | #endif | ||
| 375 | } | ||
| @@ -1,32 +1,12 @@ | |||
| 1 | set(TARGET_NAME metavoxel-tests) | 1 | set(TARGET_NAME metavoxel-tests) |
| 2 | 2 | ||
| 3 | set(ROOT_DIR ../..) | 3 | auto_mtc() |
| 4 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 5 | 4 | ||
| 6 | # setup for find modules | 5 | include_glm() |
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 8 | 6 | ||
| 9 | find_package(Qt5 COMPONENTS Network Script Widgets) | 7 | setup_hifi_project(Network Script Widgets) |
| 10 | |||
| 11 | include(${MACRO_DIR}/AutoMTC.cmake) | ||
| 12 | auto_mtc(${TARGET_NAME} "${ROOT_DIR}") | ||
| 13 | |||
| 14 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 15 | setup_hifi_project(${TARGET_NAME} TRUE "${AUTOMTC_SRC}") | ||
| 16 | |||
| 17 | #include glm | ||
| 18 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 19 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 20 | 8 | ||
| 21 | # link in the shared libraries | 9 | # link in the shared libraries |
| 22 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 10 | link_hifi_libraries(metavoxels networking shared) |
| 23 | link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 24 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 25 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 26 | |||
| 27 | IF (WIN32) | ||
| 28 | target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 29 | ENDIF(WIN32) | ||
| 30 | |||
| 31 | target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) | ||
| 32 | 11 | ||
| 12 | link_shared_dependencies() | ||
| @@ -1,33 +1,8 @@ | |||
| 1 | set(TARGET_NAME networking-tests) | 1 | set(TARGET_NAME networking-tests) |
| 2 | 2 | ||
| 3 | set(ROOT_DIR ../..) | 3 | setup_hifi_project() |
| 4 | set(MACRO_DIR ${ROOT_DIR}/cmake/macros) | ||
| 5 | |||
| 6 | # setup for find modules | ||
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 8 | |||
| 9 | #find_package(Qt5Network REQUIRED) | ||
| 10 | #find_package(Qt5Script REQUIRED) | ||
| 11 | #find_package(Qt5Widgets REQUIRED) | ||
| 12 | |||
| 13 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 14 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 15 | |||
| 16 | include(${MACRO_DIR}/AutoMTC.cmake) | ||
| 17 | auto_mtc(${TARGET_NAME} ${ROOT_DIR}) | ||
| 18 | |||
| 19 | #qt5_use_modules(${TARGET_NAME} Network Script Widgets) | ||
| 20 | |||
| 21 | #include glm | ||
| 22 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 23 | include_glm(${TARGET_NAME} ${ROOT_DIR}) | ||
| 24 | 4 | ||
| 25 | # link in the shared libraries | 5 | # link in the shared libraries |
| 26 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 6 | link_hifi_libraries(shared networking) |
| 27 | link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) | ||
| 28 | link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) | ||
| 29 | |||
| 30 | IF (WIN32) | ||
| 31 | target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 32 | ENDIF(WIN32) | ||
| 33 | 7 | ||
| 8 | link_shared_dependencies() | ||
| @@ -9,11 +9,12 @@ · 8 unmodified lines | |||
| 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html | 9 | // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html |
| 10 | // | 10 | // |
| 11 | 11 | ||
| 12 | #include "SequenceNumberStatsTests.h" | 12 | #include <cassert> |
| 13 | |||
| 14 | #include "SharedUtil.h" | ||
| 15 | #include <limits> | 13 | #include <limits> |
| 16 | 14 | ||
| 15 | #include <SharedUtil.h> | ||
| 16 | |||
| 17 | #include "SequenceNumberStatsTests.h" | ||
| 17 | 18 | ||
| 18 | void SequenceNumberStatsTests::runAllTests() { | 19 | void SequenceNumberStatsTests::runAllTests() { |
| 19 | rolloverTest(); | 20 | rolloverTest(); |
| @@ -1,44 +1,19 @@ | |||
| 1 | set(TARGET_NAME octree-tests) | 1 | set(TARGET_NAME octree-tests) |
| 2 | 2 | ||
| 3 | set(ROOT_DIR ../..) | 3 | setup_hifi_project(Script Network) |
| 4 | set(MACRO_DIR ${ROOT_DIR}/cmake/macros) | ||
| 5 | 4 | ||
| 6 | # setup for find modules | 5 | include_glm() |
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 8 | |||
| 9 | find_package(Qt5Network REQUIRED) | ||
| 10 | find_package(Qt5Script REQUIRED) | ||
| 11 | find_package(Qt5Widgets REQUIRED) | ||
| 12 | |||
| 13 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 14 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 15 | |||
| 16 | include(${MACRO_DIR}/AutoMTC.cmake) | ||
| 17 | auto_mtc(${TARGET_NAME} ${ROOT_DIR}) | ||
| 18 | |||
| 19 | qt5_use_modules(${TARGET_NAME} Network Script Widgets) | ||
| 20 | |||
| 21 | #include glm | ||
| 22 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 23 | include_glm(${TARGET_NAME} ${ROOT_DIR}) | ||
| 24 | 6 | ||
| 25 | # link in the shared libraries | 7 | # link in the shared libraries |
| 26 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 8 | //link_hifi_library(entities ${TARGET_NAME} ${ROOT_DIR}) |
| 27 | link_hifi_library(entities ${TARGET_NAME} ${ROOT_DIR}) | 9 | //link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) |
| 28 | link_hifi_library(octree ${TARGET_NAME} ${ROOT_DIR}) | 10 | //link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) |
| 29 | link_hifi_library(audio ${TARGET_NAME} ${ROOT_DIR}) | 11 | //link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) |
| 30 | link_hifi_library(networking ${TARGET_NAME} ${ROOT_DIR}) | 12 | //link_hifi_library(animation ${TARGET_NAME} ${ROOT_DIR}) |
| 31 | link_hifi_library(animation ${TARGET_NAME} ${ROOT_DIR}) | 13 | //link_hifi_library(fbx ${TARGET_NAME} ${ROOT_DIR}) |
| 32 | link_hifi_library(fbx ${TARGET_NAME} ${ROOT_DIR}) | 14 | //link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) |
| 33 | link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) | 15 | //link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) |
| 34 | link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) | 16 | |
| 35 | 17 | link_hifi_libraries(animation fbx entities networking octree shared) | |
| 36 | IF (WIN32) | 18 | |
| 37 | # add a definition for ssize_t so that windows doesn't bail | 19 | link_shared_dependencies() |
| 38 | add_definitions(-Dssize_t=long) | ||
| 39 | |||
| 40 | #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 41 | target_link_libraries(${TARGET_NAME} wsock32.lib) | ||
| 42 | ENDIF(WIN32) | ||
| 43 | |||
| 44 | |||
| @@ -1,32 +1,10 @@ | |||
| 1 | set(TARGET_NAME physics-tests) | 1 | set(TARGET_NAME physics-tests) |
| 2 | 2 | ||
| 3 | set(ROOT_DIR ../..) | 3 | setup_hifi_project() |
| 4 | set(MACRO_DIR ${ROOT_DIR}/cmake/macros) | ||
| 5 | 4 | ||
| 6 | # setup for find modules | 5 | include_glm() |
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 8 | |||
| 9 | #find_package(Qt5Network REQUIRED) | ||
| 10 | #find_package(Qt5Script REQUIRED) | ||
| 11 | #find_package(Qt5Widgets REQUIRED) | ||
| 12 | |||
| 13 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 14 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 15 | |||
| 16 | include(${MACRO_DIR}/AutoMTC.cmake) | ||
| 17 | auto_mtc(${TARGET_NAME} ${ROOT_DIR}) | ||
| 18 | |||
| 19 | #qt5_use_modules(${TARGET_NAME} Network Script Widgets) | ||
| 20 | |||
| 21 | #include glm | ||
| 22 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 23 | include_glm(${TARGET_NAME} ${ROOT_DIR}) | ||
| 24 | 6 | ||
| 25 | # link in the shared libraries | 7 | # link in the shared libraries |
| 26 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 8 | link_hifi_libraries(shared) |
| 27 | link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) | ||
| 28 | |||
| 29 | IF (WIN32) | ||
| 30 | #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 31 | ENDIF(WIN32) | ||
| 32 | 9 | ||
| 10 | link_shared_dependencies() | ||
| @@ -1,32 +1,10 @@ | |||
| 1 | set(TARGET_NAME shared-tests) | 1 | set(TARGET_NAME shared-tests) |
| 2 | 2 | ||
| 3 | set(ROOT_DIR ../..) | 3 | setup_hifi_project() |
| 4 | set(MACRO_DIR ${ROOT_DIR}/cmake/macros) | ||
| 5 | 4 | ||
| 6 | # setup for find modules | 5 | include_glm() |
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 8 | |||
| 9 | #find_package(Qt5Network REQUIRED) | ||
| 10 | #find_package(Qt5Script REQUIRED) | ||
| 11 | #find_package(Qt5Widgets REQUIRED) | ||
| 12 | |||
| 13 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 14 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 15 | |||
| 16 | include(${MACRO_DIR}/AutoMTC.cmake) | ||
| 17 | auto_mtc(${TARGET_NAME} ${ROOT_DIR}) | ||
| 18 | |||
| 19 | #qt5_use_modules(${TARGET_NAME} Network Script Widgets) | ||
| 20 | |||
| 21 | #include glm | ||
| 22 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 23 | include_glm(${TARGET_NAME} ${ROOT_DIR}) | ||
| 24 | 6 | ||
| 25 | # link in the shared libraries | 7 | # link in the shared libraries |
| 26 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | 8 | link_hifi_libraries(shared) |
| 27 | link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) | ||
| 28 | |||
| 29 | IF (WIN32) | ||
| 30 | #target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 31 | ENDIF(WIN32) | ||
| 32 | 9 | ||
| 10 | link_shared_dependencies() | ||
| @@ -1,4 +1,3 @@ | |||
| 1 | |||
| 2 | # add the tool directories | 1 | # add the tool directories |
| 3 | add_subdirectory(bitstream2json) | 2 | add_subdirectory(bitstream2json) |
| 4 | add_subdirectory(json2bitstream) | 3 | add_subdirectory(json2bitstream) |
| @@ -1,25 +1,8 @@ | |||
| 1 | set(TARGET_NAME bitstream2json) | 1 | set(TARGET_NAME bitstream2json) |
| 2 | setup_hifi_project(Widgets Script) | ||
| 2 | 3 | ||
| 3 | set(ROOT_DIR ../..) | 4 | include_glm() |
| 4 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 5 | 5 | ||
| 6 | # setup for find modules | 6 | link_hifi_libraries(metavoxels) |
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 8 | 7 | ||
| 9 | find_package(Qt5 COMPONENTS Network Script Widgets) | 8 | link_shared_dependencies() |
| 10 | |||
| 11 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 12 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 13 | |||
| 14 | link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 15 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 16 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 17 | |||
| 18 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 19 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 20 | |||
| 21 | IF (WIN32) | ||
| 22 | target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 23 | ENDIF(WIN32) | ||
| 24 | |||
| 25 | target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) | ||
| @@ -1,25 +1,8 @@ | |||
| 1 | set(TARGET_NAME json2bitstream) | 1 | set(TARGET_NAME json2bitstream) |
| 2 | setup_hifi_project(Widgets Script) | ||
| 2 | 3 | ||
| 3 | set(ROOT_DIR ../..) | 4 | include_glm() |
| 4 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 5 | 5 | ||
| 6 | # setup for find modules | 6 | link_hifi_libraries(metavoxels) |
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake/modules/") | ||
| 8 | 7 | ||
| 9 | find_package(Qt5 COMPONENTS Network Script Widgets) | 8 | link_shared_dependencies() |
| 10 | |||
| 11 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 12 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 13 | |||
| 14 | link_hifi_library(metavoxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 15 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 16 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 17 | |||
| 18 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 19 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 20 | |||
| 21 | IF (WIN32) | ||
| 22 | target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 23 | ENDIF(WIN32) | ||
| 24 | |||
| 25 | target_link_libraries(${TARGET_NAME} Qt5::Network Qt5::Widgets Qt5::Script) | ||
| @@ -1,7 +1,4 @@ | |||
| 1 | set(TARGET_NAME mtc) | 1 | set(TARGET_NAME mtc) |
| 2 | setup_hifi_project() | ||
| 2 | 3 | ||
| 3 | set(ROOT_DIR ../..) | 4 | link_shared_dependencies() |
| 4 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 5 | |||
| 6 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 7 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| @@ -1,40 +1,9 @@ | |||
| 1 | set(TARGET_NAME voxel-edit) | 1 | set(TARGET_NAME voxel-edit) |
| 2 | 2 | ||
| 3 | set(ROOT_DIR ..) | 3 | setup_hifi_project() |
| 4 | set(MACRO_DIR "${ROOT_DIR}/cmake/macros") | ||
| 5 | 4 | ||
| 6 | # setup for find modules | 5 | include_glm() |
| 7 | set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake/modules/") | ||
| 8 | 6 | ||
| 9 | # set up the external glm library | 7 | link_hifi_libraries(networking octree shared voxels) |
| 10 | include(${MACRO_DIR}/IncludeGLM.cmake) | ||
| 11 | include_glm(${TARGET_NAME} "${ROOT_DIR}") | ||
| 12 | 8 | ||
| 13 | find_package(Qt5Script REQUIRED) | 9 | link_shared_dependencies() |
| 14 | |||
| 15 | include(${MACRO_DIR}/SetupHifiProject.cmake) | ||
| 16 | setup_hifi_project(${TARGET_NAME} TRUE) | ||
| 17 | |||
| 18 | # link in the shared library | ||
| 19 | include(${MACRO_DIR}/LinkHifiLibrary.cmake) | ||
| 20 | link_hifi_library(shared ${TARGET_NAME} "${ROOT_DIR}") | ||
| 21 | |||
| 22 | # link in the hifi octree library | ||
| 23 | link_hifi_library(octree ${TARGET_NAME} "${ROOT_DIR}") | ||
| 24 | |||
| 25 | # link in the hifi voxels library | ||
| 26 | link_hifi_library(voxels ${TARGET_NAME} "${ROOT_DIR}") | ||
| 27 | |||
| 28 | # link in the hifi networking library | ||
| 29 | link_hifi_library(networking ${TARGET_NAME} "${ROOT_DIR}") | ||
| 30 | |||
| 31 | IF (WIN32) | ||
| 32 | target_link_libraries(${TARGET_NAME} Winmm Ws2_32) | ||
| 33 | ENDIF(WIN32) | ||
| 34 | |||
| 35 | target_link_libraries(${TARGET_NAME} Qt5::Script) | ||
| 36 | |||
| 37 | # add a definition for ssize_t so that windows doesn't bail | ||
| 38 | if (WIN32) | ||
| 39 | add_definitions(-Dssize_t=long) | ||
| 40 | endif () | ||