diff --git a/animation-server/CMakeLists.txt b/animation-server/CMakeLists.txt index e9662366af..de04acd8f7 100644 --- a/animation-server/CMakeLists.txt +++ b/animation-server/CMakeLists.txt @@ -14,7 +14,7 @@ include_glm(${TARGET_NAME} ${ROOT_DIR}) include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} TRUE) # link in the shared library include(${MACRO_DIR}/LinkHifiLibrary.cmake) diff --git a/audio-mixer/CMakeLists.txt b/audio-mixer/CMakeLists.txt index 7e83e6fc1a..472327de42 100644 --- a/audio-mixer/CMakeLists.txt +++ b/audio-mixer/CMakeLists.txt @@ -9,7 +9,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake set(TARGET_NAME audio-mixer) include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} TRUE) # set up the external glm library include(${MACRO_DIR}/IncludeGLM.cmake) diff --git a/avatar-mixer/CMakeLists.txt b/avatar-mixer/CMakeLists.txt index da25b6e981..33f603e228 100644 --- a/avatar-mixer/CMakeLists.txt +++ b/avatar-mixer/CMakeLists.txt @@ -10,7 +10,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake # setup the project include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} TRUE) # include glm include(${MACRO_DIR}/IncludeGLM.cmake) diff --git a/cmake/macros/SetupHifiLibrary.cmake b/cmake/macros/SetupHifiLibrary.cmake index 156ca186b2..b7d0af7499 100644 --- a/cmake/macros/SetupHifiLibrary.cmake +++ b/cmake/macros/SetupHifiLibrary.cmake @@ -1,9 +1,15 @@ MACRO(SETUP_HIFI_LIBRARY TARGET) - project(${TARGET_NAME}) + project(${TARGET}) # grab the implemenation and header files file(GLOB LIB_SRCS src/*.h src/*.cpp) # create a library and set the property so it can be referenced later - add_library(${TARGET_NAME} ${LIB_SRCS}) + add_library(${TARGET} ${LIB_SRCS}) + + find_package(Qt4 REQUIRED QtCore) + include(${QT_USE_FILE}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}") + + target_link_libraries(${TARGET} ${QT_LIBRARIES}) ENDMACRO(SETUP_HIFI_LIBRARY _target) \ No newline at end of file diff --git a/cmake/macros/SetupHifiProject.cmake b/cmake/macros/SetupHifiProject.cmake index 3b6f130073..8360dc66b6 100644 --- a/cmake/macros/SetupHifiProject.cmake +++ b/cmake/macros/SetupHifiProject.cmake @@ -1,4 +1,4 @@ -MACRO(SETUP_HIFI_PROJECT TARGET) +MACRO(SETUP_HIFI_PROJECT TARGET INCLUDE_QT) project(${TARGET}) # grab the implemenation and header files @@ -6,4 +6,12 @@ MACRO(SETUP_HIFI_PROJECT TARGET) # add the executable add_executable(${TARGET} ${TARGET_SRCS}) -ENDMACRO(SETUP_HIFI_PROJECT _target) \ No newline at end of file + + IF (${INCLUDE_QT}) + find_package(Qt4 REQUIRED QtCore) + include(${QT_USE_FILE}) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}") + ENDIF() + + target_link_libraries(${TARGET} ${QT_LIBRARIES}) +ENDMACRO(SETUP_HIFI_PROJECT _target _include_qt) \ No newline at end of file diff --git a/domain-server/CMakeLists.txt b/domain-server/CMakeLists.txt index 27863f01df..4e1f0de298 100644 --- a/domain-server/CMakeLists.txt +++ b/domain-server/CMakeLists.txt @@ -6,7 +6,7 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros) set(TARGET_NAME domain-server) include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} TRUE) # link the shared hifi library include(${MACRO_DIR}/LinkHifiLibrary.cmake) diff --git a/eve/CMakeLists.txt b/eve/CMakeLists.txt index acca9520ed..0a7691b781 100644 --- a/eve/CMakeLists.txt +++ b/eve/CMakeLists.txt @@ -9,7 +9,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake set(TARGET_NAME eve) include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} TRUE) include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} ${ROOT_DIR}) diff --git a/injector/CMakeLists.txt b/injector/CMakeLists.txt index 2c022b0e92..ae9ed3d8ad 100644 --- a/injector/CMakeLists.txt +++ b/injector/CMakeLists.txt @@ -9,7 +9,7 @@ set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../cmake set(TARGET_NAME injector) include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} TRUE) # set up the external glm library include(${MACRO_DIR}/IncludeGLM.cmake) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e0ca3b66dd..bb717e7f9e 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -70,10 +70,10 @@ using namespace std; // Starfield information -static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; +static char STAR_FILE[] = "http://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; static char STAR_CACHE_FILE[] = "cachedStars.txt"; -static const bool TESTING_PARTICLE_SYSTEM = false; +static const bool TESTING_PARTICLE_SYSTEM = true; static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored @@ -164,6 +164,11 @@ void GLCanvas::wheelEvent(QWheelEvent* event) { Application::getInstance()->wheelEvent(event); } +void messageHandler(QtMsgType type, const char* message) { + fprintf(stdout, "%s", message); + LogDisplay::instance.addMessage(message); +} + Application::Application(int& argc, char** argv, timeval &startup_time) : QApplication(argc, argv), _window(new QMainWindow(desktop())), @@ -173,6 +178,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _frameCount(0), _fps(120.0f), _justStarted(true), + _particleSystemInitialized(false), + _coolDemoParticleEmitter(-1), _wantToKillLocalVoxels(false), _frustumDrawingMode(FRUSTUM_DRAW_MODE_ALL), _viewFrustumOffsetYaw(-135.0), @@ -188,6 +195,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _isTouchPressed(false), _yawFromTouch(0.0f), _pitchFromTouch(0.0f), + _groundPlaneImpact(0.0f), _mousePressed(false), _mouseVoxelScale(1.0f / 1024.0f), _justEditedVoxel(false), @@ -210,7 +218,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : { _applicationStartupTime = startup_time; _window->setWindowTitle("Interface"); - printLog("Interface Startup:\n"); + + qInstallMsgHandler(messageHandler); unsigned int listenPort = 0; // bind to an ephemeral port by default const char** constArgv = const_cast(argv); @@ -233,7 +242,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : // Handle Local Domain testing with the --local command line if (cmdOptionExists(argc, constArgv, "--local")) { - printLog("Local Domain MODE!\n"); + qDebug("Local Domain MODE!\n"); NodeList::getInstance()->setDomainIPToLocalhost(); } @@ -297,7 +306,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : } void Application::initializeGL() { - printLog( "Created Display Window.\n" ); + qDebug( "Created Display Window.\n" ); // initialize glut for shape drawing; Qt apparently initializes it on OS X #ifndef __APPLE__ @@ -312,10 +321,10 @@ void Application::initializeGL() { _viewFrustumOffsetCamera.setFarClip(500.0 * TREE_SCALE); initDisplay(); - printLog( "Initialized Display.\n" ); + qDebug( "Initialized Display.\n" ); init(); - printLog( "Init() complete.\n" ); + qDebug( "Init() complete.\n" ); // Check to see if the user passed in a command line option for randomizing colors bool wantColorRandomizer = !arguments().contains("--NoColorRandomizer"); @@ -324,13 +333,13 @@ void Application::initializeGL() { // Voxel File. If so, load it now. if (!_voxelsFilename.isEmpty()) { _voxels.loadVoxelsFile(_voxelsFilename.constData(), wantColorRandomizer); - printLog("Local Voxel File loaded.\n"); + qDebug("Local Voxel File loaded.\n"); } // create thread for receipt of data via UDP if (_enableNetworkThread) { pthread_create(&_networkReceiveThread, NULL, networkReceive, NULL); - printLog("Network receive thread created.\n"); + qDebug("Network receive thread created.\n"); } // call terminate before exiting @@ -352,7 +361,7 @@ void Application::initializeGL() { _justStarted = false; char title[50]; sprintf(title, "Interface: %4.2f seconds\n", startupTime); - printLog("%s", title); + qDebug("%s", title); _window->setWindowTitle(title); const char LOGSTASH_INTERFACE_START_TIME_KEY[] = "interface-start-time"; @@ -1177,25 +1186,20 @@ void Application::editPreferences() { return; } - - const char* newHostname = domainServerHostname->text().toLocal8Bit().data(); - + char newHostname[MAX_HOSTNAME_BYTES] = {}; + memcpy(newHostname, domainServerHostname->text().toAscii().data(), domainServerHostname->text().size()); + // check if the domain server hostname is new - if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname, sizeof(&newHostname)) != 0) { - // if so we need to clear the nodelist and delete the local voxels - Node *voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); - - if (voxelServer) { - voxelServer->lock(); - } - - _voxels.killLocalVoxels(); - - if (voxelServer) { - voxelServer->unlock(); - } + if (memcmp(NodeList::getInstance()->getDomainHostname(), newHostname, strlen(newHostname)) != 0) { NodeList::getInstance()->clear(); + + // kill the local voxels + _voxels.killLocalVoxels(); + + // reset the environment to default + _environment.resetToDefault(); + NodeList::getInstance()->setDomainHostname(newHostname); } @@ -1456,12 +1460,12 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { uint64_t elapsed = now - args->lastSendTime; int usecToSleep = CLIENT_TO_SERVER_VOXEL_SEND_INTERVAL_USECS - elapsed; if (usecToSleep > 0) { - printLog("sendVoxelsOperation: packet: %d bytes:%ld elapsed %ld usecs, sleeping for %d usecs!\n", - args->packetsSent, args->bytesSent, elapsed, usecToSleep); + qDebug("sendVoxelsOperation: packet: %d bytes:%lld elapsed %lld usecs, sleeping for %d usecs!\n", + args->packetsSent, args->bytesSent, elapsed, usecToSleep); usleep(usecToSleep); } else { - printLog("sendVoxelsOperation: packet: %d bytes:%ld elapsed %ld usecs, no need to sleep!\n", - args->packetsSent, args->bytesSent, elapsed); + qDebug("sendVoxelsOperation: packet: %d bytes:%lld elapsed %lld usecs, no need to sleep!\n", + args->packetsSent, args->bytesSent, elapsed); } args->lastSendTime = now; } @@ -1505,7 +1509,7 @@ void Application::importVoxelsToClipboard() { if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) { QImage pngImage = QImage(fileName); if (pngImage.height() != pngImage.width()) { - printLog("ERROR: Bad PNG size: height != width.\n"); + qDebug("ERROR: Bad PNG size: height != width.\n"); return; } @@ -1539,7 +1543,7 @@ void Application::importVoxels() { if (fileNameString.endsWith(".png", Qt::CaseInsensitive)) { QImage pngImage = QImage(fileName); if (pngImage.height() != pngImage.width()) { - printLog("ERROR: Bad PNG size: height != width.\n"); + qDebug("ERROR: Bad PNG size: height != width.\n"); return; } @@ -1644,9 +1648,9 @@ void Application::pasteVoxels() { // If we have voxels left in the packet, then send the packet if (args.bufferInUse > (numBytesPacketHeader + sizeof(unsigned short int))) { controlledBroadcastToNodes(args.messageBuffer, args.bufferInUse, & NODE_TYPE_VOXEL_SERVER, 1); - printLog("sending packet: %d\n", ++args.packetsSent); + qDebug("sending packet: %d\n", ++args.packetsSent); args.bytesSent += args.bufferInUse; - printLog("total bytes sent: %ld\n", args.bytesSent); + qDebug("total bytes sent: %lld\n", args.bytesSent); } if (calculatedOctCode) { @@ -1713,8 +1717,8 @@ void Application::initMenu() { "First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P))->setCheckable(true); (_manualThirdPerson = renderMenu->addAction( "Third Person", this, SLOT(setRenderThirdPerson(bool))))->setCheckable(true); - renderMenu->addAction("Increase Avatar Size", this, SLOT(increaseAvatarSize()), Qt::SHIFT | Qt::Key_Plus); - renderMenu->addAction("Decrease Avatar Size", this, SLOT(decreaseAvatarSize()), Qt::SHIFT | Qt::Key_Minus); + renderMenu->addAction("Increase Avatar Size", this, SLOT(increaseAvatarSize()), Qt::ALT | Qt::Key_Plus); + renderMenu->addAction("Decrease Avatar Size", this, SLOT(decreaseAvatarSize()), Qt::ALT | Qt::Key_Minus); QMenu* toolsMenu = menuBar->addMenu("Tools"); @@ -1894,7 +1898,7 @@ void Application::init() { _audio.setJitterBufferSamples(_audioJitterBufferSamples); } - printLog("Loaded settings.\n"); + qDebug("Loaded settings.\n"); sendAvatarVoxelURLMessage(_myAvatar.getVoxels()->getVoxelURL()); @@ -1904,9 +1908,10 @@ void Application::init() { _palette.addTool(&_swatch); _palette.addAction(_colorVoxelMode, 0, 2); _palette.addAction(_eyedropperMode, 0, 3); - _palette.addAction(_selectVoxelMode, 0, 4); + _palette.addAction(_selectVoxelMode, 0, 4); } + const float MAX_AVATAR_EDIT_VELOCITY = 1.0f; const float MAX_VOXEL_EDIT_DISTANCE = 20.0f; const float HEAD_SPHERE_RADIUS = 0.07; @@ -2071,6 +2076,7 @@ void Application::update(float deltaTime) { // Leap finger-sensing device LeapManager::enableFakeFingers(_simulateLeapHand->isChecked() || _testRaveGlove->isChecked()); LeapManager::nextFrame(); + _myAvatar.getHand().setRaveGloveActive(_testRaveGlove->isChecked()); _myAvatar.getHand().setLeapFingers(LeapManager::getFingerTips(), LeapManager::getFingerRoots()); _myAvatar.getHand().setLeapHands(LeapManager::getHandPositions(), LeapManager::getHandNormals()); @@ -2118,6 +2124,8 @@ void Application::update(float deltaTime) { _myAvatar.simulate(deltaTime, NULL); } + _myAvatar.getHand().simulate(deltaTime, true); + if (!OculusManager::isConnected()) { if (_lookingInMirror->isChecked()) { if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { @@ -2166,8 +2174,8 @@ void Application::update(float deltaTime) { #endif if (TESTING_PARTICLE_SYSTEM) { - _particleSystem.simulate(deltaTime); - } + updateParticleSystem(deltaTime); + } } void Application::updateAvatar(float deltaTime) { @@ -2560,7 +2568,7 @@ void Application::displaySide(Camera& whichCamera) { //draw a grid ground plane.... if (_renderGroundPlaneOn->isChecked()) { - drawGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE); + renderGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE, _audio.getCollisionSoundMagnitude()); } // Draw voxels if (_renderVoxels->isChecked()) { @@ -2616,7 +2624,9 @@ void Application::displaySide(Camera& whichCamera) { } if (TESTING_PARTICLE_SYSTEM) { - _particleSystem.render(); + if (_particleSystemInitialized) { + _particleSystem.render(); + } } // Render the world box @@ -2636,6 +2646,9 @@ void Application::displayOverlay() { glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); + // Display a single screen-size quad to + renderCollisionOverlay(_glWidget->width(), _glWidget->height(), _audio.getCollisionSoundMagnitude()); + #ifndef _WIN32 _audio.render(_glWidget->width(), _glWidget->height()); if (_oscilloscopeOn->isChecked()) { @@ -2907,7 +2920,7 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { // render the coverage map on screen void Application::renderCoverageMapV2() { - //printLog("renderCoverageMap()\n"); + //qDebug("renderCoverageMap()\n"); glDisable(GL_LIGHTING); glLineWidth(2.0); @@ -2952,7 +2965,7 @@ void Application::renderCoverageMapsV2Recursively(CoverageMapV2* map) { // render the coverage map on screen void Application::renderCoverageMap() { - //printLog("renderCoverageMap()\n"); + //qDebug("renderCoverageMap()\n"); glDisable(GL_LIGHTING); glLineWidth(2.0); @@ -3283,7 +3296,7 @@ void Application::eyedropperVoxelUnderCursor() { } void Application::goHome() { - printLog("Going Home!\n"); + qDebug("Going Home!\n"); _myAvatar.setPosition(START_LOCATION); } @@ -3378,7 +3391,7 @@ void* Application::networkReceive(void* args) { case PACKET_TYPE_ENVIRONMENT_DATA: { if (app->_renderVoxels->isChecked()) { Node* voxelServer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_VOXEL_SERVER); - if (voxelServer) { + if (voxelServer && socketMatch(voxelServer->getActiveSocket(), &senderAddress)) { voxelServer->lock(); if (app->_incomingPacket[0] == PACKET_TYPE_ENVIRONMENT_DATA) { @@ -3528,3 +3541,68 @@ void Application::exportSettings() { } + +void Application::updateParticleSystem(float deltaTime) { + + if (!_particleSystemInitialized) { + // create a stable test emitter and spit out a bunch of particles + _coolDemoParticleEmitter = _particleSystem.addEmitter(); + + if (_coolDemoParticleEmitter != -1) { + _particleSystem.setShowingEmitter(_coolDemoParticleEmitter, true); + glm::vec3 particleEmitterPosition = glm::vec3(5.0f, 1.0f, 5.0f); + _particleSystem.setEmitterPosition(_coolDemoParticleEmitter, particleEmitterPosition); + glm::vec3 velocity(0.0f, 0.1f, 0.0f); + float lifespan = 100000.0f; + _particleSystem.emitParticlesNow(_coolDemoParticleEmitter, 1500, velocity, lifespan); + } + + // signal that the particle system has been initialized + _particleSystemInitialized = true; + } else { + // update the particle system + + static float t = 0.0f; + t += deltaTime; + + if (_coolDemoParticleEmitter != -1) { + + glm::vec3 tilt = glm::vec3 + ( + 30.0f * sinf( t * 0.55f ), + 0.0f, + 30.0f * cosf( t * 0.75f ) + ); + + _particleSystem.setEmitterRotation(_coolDemoParticleEmitter, glm::quat(glm::radians(tilt))); + + ParticleSystem::ParticleAttributes attributes; + + attributes.radius = 0.01f; + attributes.color = glm::vec4( 1.0f, 1.0f, 1.0f, 1.0f); + attributes.gravity = 0.0f + 0.05f * sinf( t * 0.52f ); + attributes.airFriction = 2.5 + 2.0f * sinf( t * 0.32f ); + attributes.jitter = 0.05f + 0.05f * sinf( t * 0.42f ); + attributes.emitterAttraction = 0.015f + 0.015f * cosf( t * 0.6f ); + attributes.tornadoForce = 0.0f + 0.03f * sinf( t * 0.7f ); + attributes.neighborAttraction = 0.1f + 0.1f * cosf( t * 0.8f ); + attributes.neighborRepulsion = 0.2f + 0.2f * sinf( t * 0.4f ); + attributes.bounce = 1.0f; + attributes.usingCollisionSphere = true; + attributes.collisionSpherePosition = glm::vec3( 5.0f, 0.5f, 5.0f ); + attributes.collisionSphereRadius = 0.5f; + + if (attributes.gravity < 0.0f) { + attributes.gravity = 0.0f; + } + + _particleSystem.setParticleAttributes(_coolDemoParticleEmitter, attributes); + } + + _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); + _particleSystem.simulate(deltaTime); + } +} + + + diff --git a/interface/src/Application.h b/interface/src/Application.h index bb65343749..37eadb04f8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -22,8 +22,6 @@ #include #include -#include - #ifndef _WIN32 #include "Audio.h" #endif @@ -31,15 +29,18 @@ #include "BandwidthMeter.h" #include "Camera.h" #include "Environment.h" +#include "PacketHeaders.h" #include "ParticleSystem.h" +#include "renderer/GeometryCache.h" #include "SerialInterface.h" #include "Stars.h" #include "Swatch.h" #include "ToolsPalette.h" +#include "ViewFrustum.h" #include "VoxelSystem.h" #include "Webcam.h" +#include "avatar/Avatar.h" #include "avatar/HandControl.h" -#include "renderer/GeometryCache.h" #include "ui/BandwidthDialog.h" #include "ui/ChatEntry.h" @@ -83,7 +84,10 @@ public: const glm::vec3 getMouseVoxelWorldCoordinates(const VoxelDetail _mouseVoxel); + void updateParticleSystem(float deltaTime); + Avatar* getAvatar() { return &_myAvatar; } + Audio* getAudio() { return &_audio; } Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } @@ -104,6 +108,9 @@ public slots: void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data); + void setGroundPlaneImpact(float groundPlaneImpact) { _groundPlaneImpact = groundPlaneImpact; } + + private slots: void timer(); @@ -210,7 +217,7 @@ private: void deleteVoxelUnderCursor(); void eyedropperVoxelUnderCursor(); void resetSensors(); - + void setMenuShortcutsEnabled(bool enabled); void updateCursor(); @@ -290,6 +297,8 @@ private: timeval _timerStart, _timerEnd; timeval _lastTimeUpdated; bool _justStarted; + bool _particleSystemInitialized; + int _coolDemoParticleEmitter; Stars _stars; @@ -348,6 +357,8 @@ private: float _yawFromTouch; float _pitchFromTouch; + float _groundPlaneImpact; + VoxelDetail _mouseVoxelDragging; glm::vec3 _voxelThrust; bool _mousePressed; // true if mouse has been pressed (clear when finished) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 63fc24f56d..41090584f3 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -7,24 +7,25 @@ // #ifndef _WIN32 -#include +#include #include + +#include #include #include -#include -#include -#include -#include -#include + +#include #include #include -#include +#include +#include +#include +#include #include "Application.h" #include "Audio.h" #include "Util.h" -#include "Log.h" // Uncomment the following definition to test audio device latency by copying output to input //#define TEST_AUDIO_LOOPBACK @@ -75,9 +76,12 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o NodeList* nodeList = NodeList::getInstance(); Application* interface = Application::getInstance(); Avatar* interfaceAvatar = interface->getAvatar(); - + + memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); + // Add Procedural effects to input samples - addProceduralSounds(inputLeft, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); + addProceduralSounds(inputLeft, outputLeft, outputRight, BUFFER_LENGTH_SAMPLES_PER_CHANNEL); if (nodeList && inputLeft) { @@ -134,12 +138,8 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o + leadingBytes); } - } - - memset(outputLeft, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - memset(outputRight, 0, PACKET_LENGTH_BYTES_PER_CHANNEL); - + AudioRingBuffer* ringBuffer = &_ringBuffer; // if there is anything in the ring buffer, decide what to do: @@ -151,7 +151,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o // If not enough audio has arrived to start playback, keep waiting // #ifdef SHOW_AUDIO_DEBUG - printLog("%i,%i,%i,%i\n", + qDebug("%i,%i,%i,%i\n", _packetsReceivedThisPlayback, ringBuffer->diffLastWriteNextOutput(), PACKET_LENGTH_SAMPLES, @@ -168,7 +168,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o _packetsReceivedThisPlayback = 0; _wasStarved = 10; // Frames for which to render the indication that the system was starved. #ifdef SHOW_AUDIO_DEBUG - printLog("Starved, remaining samples = %d\n", + qDebug("Starved, remaining samples = %d\n", ringBuffer->diffLastWriteNextOutput()); #endif @@ -179,7 +179,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o if (!ringBuffer->isStarted()) { ringBuffer->setStarted(true); #ifdef SHOW_AUDIO_DEBUG - printLog("starting playback %0.1f msecs delayed, jitter = %d, pkts recvd: %d \n", + qDebug("starting playback %0.1f msecs delayed, jitter = %d, pkts recvd: %d \n", (usecTimestampNow() - usecTimestamp(&_firstPacketReceivedTime))/1000.0, _jitterBufferSamples, _packetsReceivedThisPlayback); @@ -250,11 +250,11 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o } } #ifndef TEST_AUDIO_LOOPBACK - outputLeft[s] = leftSample; - outputRight[s] = rightSample; + outputLeft[s] += leftSample; + outputRight[s] += rightSample; #else - outputLeft[s] = inputLeft[s]; - outputRight[s] = inputLeft[s]; + outputLeft[s] += inputLeft[s]; + outputRight[s] += inputLeft[s]; #endif } ringBuffer->setNextOutput(ringBuffer->getNextOutput() + PACKET_LENGTH_SAMPLES); @@ -299,8 +299,8 @@ int Audio::audioCallback (const void* inputBuffer, static void outputPortAudioError(PaError error) { if (error != paNoError) { - printLog("-- portaudio termination error --\n"); - printLog("PortAudio error (%d): %s\n", error, Pa_GetErrorText(error)); + qDebug("-- portaudio termination error --\n"); + qDebug("PortAudio error (%d): %s\n", error, Pa_GetErrorText(error)); } } @@ -332,7 +332,13 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : _lastYawMeasuredMaximum(0), _flangeIntensity(0.0f), _flangeRate(0.0f), - _flangeWeight(0.0f) + _flangeWeight(0.0f), + _collisionSoundMagnitude(0.0f), + _collisionSoundFrequency(0.0f), + _collisionSoundNoise(0.0f), + _collisionSoundDuration(0.0f), + _proceduralEffectSample(0), + _heartbeatMagnitude(0.0f) { outputPortAudioError(Pa_Initialize()); @@ -349,7 +355,7 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : outputParameters.device = Pa_GetDefaultOutputDevice(); if (inputParameters.device == -1 || outputParameters.device == -1) { - printLog("Audio: Missing device.\n"); + qDebug("Audio: Missing device.\n"); outputPortAudioError(Pa_Terminate()); return; } @@ -384,12 +390,12 @@ Audio::Audio(Oscilloscope* scope, int16_t initialJitterBufferSamples) : outputPortAudioError(Pa_StartStream(_stream)); // Uncomment these lines to see the system-reported latency - //printLog("Default low input, output latency (secs): %0.4f, %0.4f\n", + //qDebug("Default low input, output latency (secs): %0.4f, %0.4f\n", // Pa_GetDeviceInfo(Pa_GetDefaultInputDevice())->defaultLowInputLatency, // Pa_GetDeviceInfo(Pa_GetDefaultOutputDevice())->defaultLowOutputLatency); const PaStreamInfo* streamInfo = Pa_GetStreamInfo(_stream); - printLog("Started audio with reported latency msecs In/Out: %.0f, %.0f\n", streamInfo->inputLatency * 1000.f, + qDebug("Started audio with reported latency msecs In/Out: %.0f, %.0f\n", streamInfo->inputLatency * 1000.f, streamInfo->outputLatency * 1000.f); gettimeofday(&_lastReceiveTime, NULL); @@ -588,7 +594,10 @@ void Audio::lowPassFilter(int16_t* inputBuffer) { } // Take a pointer to the acquired microphone input samples and add procedural sounds -void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { +void Audio::addProceduralSounds(int16_t* inputBuffer, + int16_t* outputLeft, + int16_t* outputRight, + int numSamples) { const float MAX_AUDIBLE_VELOCITY = 6.0; const float MIN_AUDIBLE_VELOCITY = 0.1; const int VOLUME_BASELINE = 400; @@ -597,14 +606,48 @@ void Audio::addProceduralSounds(int16_t* inputBuffer, int numSamples) { float speed = glm::length(_lastVelocity); float volume = VOLUME_BASELINE * (1.f - speed / MAX_AUDIBLE_VELOCITY); + int sample; + + // + // Travelling noise + // // Add a noise-modulated sinewave with volume that tapers off with speed increasing if ((speed > MIN_AUDIBLE_VELOCITY) && (speed < MAX_AUDIBLE_VELOCITY)) { for (int i = 0; i < numSamples; i++) { - inputBuffer[i] += (int16_t)((sinf((float) i / SOUND_PITCH * speed) * randFloat()) * volume * speed); + inputBuffer[i] += (int16_t)(sinf((float) (_proceduralEffectSample + i) / SOUND_PITCH ) * volume * (1.f + randFloat() * 0.25f) * speed); } } + const float COLLISION_SOUND_CUTOFF_LEVEL = 0.01f; + const float COLLISION_SOUND_MAX_VOLUME = 1000.f; + const float UP_MAJOR_FIFTH = powf(1.5f, 4.0f); + const float DOWN_TWO_OCTAVES = 4.f; + const float DOWN_FOUR_OCTAVES = 16.f; + float t; + if (_collisionSoundMagnitude > COLLISION_SOUND_CUTOFF_LEVEL) { + for (int i = 0; i < numSamples; i++) { + t = (float) _proceduralEffectSample + (float) i; + sample = sinf(t * _collisionSoundFrequency) + + sinf(t * _collisionSoundFrequency / DOWN_TWO_OCTAVES) + + sinf(t * _collisionSoundFrequency / DOWN_FOUR_OCTAVES * UP_MAJOR_FIFTH); + sample *= _collisionSoundMagnitude * COLLISION_SOUND_MAX_VOLUME; + inputBuffer[i] += sample; + outputLeft[i] += sample; + outputRight[i] += sample; + _collisionSoundMagnitude *= _collisionSoundDuration; + } + } + _proceduralEffectSample += numSamples; } +// +// Starts a collision sound. magnitude is 0-1, with 1 the loudest possible sound. +// +void Audio::startCollisionSound(float magnitude, float frequency, float noise, float duration) { + _collisionSoundMagnitude = magnitude; + _collisionSoundFrequency = frequency; + _collisionSoundNoise = noise; + _collisionSoundDuration = duration; +} // ----------------------------------------------------------- // Accoustic ping (audio system round trip time determination) // ----------------------------------------------------------- @@ -650,7 +693,7 @@ inline void Audio::eventuallySendRecvPing(int16_t* inputLeft, int16_t* outputLef // As of the next frame, we'll be recoding PING_FRAMES_TO_RECORD from // the mic (pointless to start now as we can't record unsent audio). _isSendingEchoPing = false; - printLog("Send audio ping\n"); + qDebug("Send audio ping\n"); } else if (_pingFramesToRecord > 0) { @@ -664,7 +707,7 @@ inline void Audio::eventuallySendRecvPing(int16_t* inputLeft, int16_t* outputLef if (_pingFramesToRecord == 0) { _pingAnalysisPending = true; - printLog("Received ping echo\n"); + qDebug("Received ping echo\n"); } } } @@ -688,25 +731,25 @@ inline void Audio::analyzePing() { // Determine extrema int botAt = findExtremum(_echoSamplesLeft, PING_SAMPLES_TO_ANALYZE, -1); if (botAt == -1) { - printLog("Audio Ping: Minimum not found.\n"); + qDebug("Audio Ping: Minimum not found.\n"); return; } int topAt = findExtremum(_echoSamplesLeft, PING_SAMPLES_TO_ANALYZE, 1); if (topAt == -1) { - printLog("Audio Ping: Maximum not found.\n"); + qDebug("Audio Ping: Maximum not found.\n"); return; } // Determine peak amplitude - warn if low int ampli = (_echoSamplesLeft[topAt] - _echoSamplesLeft[botAt]) / 2; if (ampli < PING_MIN_AMPLI) { - printLog("Audio Ping unreliable - low amplitude %d.\n", ampli); + qDebug("Audio Ping unreliable - low amplitude %d.\n", ampli); } // Determine period - warn if doesn't look like our signal int halfPeriod = abs(topAt - botAt); if (abs(halfPeriod-PING_HALF_PERIOD) > PING_MAX_PERIOD_DIFFERENCE) { - printLog("Audio Ping unreliable - peak distance %d vs. %d\n", halfPeriod, PING_HALF_PERIOD); + qDebug("Audio Ping unreliable - peak distance %d vs. %d\n", halfPeriod, PING_HALF_PERIOD); } // Ping is sent: @@ -747,7 +790,7 @@ inline void Audio::analyzePing() { int delay = (botAt + topAt) / 2 + PING_PERIOD; - printLog("\n| Audio Ping results:\n+----- ---- --- - - - - -\n\n" + qDebug("\n| Audio Ping results:\n+----- ---- --- - - - - -\n\n" "Delay = %d samples (%d ms)\nPeak amplitude = %d\n\n", delay, (delay * 1000) / int(SAMPLE_RATE), ampli); } diff --git a/interface/src/Audio.h b/interface/src/Audio.h index ffbf1f7214..37db447381 100644 --- a/interface/src/Audio.h +++ b/interface/src/Audio.h @@ -14,7 +14,6 @@ #include #include "Oscilloscope.h" -#include "avatar/Avatar.h" static const int NUM_AUDIO_CHANNELS = 2; @@ -43,7 +42,11 @@ public: int getJitterBufferSamples() { return _jitterBufferSamples; }; void lowPassFilter(int16_t* inputBuffer); - + + void startCollisionSound(float magnitude, float frequency, float noise, float duration); + float getCollisionSoundMagnitude() { return _collisionSoundMagnitude; }; + + void ping(); // Call periodically to eventually perform round trip time analysis, @@ -81,7 +84,13 @@ private: float _flangeIntensity; float _flangeRate; float _flangeWeight; - + float _collisionSoundMagnitude; + float _collisionSoundFrequency; + float _collisionSoundNoise; + float _collisionSoundDuration; + int _proceduralEffectSample; + float _heartbeatMagnitude; + // Audio callback in class context. inline void performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* outputRight); @@ -93,7 +102,7 @@ private: inline void analyzePing(); // Add sounds that we want the user to not hear themselves, by adding on top of mic input signal - void addProceduralSounds(int16_t* inputBuffer, int numSamples); + void addProceduralSounds(int16_t* inputBuffer, int16_t* outputLeft, int16_t* outputRight, int numSamples); // Audio callback called by portaudio. Calls 'performIO'. diff --git a/interface/src/BandwidthMeter.cpp b/interface/src/BandwidthMeter.cpp index 5e0d63d6c5..1c1fa62297 100644 --- a/interface/src/BandwidthMeter.cpp +++ b/interface/src/BandwidthMeter.cpp @@ -9,7 +9,6 @@ #include "BandwidthMeter.h" #include "InterfaceConfig.h" -#include "Log.h" #include "Util.h" namespace { // .cpp-local diff --git a/interface/src/Camera.cpp b/interface/src/Camera.cpp index 8aaec5b899..a9db96e65c 100644 --- a/interface/src/Camera.cpp +++ b/interface/src/Camera.cpp @@ -5,9 +5,10 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include + #include #include -#include "Log.h" + #include "Camera.h" #include "Util.h" diff --git a/interface/src/Environment.cpp b/interface/src/Environment.cpp index 35ed121e38..adfb1cfb3b 100644 --- a/interface/src/Environment.cpp +++ b/interface/src/Environment.cpp @@ -47,6 +47,11 @@ void Environment::init() { _data[getZeroAddress()][0]; } +void Environment::resetToDefault() { + _data.clear(); + _data[getZeroAddress()][0]; +} + void Environment::renderAtmospheres(Camera& camera) { // get the lock for the duration of the call QMutexLocker locker(&_mutex); diff --git a/interface/src/Environment.h b/interface/src/Environment.h index f711f0c38c..7bdbfa600b 100644 --- a/interface/src/Environment.h +++ b/interface/src/Environment.h @@ -24,6 +24,7 @@ class Environment { public: void init(); + void resetToDefault(); void renderAtmospheres(Camera& camera); glm::vec3 getGravity (const glm::vec3& position); diff --git a/interface/src/LogDisplay.cpp b/interface/src/LogDisplay.cpp index 6a65c30021..247ea4beb5 100644 --- a/interface/src/LogDisplay.cpp +++ b/interface/src/LogDisplay.cpp @@ -15,7 +15,7 @@ #include "Util.h" using namespace std; -FILE* const LogDisplay::DEFAULT_STREAM = stdout; +FILE* const LogDisplay::DEFAULT_STREAM = 0l; // // Singleton constructor @@ -26,9 +26,7 @@ LogDisplay LogDisplay::instance; // State management // -LogDisplay::LogDisplay() : - - +LogDisplay::LogDisplay() : _textRenderer(SANS_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT), _stream(DEFAULT_STREAM), _chars(0l), @@ -53,8 +51,6 @@ LogDisplay::LogDisplay() : memset(_lines, 0, LINE_BUFFER_SIZE * sizeof(char*)); setCharacterSize(DEFAULT_CHAR_WIDTH, DEFAULT_CHAR_HEIGHT); - - printLog = & printLogHandler; } @@ -92,32 +88,7 @@ void LogDisplay::setCharacterSize(unsigned width, unsigned height) { // Logging // -int LogDisplay::printLogHandler(char const* fmt, ...) { - - va_list args; - int n; - char buf[MAX_MESSAGE_LENGTH]; - va_start(args,fmt); - - // print to buffer - n = vsnprintf(buf, MAX_MESSAGE_LENGTH, fmt, args); - if (n > 0) { - - // all fine? log the message - instance.addMessage(buf); - - } else { - - // error? -> mutter on stream or stderr - fprintf(instance._stream != 0l ? instance._stream : stderr, - "Log: Failed to log message with format string = \"%s\".\n", fmt); - } - - va_end(args); - return n; -} - -inline void LogDisplay::addMessage(char const* ptr) { +void LogDisplay::addMessage(const char* ptr) { pthread_mutex_lock(& _mutex); diff --git a/interface/src/LogDisplay.h b/interface/src/LogDisplay.h index f699cb5279..6f90df3724 100644 --- a/interface/src/LogDisplay.h +++ b/interface/src/LogDisplay.h @@ -12,7 +12,6 @@ #include #include -#include "Log.h" #include "ui/TextRenderer.h" class LogDisplay { @@ -21,6 +20,9 @@ public: static LogDisplay instance; void render(unsigned screenWidth, unsigned screenHeight); + + // log formatted message + void addMessage(const char* message); // settings @@ -50,12 +52,6 @@ private: LogDisplay(LogDisplay const&); // = delete; LogDisplay& operator=(LogDisplay const&); // = delete; - // format and log message - entrypoint used to replace global 'printLog' - static int printLogHandler(char const* fmt, ...); - - // log formatted message (called by printLogHandler) - inline void addMessage(char const*); - TextRenderer _textRenderer; FILE* _stream; // FILE as secondary destination for log messages char* _chars; // character buffer base address diff --git a/interface/src/ParticleSystem.cpp b/interface/src/ParticleSystem.cpp index 3c27f3a8df..9dcdbe5f06 100644 --- a/interface/src/ParticleSystem.cpp +++ b/interface/src/ParticleSystem.cpp @@ -8,116 +8,217 @@ #include #include "InterfaceConfig.h" #include - #include "ParticleSystem.h" +#include "Application.h" + +const float DEFAULT_PARTICLE_RADIUS = 0.01f; +const float DEFAULT_PARTICLE_BOUNCE = 1.0f; +const float DEFAULT_PARTICLE_AIR_FRICTION = 2.0f; ParticleSystem::ParticleSystem() { - _numberOfParticles = 1500; - assert(_numberOfParticles <= MAX_PARTICLES); - - _bounce = 0.9f; - _timer = 0.0f; - _airFriction = 6.0f; - _jitter = 0.1f; - _homeAttraction = 0.0f; - _tornadoForce = 0.0f; - _neighborAttraction = 0.02f; - _neighborRepulsion = 0.9f; - _tornadoAxis = glm::normalize(glm::vec3(0.1f, 1.0f, 0.1f)); - _home = glm::vec3(5.0f, 1.0f, 5.0f); - - _TEST_bigSphereRadius = 0.5f; - _TEST_bigSpherePosition = glm::vec3( 5.0f, _TEST_bigSphereRadius, 5.0f); + _numEmitters = 0; + _numParticles = 0; + _upDirection = glm::vec3(0.0f, 1.0f, 0.0f); // default + + for (unsigned int emitterIndex = 0; emitterIndex < MAX_EMITTERS; emitterIndex++) { + _emitter[emitterIndex].position = glm::vec3(0.0f, 0.0f, 0.0f); + _emitter[emitterIndex].rotation = glm::quat(); + _emitter[emitterIndex].visible = false; + _emitter[emitterIndex].baseParticle.alive = false; + _emitter[emitterIndex].baseParticle.age = 0.0f; + _emitter[emitterIndex].baseParticle.lifespan = 0.0f; + _emitter[emitterIndex].baseParticle.radius = 0.0f; + _emitter[emitterIndex].baseParticle.emitterIndex = 0; + _emitter[emitterIndex].baseParticle.position = glm::vec3(0.0f, 0.0f, 0.0f); + _emitter[emitterIndex].baseParticle.velocity = glm::vec3(0.0f, 0.0f, 0.0f); + + for (int lifeStage = 0; lifeStageradius = DEFAULT_PARTICLE_RADIUS; + a->color = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f); + a->bounce = DEFAULT_PARTICLE_BOUNCE; + a->airFriction = DEFAULT_PARTICLE_AIR_FRICTION; + a->gravity = 0.0f; + a->jitter = 0.0f; + a->emitterAttraction = 0.0f; + a->tornadoForce = 0.0f; + a->neighborAttraction = 0.0f; + a->neighborRepulsion = 0.0f; + a->collisionSphereRadius = 0.0f; + a->collisionSpherePosition = glm::vec3(0.0f, 0.0f, 0.0f); + a->usingCollisionSphere = false; + } + }; + + for (unsigned int p = 0; p < MAX_PARTICLES; p++) { + _particle[p].alive = false; + _particle[p].age = 0.0f; + _particle[p].lifespan = 0.0f; + _particle[p].radius = 0.0f; + _particle[p].emitterIndex = 0; + _particle[p].position = glm::vec3(0.0f, 0.0f, 0.0f); + _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); + } } +int ParticleSystem::addEmitter() { + + _numEmitters ++; + + if (_numEmitters > MAX_EMITTERS) { + return -1; + } + + return _numEmitters - 1; +} + + void ParticleSystem::simulate(float deltaTime) { - runSpecialEffectsTest(deltaTime); - - for (unsigned int p = 0; p < _numberOfParticles; p++) { - updateParticle(p, deltaTime); + // update particles + for (unsigned int p = 0; p < _numParticles; p++) { + if (_particle[p].alive) { + if (_particle[p].age > _particle[p].lifespan) { + killParticle(p); + } else { + updateParticle(p, deltaTime); + } + } } } +void ParticleSystem::emitParticlesNow(int e, int num, glm::vec3 velocity, float lifespan) { - -void ParticleSystem::runSpecialEffectsTest(float deltaTime) { - - _timer += deltaTime; - - _gravity = 0.01f + 0.01f * sinf( _timer * 0.52f ); - _airFriction = 3.0f + 2.0f * sinf( _timer * 0.32f ); - _jitter = 0.05f + 0.05f * sinf( _timer * 0.42f ); - _homeAttraction = 0.01f + 0.01f * cosf( _timer * 0.6f ); - _tornadoForce = 0.0f + 0.03f * sinf( _timer * 0.7f ); - _neighborAttraction = 0.1f + 0.1f * cosf( _timer * 0.8f ); - _neighborRepulsion = 0.4f + 0.3f * sinf( _timer * 0.4f ); - - _tornadoAxis = glm::vec3 - ( - 0.0f + 0.5f * sinf( _timer * 0.55f ), - 1.0f, - 0.0f + 0.5f * cosf( _timer * 0.75f ) - ); + for (unsigned int p = 0; p < num; p++) { + createParticle(e, velocity, lifespan); + } } +void ParticleSystem::createParticle(int e, glm::vec3 velocity, float lifespan) { + + for (unsigned int p = 0; p < MAX_PARTICLES; p++) { + if (!_particle[p].alive) { + + _particle[p].emitterIndex = e; + _particle[p].lifespan = lifespan; + _particle[p].alive = true; + _particle[p].age = 0.0f; + _particle[p].velocity = velocity; + _particle[p].position = _emitter[e].position; + _particle[p].radius = _emitter[e].particleAttributes[0].radius; + _particle[p].color = _emitter[e].particleAttributes[0].color; + + _numParticles ++; + + assert(_numParticles <= MAX_PARTICLES); + + return; + } + } +} + +void ParticleSystem::killParticle(int p) { + + assert( p >= 0); + assert( p < MAX_PARTICLES); + assert( _numParticles > 0); + + _particle[p].alive = false; + _numParticles --; +} + + +void ParticleSystem::setParticleAttributes(int emitterIndex, ParticleAttributes attributes) { + + for (int lifeStage = 0; lifeStage < NUM_PARTICLE_LIFE_STAGES; lifeStage ++ ) { + setParticleAttributes(emitterIndex, lifeStage, attributes); + } +} + +void ParticleSystem::setParticleAttributes(int emitterIndex, int lifeStage, ParticleAttributes attributes) { + + ParticleAttributes * a = &_emitter[emitterIndex].particleAttributes[lifeStage]; + + a->radius = attributes.radius; + a->color = attributes.color; + a->bounce = attributes.bounce; + a->gravity = attributes.gravity; + a->airFriction = attributes.airFriction; + a->jitter = attributes.jitter; + a->emitterAttraction = attributes.emitterAttraction; + a->tornadoForce = attributes.tornadoForce; + a->neighborAttraction = attributes.neighborAttraction; + a->neighborRepulsion = attributes.neighborRepulsion; + a->usingCollisionSphere = attributes.usingCollisionSphere; + a->collisionSpherePosition = attributes.collisionSpherePosition; + a->collisionSphereRadius = attributes.collisionSphereRadius; +} void ParticleSystem::updateParticle(int p, float deltaTime) { - _particle[p].age += deltaTime; + assert(_particle[p].age <= _particle[p].lifespan); + + float ageFraction = _particle[p].age / _particle[p].lifespan; + + int lifeStage = (int)( ageFraction * (NUM_PARTICLE_LIFE_STAGES-1) ); + + float lifeStageFraction = ageFraction * ( NUM_PARTICLE_LIFE_STAGES - 1 ) - lifeStage; + + _particle[p].radius + = _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage ].radius * (1.0f - lifeStageFraction) + + _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage+1].radius * lifeStageFraction; + + _particle[p].color + = _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage ].color * (1.0f - lifeStageFraction) + + _emitter[_particle[p].emitterIndex].particleAttributes[lifeStage+1].color * lifeStageFraction; + + Emitter myEmitter = _emitter[_particle[p].emitterIndex]; // apply random jitter + float j = myEmitter.particleAttributes[lifeStage].jitter; _particle[p].velocity += glm::vec3 ( - -_jitter * ONE_HALF + _jitter * randFloat(), - -_jitter * ONE_HALF + _jitter * randFloat(), - -_jitter * ONE_HALF + _jitter * randFloat() + -j * ONE_HALF + j * randFloat(), + -j * ONE_HALF + j * randFloat(), + -j * ONE_HALF + j * randFloat() ) * deltaTime; - // apply attraction to home position - glm::vec3 vectorToHome = _home - _particle[p].position; - _particle[p].velocity += vectorToHome * _homeAttraction * deltaTime; + glm::vec3 vectorToHome = myEmitter.position - _particle[p].position; + _particle[p].velocity += vectorToHome * myEmitter.particleAttributes[lifeStage].emitterAttraction * deltaTime; // apply neighbor attraction int neighbor = p + 1; - if (neighbor == _numberOfParticles ) { + if (neighbor == _numParticles ) { neighbor = 0; } - glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position; - _particle[p].velocity -= vectorToNeighbor * _neighborAttraction * deltaTime; + if ( _particle[neighbor].emitterIndex == _particle[p].emitterIndex) { + glm::vec3 vectorToNeighbor = _particle[p].position - _particle[neighbor].position; + + _particle[p].velocity -= vectorToNeighbor * myEmitter.particleAttributes[lifeStage].neighborAttraction * deltaTime; - float distanceToNeighbor = glm::length(vectorToNeighbor); - if (distanceToNeighbor > 0.0f) { - _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * _neighborRepulsion * deltaTime; + float distanceToNeighbor = glm::length(vectorToNeighbor); + if (distanceToNeighbor > 0.0f) { + _particle[neighbor].velocity += (vectorToNeighbor / ( 1.0f + distanceToNeighbor * distanceToNeighbor)) * myEmitter.particleAttributes[lifeStage].neighborRepulsion * deltaTime; + } } // apply tornado force - glm::vec3 tornadoDirection = glm::cross(vectorToHome, _tornadoAxis); - _particle[p].velocity += tornadoDirection * _tornadoForce * deltaTime; + + + glm::vec3 emitterUp = myEmitter.rotation * IDENTITY_UP; + + glm::vec3 tornadoDirection = glm::cross(vectorToHome, emitterUp); + _particle[p].velocity += tornadoDirection * myEmitter.particleAttributes[lifeStage].tornadoForce * deltaTime; // apply air friction - float drag = 1.0 - _airFriction * deltaTime; + float drag = 1.0 - myEmitter.particleAttributes[lifeStage].airFriction * deltaTime; if (drag < 0.0f) { _particle[p].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } else { @@ -125,7 +226,7 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { } // apply gravity - _particle[p].velocity.y -= _gravity * deltaTime; + _particle[p].velocity -= _upDirection * myEmitter.particleAttributes[lifeStage].gravity * deltaTime; // update position by velocity _particle[p].position += _particle[p].velocity; @@ -135,49 +236,149 @@ void ParticleSystem::updateParticle(int p, float deltaTime) { _particle[p].position.y = _particle[p].radius; if (_particle[p].velocity.y < 0.0f) { - _particle[p].velocity.y *= -_bounce; + _particle[p].velocity.y *= -myEmitter.particleAttributes[lifeStage].bounce; } } // collision with sphere - glm::vec3 vectorToSphereCenter = _TEST_bigSpherePosition - _particle[p].position; - float distanceToSphereCenter = glm::length(vectorToSphereCenter); - float combinedRadius = _TEST_bigSphereRadius + _particle[p].radius; - if (distanceToSphereCenter < combinedRadius) { - - if (distanceToSphereCenter > 0.0f){ - glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; - _particle[p].position = _TEST_bigSpherePosition - directionToSphereCenter * combinedRadius; + if (myEmitter.particleAttributes[lifeStage].usingCollisionSphere) { + glm::vec3 vectorToSphereCenter = myEmitter.particleAttributes[lifeStage].collisionSpherePosition - _particle[p].position; + float distanceToSphereCenter = glm::length(vectorToSphereCenter); + float combinedRadius = myEmitter.particleAttributes[lifeStage].collisionSphereRadius + _particle[p].radius; + if (distanceToSphereCenter < combinedRadius) { + + if (distanceToSphereCenter > 0.0f){ + glm::vec3 directionToSphereCenter = vectorToSphereCenter / distanceToSphereCenter; + _particle[p].position = myEmitter.particleAttributes[lifeStage].collisionSpherePosition - directionToSphereCenter * combinedRadius; + } } } + + // do this at the end... + _particle[p].age += deltaTime; +} + +void ParticleSystem::setEmitterBaseParticle(int emitterIndex, bool showing ) { + + _emitter[emitterIndex].baseParticle.alive = true; + _emitter[emitterIndex].baseParticle.emitterIndex = emitterIndex; +} + +void ParticleSystem::setEmitterBaseParticle(int emitterIndex, bool showing, float radius, glm::vec4 color ) { + + _emitter[emitterIndex].baseParticle.alive = true; + _emitter[emitterIndex].baseParticle.emitterIndex = emitterIndex; + _emitter[emitterIndex].baseParticle.radius = radius; + _emitter[emitterIndex].baseParticle.color = color; } void ParticleSystem::render() { - for (unsigned int p = 0; p < _numberOfParticles; p++) { - glColor3f(_particle[p].color.x, _particle[p].color.y, _particle[p].color.z); + // render the emitters + for (int e = 0; e < _numEmitters; e++) { + + if (_emitter[e].baseParticle.alive) { + glColor4f(_emitter[e].baseParticle.color.r, _emitter[e].baseParticle.color.g, _emitter[e].baseParticle.color.b, _emitter[e].baseParticle.color.a ); + glPushMatrix(); + glTranslatef(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glutSolidSphere(_emitter[e].baseParticle.radius, 6, 6); + glPopMatrix(); + } + + if (_emitter[e].visible) { + renderEmitter(e, 0.2f); + } + }; + + // render the particles + for (unsigned int p = 0; p < _numParticles; p++) { + if (_particle[p].alive) { + renderParticle(p); + } + } +} + +void ParticleSystem::renderParticle(int p) { + + glColor4f(_particle[p].color.r, _particle[p].color.g, _particle[p].color.b, _particle[p].color.a ); + + if (USE_BILLBOARD_RENDERING) { + glm::vec3 cameraPosition = Application::getInstance()->getCamera()->getPosition(); + glm::vec3 viewVector = _particle[p].position - cameraPosition; + float distance = glm::length(viewVector); + + if (distance >= 0.0f) { + viewVector /= distance; + glm::vec3 up = glm::vec3(viewVector.y, viewVector.z, viewVector.x); + glm::vec3 right = glm::vec3(viewVector.z, viewVector.x, viewVector.y); + + glm::vec3 p0 = _particle[p].position - right * _particle[p].radius - up * _particle[p].radius; + glm::vec3 p1 = _particle[p].position + right * _particle[p].radius - up * _particle[p].radius; + glm::vec3 p2 = _particle[p].position + right * _particle[p].radius + up * _particle[p].radius; + glm::vec3 p3 = _particle[p].position - right * _particle[p].radius + up * _particle[p].radius; + + glBegin(GL_TRIANGLES); + glVertex3f(p0.x, p0.y, p0.z); + glVertex3f(p1.x, p1.y, p1.z); + glVertex3f(p2.x, p2.y, p2.z); + glEnd(); + + glBegin(GL_TRIANGLES); + glVertex3f(p0.x, p0.y, p0.z); + glVertex3f(p2.x, p2.y, p2.z); + glVertex3f(p3.x, p3.y, p3.z); + glEnd(); + } + } else { glPushMatrix(); glTranslatef(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); glutSolidSphere(_particle[p].radius, 6, 6); glPopMatrix(); - - // render velocity lines - glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f); - glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f; - glBegin(GL_LINES); - glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); - glVertex3f(end.x, end.y, end.z); - - glEnd(); - + + if (SHOW_VELOCITY_TAILS) { + glColor4f( _particle[p].color.x, _particle[p].color.y, _particle[p].color.z, 0.5f); + glm::vec3 end = _particle[p].position - _particle[p].velocity * 2.0f; + glBegin(GL_LINES); + glVertex3f(_particle[p].position.x, _particle[p].position.y, _particle[p].position.z); + glVertex3f(end.x, end.y, end.z); + glEnd(); + } } } +void ParticleSystem::renderEmitter(int e, float size) { + + glm::vec3 r = _emitter[e].rotation * IDENTITY_FRONT * size; + glm::vec3 u = _emitter[e].rotation * IDENTITY_RIGHT * size; + glm::vec3 f = _emitter[e].rotation * IDENTITY_UP * size; + + glLineWidth(2.0f); + + glColor3f(0.8f, 0.4, 0.4); + glBegin(GL_LINES); + glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glVertex3f(_emitter[e].position.x + r.x, _emitter[e].position.y + r.y, _emitter[e].position.z + r.z); + glEnd(); + + glColor3f(0.4f, 0.8, 0.4); + glBegin(GL_LINES); + glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glVertex3f(_emitter[e].position.x + u.x, _emitter[e].position.y + u.y, _emitter[e].position.z + u.z); + glEnd(); + + glColor3f(0.4f, 0.4, 0.8); + glBegin(GL_LINES); + glVertex3f(_emitter[e].position.x, _emitter[e].position.y, _emitter[e].position.z); + glVertex3f(_emitter[e].position.x + f.x, _emitter[e].position.y + f.y, _emitter[e].position.z + f.z); + glEnd(); +} + + + - diff --git a/interface/src/ParticleSystem.h b/interface/src/ParticleSystem.h index 38eb0a1777..764800f23e 100644 --- a/interface/src/ParticleSystem.h +++ b/interface/src/ParticleSystem.h @@ -4,56 +4,86 @@ // // Created by Jeffrey on July 10, 2013 // -// #ifndef hifi_ParticleSystem_h #define hifi_ParticleSystem_h -const int MAX_PARTICLES = 5000; -const int MAX_EMITTERS = 10; +#include + +const int MAX_PARTICLES = 5000; +const int MAX_EMITTERS = 20; +const int NUM_PARTICLE_LIFE_STAGES = 4; +const bool USE_BILLBOARD_RENDERING = false; +const bool SHOW_VELOCITY_TAILS = false; class ParticleSystem { public: + + struct ParticleAttributes { + float radius; + glm::vec4 color; + float bounce; + float gravity; + float airFriction; + float jitter; + float emitterAttraction; + float tornadoForce; + float neighborAttraction; + float neighborRepulsion; + bool usingCollisionSphere; + glm::vec3 collisionSpherePosition; + float collisionSphereRadius; + }; + ParticleSystem(); + int addEmitter(); // add (create new) emitter and get its unique id + void emitParticlesNow(int emitterIndex, int numParticles, glm::vec3 velocity, float lifespan); void simulate(float deltaTime); void render(); + + void setUpDirection(glm::vec3 upDirection) {_upDirection = upDirection;} // tell particle system which direction is up + void setEmitterBaseParticle(int emitterIndex, bool showing ); + void setEmitterBaseParticle(int emitterIndex, bool showing, float radius, glm::vec4 color ); + void setParticleAttributes (int emitterIndex, ParticleAttributes attributes); + void setParticleAttributes (int emitterIndex, int lifeStage, ParticleAttributes attributes); + void setEmitterPosition (int emitterIndex, glm::vec3 position) { _emitter[emitterIndex].position = position; } // set position of emitter + void setEmitterRotation (int emitterIndex, glm::quat rotation) { _emitter[emitterIndex].rotation = rotation; } // set rotation of emitter + void setShowingEmitter (int emitterIndex, bool showing ) { _emitter[emitterIndex].visible = showing; } // set its visibiity private: - - struct Particle { - glm::vec3 position; - glm::vec3 velocity; - glm::vec3 color; - float age; - float radius; - }; - - struct Emitter { - glm::vec3 position; - glm::vec3 direction; - }; - float _bounce; - float _gravity; - float _timer; - Emitter _emitter[MAX_EMITTERS]; - Particle _particle[MAX_PARTICLES]; - int _numberOfParticles; - glm::vec3 _home; - glm::vec3 _tornadoAxis; - float _airFriction; - float _jitter; - float _homeAttraction; - float _tornadoForce; - float _neighborAttraction; - float _neighborRepulsion; - float _TEST_bigSphereRadius; - glm::vec3 _TEST_bigSpherePosition; + struct Particle { + bool alive; // is the particle active? + glm::vec3 position; // position + glm::vec3 velocity; // velocity + glm::vec4 color; // color (rgba) + float age; // age in seconds + float radius; // radius + float lifespan; // how long this particle stays alive (in seconds) + int emitterIndex; // which emitter created this particle? + }; + + struct Emitter { + glm::vec3 position; + glm::quat rotation; + bool visible; + Particle baseParticle; // a non-physical particle at the emitter position + ParticleAttributes particleAttributes[NUM_PARTICLE_LIFE_STAGES]; // the attributes of particles emitted from this emitter + }; + + glm::vec3 _upDirection; + Emitter _emitter[MAX_EMITTERS]; + Particle _particle[MAX_PARTICLES]; + int _numParticles; + int _numEmitters; // private methods void updateParticle(int index, float deltaTime); - void runSpecialEffectsTest(float deltaTime); + void createParticle(int e, glm::vec3 velocity, float lifespan); + void killParticle(int p); + void renderEmitter(int emitterIndex, float size); + void renderParticle(int p); }; #endif diff --git a/interface/src/SerialInterface.cpp b/interface/src/SerialInterface.cpp index aac1f8f1f2..0f90ee8dd7 100644 --- a/interface/src/SerialInterface.cpp +++ b/interface/src/SerialInterface.cpp @@ -36,6 +36,28 @@ const int LONG_TERM_RATE_SAMPLES = 1000; const bool USING_INVENSENSE_MPU9150 = 1; +SerialInterface::SerialInterface() : + _active(false), + _gravity(0, 0, 0), + _averageRotationRates(0, 0, 0), + _averageAcceleration(0, 0, 0), + _estimatedRotation(0, 0, 0), + _estimatedPosition(0, 0, 0), + _estimatedVelocity(0, 0, 0), + _lastAcceleration(0, 0, 0), + _lastRotationRates(0, 0, 0), + _compassMinima(-211, -132, -186), + _compassMaxima(89, 95, 98), + _angularVelocityToLinearAccel(0.003f, -0.001f, -0.006f, + -0.005f, -0.001f, -0.006f, + 0.010f, 0.004f, 0.007f), + _angularAccelToLinearAccel(0.0f, 0.0f, 0.002f, + 0.0f, 0.0f, 0.001f, + -0.002f, -0.002f, 0.0f) +{ + +} + void SerialInterface::pair() { #ifndef _WIN32 @@ -75,10 +97,10 @@ void SerialInterface::initializePort(char* portname) { #ifndef _WIN32 _serialDescriptor = open(portname, O_RDWR | O_NOCTTY | O_NDELAY); - printLog("Opening SerialUSB %s: ", portname); + qDebug("Opening SerialUSB %s: ", portname); if (_serialDescriptor == -1) { - printLog("Failed.\n"); + qDebug("Failed.\n"); return; } @@ -112,7 +134,7 @@ void SerialInterface::initializePort(char* portname) { mpu_set_sensors(INV_XYZ_GYRO | INV_XYZ_ACCEL | INV_XYZ_COMPASS); } - printLog("Connected.\n"); + qDebug("Connected.\n"); resetSerial(); _active = true; @@ -351,7 +373,7 @@ void SerialInterface::readData(float deltaTime) { gettimeofday(&now, NULL); if (diffclock(&lastGoodRead, &now) > NO_READ_MAXIMUM_MSECS) { - printLog("No data - Shutting down SerialInterface.\n"); + qDebug("No data - Shutting down SerialInterface.\n"); resetSerial(); } } else { diff --git a/interface/src/SerialInterface.h b/interface/src/SerialInterface.h index 6398953456..711ff56757 100644 --- a/interface/src/SerialInterface.h +++ b/interface/src/SerialInterface.h @@ -1,17 +1,14 @@ // // SerialInterface.h -// - +// hifi +// +// Created by Stephen Birarda on 2/15/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// #ifndef __interface__SerialInterface__ #define __interface__SerialInterface__ -#include -#include "Util.h" -#include "world.h" -#include "InterfaceConfig.h" -#include "Log.h" - // These includes are for serial port reading/writing #ifndef _WIN32 #include @@ -20,30 +17,16 @@ #include #endif +#include + +#include "InterfaceConfig.h" +#include "Util.h" + extern const bool USING_INVENSENSE_MPU9150; class SerialInterface { public: - SerialInterface() : _active(false), - _gravity(0, 0, 0), - _averageRotationRates(0, 0, 0), - _averageAcceleration(0, 0, 0), - _estimatedRotation(0, 0, 0), - _estimatedPosition(0, 0, 0), - _estimatedVelocity(0, 0, 0), - _lastAcceleration(0, 0, 0), - _lastRotationRates(0, 0, 0), - _compassMinima(-211, -132, -186), - _compassMaxima(89, 95, 98), - _angularVelocityToLinearAccel( - 0.003f, -0.001f, -0.006f, - -0.005f, -0.001f, -0.006f, - 0.010f, 0.004f, 0.007f), - _angularAccelToLinearAccel( - 0.0f, 0.0f, 0.002f, - 0.0f, 0.0f, 0.001f, - -0.002f, -0.002f, 0.0f) - {} + SerialInterface(); void pair(); void readData(float deltaTime); diff --git a/interface/src/Transmitter.cpp b/interface/src/Transmitter.cpp index b16fb79295..eac769ead7 100644 --- a/interface/src/Transmitter.cpp +++ b/interface/src/Transmitter.cpp @@ -13,11 +13,9 @@ #include #include "InterfaceConfig.h" -#include "Log.h" #include "Transmitter.h" #include "Util.h" - const float DELTA_TIME = 1.f / 60.f; const float DECAY_RATE = 0.15f; @@ -40,7 +38,7 @@ void Transmitter::checkForLostTransmitter() { int msecsSinceLast = diffclock(_lastReceivedPacket, &now); if (msecsSinceLast > TIME_TO_ASSUME_LOST_MSECS) { resetLevels(); - printLog("Transmitter signal lost.\n"); + qDebug("Transmitter signal lost.\n"); } } } @@ -95,12 +93,12 @@ void Transmitter::processIncomingData(unsigned char* packetData, int numBytes) { _estimatedRotation.y *= (1.f - DECAY_RATE * DELTA_TIME); if (!_isConnected) { - printLog("Transmitter Connected.\n"); + qDebug("Transmitter Connected.\n"); _isConnected = true; _estimatedRotation *= 0.0; } } else { - printLog("Transmitter packet read error, %d bytes.\n", numBytes); + qDebug("Transmitter packet read error, %d bytes.\n", numBytes); } } diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 65a277b623..6aff15240e 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -6,7 +6,6 @@ // Copyright (c) 2012 High Fidelity, Inc. All rights reserved. // -#include "InterfaceConfig.h" #include #include #include @@ -15,16 +14,16 @@ #include #include #include + #include #include -#include "Log.h" +#include "InterfaceConfig.h" #include "ui/TextRenderer.h" -#include "world.h" -#include "Util.h" - - #include "VoxelConstants.h" +#include "world.h" + +#include "Util.h" using namespace std; @@ -326,22 +325,38 @@ void drawvec3(int x, int y, float scale, float rotate, float thick, int mono, gl glPopMatrix(); } +void renderCollisionOverlay(int width, int height, float magnitude) { + const float MIN_VISIBLE_COLLISION = 0.01f; + if (magnitude > MIN_VISIBLE_COLLISION) { + glColor4f(0, 0, 0, magnitude); + glBegin(GL_QUADS); + glVertex2f(0, 0); + glVertex2d(width, 0); + glVertex2d(width, height); + glVertex2d(0, height); + glEnd(); + } +} -void drawGroundPlaneGrid(float size) { - glColor3f(0.4f, 0.5f, 0.3f); +void renderGroundPlaneGrid(float size, float impact) { glLineWidth(2.0); - + glm::vec4 impactColor(1, 0, 0, 1); + glm::vec3 lineColor(0.4, 0.5, 0.3); + glm::vec4 surfaceColor(0.5, 0.5, 0.5, 0.4); + + glColor3fv(&lineColor.x); for (float x = 0; x <= size; x++) { glBegin(GL_LINES); - glVertex3f(x, 0.0f, 0); - glVertex3f(x, 0.0f, size); - glVertex3f(0, 0.0f, x); - glVertex3f(size, 0.0f, x); + glVertex3f(x, 0, 0); + glVertex3f(x, 0, size); + glVertex3f(0, 0, x); + glVertex3f(size, 0, x); glEnd(); } - // Draw a translucent quad just underneath the grid. - glColor4f(0.5, 0.5, 0.5, 0.4); + // Draw the floor, colored for recent impact + glm::vec4 floorColor = impact * impactColor + (1.f - impact) * surfaceColor; + glColor4fv(&floorColor.x); glBegin(GL_QUADS); glVertex3f(0, 0, 0); glVertex3f(size, 0, 0); @@ -452,7 +467,7 @@ void renderOrientationDirections(glm::vec3 position, const glm::quat& orientatio bool closeEnoughForGovernmentWork(float a, float b) { float distance = std::abs(a-b); - //printLog("closeEnoughForGovernmentWork() a=%1.10f b=%1.10f distance=%1.10f\n",a,b,distance); + //qDebug("closeEnoughForGovernmentWork() a=%1.10f b=%1.10f distance=%1.10f\n",a,b,distance); return (distance < 0.00001f); } @@ -470,7 +485,7 @@ void runTimingTests() { gettimeofday(&endTime, NULL); } elapsedMsecs = diffclock(&startTime, &endTime); - printLog("gettimeofday() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); + qDebug("gettimeofday() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); // Random number generation gettimeofday(&startTime, NULL); @@ -479,7 +494,7 @@ void runTimingTests() { } gettimeofday(&endTime, NULL); elapsedMsecs = diffclock(&startTime, &endTime); - printLog("rand() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); + qDebug("rand() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); // Random number generation using randFloat() gettimeofday(&startTime, NULL); @@ -488,7 +503,7 @@ void runTimingTests() { } gettimeofday(&endTime, NULL); elapsedMsecs = diffclock(&startTime, &endTime); - printLog("randFloat() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); + qDebug("randFloat() stored in array usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); // PowF function fTest = 1145323.2342f; @@ -498,7 +513,7 @@ void runTimingTests() { } gettimeofday(&endTime, NULL); elapsedMsecs = diffclock(&startTime, &endTime); - printLog("powf(f, 0.5) usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); + qDebug("powf(f, 0.5) usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); // Vector Math float distance; @@ -511,7 +526,7 @@ void runTimingTests() { } gettimeofday(&endTime, NULL); elapsedMsecs = diffclock(&startTime, &endTime); - printLog("vector math usecs: %f [%f msecs total for %d tests]\n", + qDebug("vector math usecs: %f [%f msecs total for %d tests]\n", 1000.0f * elapsedMsecs / (float) numTests, elapsedMsecs, numTests); // Vec3 test @@ -525,7 +540,7 @@ void runTimingTests() { } gettimeofday(&endTime, NULL); elapsedMsecs = diffclock(&startTime, &endTime); - printLog("vec3 assign and dot() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); + qDebug("vec3 assign and dot() usecs: %f\n", 1000.0f * elapsedMsecs / (float) numTests); } diff --git a/interface/src/Util.h b/interface/src/Util.h index 37bd0595ec..8bc77a98ea 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -57,7 +57,10 @@ glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); double diffclock(timeval *clock1,timeval *clock2); -void drawGroundPlaneGrid(float size); +void renderGroundPlaneGrid(float size, float impact); + +void renderCollisionOverlay(int width, int height, float magnitude); + void renderDiskShadow(glm::vec3 position, glm::vec3 upDirection, float radius, float darkness); diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 2801d16748..f219e38dc6 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -5,28 +5,31 @@ // Created by Philip on 12/31/12. // Copyright (c) 2012 High Fidelity, Inc. All rights reserved. // + #ifdef _WIN32 #define _timeval_ #define _USE_MATH_DEFINES #endif + #include #include #include // to load voxels from file #include // to load voxels from file +#include + #include -#include + +#include #include #include -#include -#include +#include + #include "Application.h" -#include "Log.h" -#include "VoxelConstants.h" #include "CoverageMap.h" #include "CoverageMapV2.h" #include "InterfaceConfig.h" #include "renderer/ProgramObject.h" - +#include "VoxelConstants.h" #include "VoxelSystem.h" float identityVertices[] = { 0,0,0, 1,0,0, 1,1,0, 0,1,0, 0,0,1, 1,0,1, 1,1,1, 0,1,1, @@ -141,16 +144,16 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { int commandLength = strlen(command); // commands are null terminated strings int totalLength = 1+commandLength+1; - printLog("got Z message len(%d)= %s\n", numBytes, command); + qDebug("got Z message len(%d)= %s\n", numBytes, command); while (totalLength <= numBytes) { if (0==strcmp(command,(char*)"erase all")) { - printLog("got Z message == erase all\n"); + qDebug("got Z message == erase all\n"); _tree->eraseAllVoxels(); _voxelsInReadArrays = _voxelsInWriteArrays = 0; // better way to do this?? } if (0==strcmp(command,(char*)"add scene")) { - printLog("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n"); + qDebug("got Z message == add scene - NOT SUPPORTED ON INTERFACE\n"); } totalLength += commandLength+1; } @@ -705,7 +708,7 @@ bool VoxelSystem::randomColorOperation(VoxelNode* node, void* extraData) { void VoxelSystem::randomizeVoxelColors() { _nodeCount = 0; _tree->recurseTreeWithOperation(randomColorOperation); - printLog("setting randomized true color for %d nodes\n", _nodeCount); + qDebug("setting randomized true color for %d nodes\n", _nodeCount); setupNewVoxelsForDrawing(); } @@ -719,7 +722,7 @@ bool VoxelSystem::falseColorizeRandomOperation(VoxelNode* node, void* extraData) void VoxelSystem::falseColorizeRandom() { _nodeCount = 0; _tree->recurseTreeWithOperation(falseColorizeRandomOperation); - printLog("setting randomized false color for %d nodes\n", _nodeCount); + qDebug("setting randomized false color for %d nodes\n", _nodeCount); setupNewVoxelsForDrawing(); } @@ -733,7 +736,7 @@ void VoxelSystem::trueColorize() { PerformanceWarning warn(true, "trueColorize()",true); _nodeCount = 0; _tree->recurseTreeWithOperation(trueColorizeOperation); - printLog("setting true color for %d nodes\n", _nodeCount); + qDebug("setting true color for %d nodes\n", _nodeCount); setupNewVoxelsForDrawing(); } @@ -753,7 +756,7 @@ bool VoxelSystem::falseColorizeInViewOperation(VoxelNode* node, void* extraData) void VoxelSystem::falseColorizeInView(ViewFrustum* viewFrustum) { _nodeCount = 0; _tree->recurseTreeWithOperation(falseColorizeInViewOperation,(void*)viewFrustum); - printLog("setting in view false color for %d nodes\n", _nodeCount); + qDebug("setting in view false color for %d nodes\n", _nodeCount); setupNewVoxelsForDrawing(); } @@ -803,10 +806,10 @@ void VoxelSystem::falseColorizeDistanceFromView(ViewFrustum* viewFrustum) { _maxDistance = 0.0; _minDistance = FLT_MAX; _tree->recurseTreeWithOperation(getDistanceFromViewRangeOperation,(void*)viewFrustum); - printLog("determining distance range for %d nodes\n", _nodeCount); + qDebug("determining distance range for %d nodes\n", _nodeCount); _nodeCount = 0; _tree->recurseTreeWithOperation(falseColorizeDistanceFromViewOperation,(void*)viewFrustum); - printLog("setting in distance false color for %d nodes\n", _nodeCount); + qDebug("setting in distance false color for %d nodes\n", _nodeCount); setupNewVoxelsForDrawing(); } @@ -918,7 +921,7 @@ void VoxelSystem::removeOutOfView() { } bool showRemoveDebugDetails = false; if (showRemoveDebugDetails) { - printLog("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld _removedVoxels.count()=%d \n", + qDebug("removeOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld _removedVoxels.count()=%d \n", args.nodesScanned, args.nodesRemoved, args.nodesInside, args.nodesIntersect, args.nodesOutside, _removedVoxels.count() ); @@ -984,7 +987,7 @@ bool VoxelSystem::falseColorizeRandomEveryOtherOperation(VoxelNode* node, void* void VoxelSystem::falseColorizeRandomEveryOther() { falseColorizeRandomEveryOtherArgs args; _tree->recurseTreeWithOperation(falseColorizeRandomEveryOtherOperation,&args); - printLog("randomized false color for every other node: total %ld, colorable %ld, colored %ld\n", + qDebug("randomized false color for every other node: total %ld, colorable %ld, colored %ld\n", args.totalNodes, args.colorableNodes, args.coloredNodes); setupNewVoxelsForDrawing(); } @@ -1045,7 +1048,7 @@ bool VoxelSystem::collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* ex unsigned long nodeIndex = node->getBufferIndex(); if (args->hasIndexFound[nodeIndex]) { args->duplicateVBOIndex++; - printLog("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s \n", nodeIndex, + qDebug("duplicateVBO found... index=%ld, isDirty=%s, shouldRender=%s \n", nodeIndex, debug::valueOf(node->isDirty()), debug::valueOf(node->getShouldRender())); } else { args->hasIndexFound[nodeIndex] = true; @@ -1080,13 +1083,13 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { args.expectedMax = _voxelsInWriteArrays; _tree->recurseTreeWithOperation(collectStatsForTreesAndVBOsOperation,&args); - printLog("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n", + qDebug("Local Voxel Tree Statistics:\n total nodes %ld \n leaves %ld \n dirty %ld \n colored %ld \n shouldRender %ld \n", args.totalNodes, args.leafNodes, args.dirtyNodes, args.coloredNodes, args.shouldRenderNodes); - printLog(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld \n", debug::valueOf(_voxelsDirty), + qDebug(" _voxelsDirty=%s \n _voxelsInWriteArrays=%ld \n minDirty=%ld \n maxDirty=%ld \n", debug::valueOf(_voxelsDirty), _voxelsInWriteArrays, minDirty, maxDirty); - printLog(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld \n", + qDebug(" inVBO %ld \n nodesInVBOOverExpectedMax %ld \n duplicateVBOIndex %ld \n nodesInVBONotShouldRender %ld \n", args.nodesInVBO, args.nodesInVBOOverExpectedMax, args.duplicateVBOIndex, args.nodesInVBONotShouldRender); glBufferIndex minInVBO = GLBUFFER_INDEX_UNKNOWN; @@ -1099,7 +1102,7 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { } } - printLog(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld \n", + qDebug(" minInVBO=%ld \n maxInVBO=%ld \n _voxelsInWriteArrays=%ld \n _voxelsInReadArrays=%ld \n", minInVBO, maxInVBO, _voxelsInWriteArrays, _voxelsInReadArrays); } @@ -1124,7 +1127,7 @@ void VoxelSystem::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue, bool destructive) { pthread_mutex_lock(&_treeLock); - //printLog("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s); + //qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s); _tree->createVoxel(x, y, z, s, red, green, blue, destructive); setupNewVoxelsForDrawing(); @@ -1250,9 +1253,9 @@ bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraDat args->occludedVoxels++; } else if (result == STORED) { args->notOccludedVoxels++; - //printLog("***** falseColorizeOccludedOperation() NODE is STORED *****\n"); + //qDebug("***** falseColorizeOccludedOperation() NODE is STORED *****\n"); } else if (result == DOESNT_FIT) { - //printLog("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n"); + //qDebug("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n"); } } return true; // keep going! @@ -1285,7 +1288,7 @@ void VoxelSystem::falseColorizeOccluded() { _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedOperation, position, (void*)&args); - printLog("falseColorizeOccluded()\n position=(%f,%f)\n total=%ld\n colored=%ld\n occluded=%ld\n notOccluded=%ld\n outOfView=%ld\n subtreeVoxelsSkipped=%ld\n stagedForDeletion=%ld\n nonLeaves=%ld\n nonLeavesOutOfView=%ld\n nonLeavesOccluded=%ld\n pointInside_calls=%ld\n occludes_calls=%ld\n intersects_calls=%ld\n", + qDebug("falseColorizeOccluded()\n position=(%f,%f)\n total=%ld\n colored=%ld\n occluded=%ld\n notOccluded=%ld\n outOfView=%ld\n subtreeVoxelsSkipped=%ld\n stagedForDeletion=%ld\n nonLeaves=%ld\n nonLeavesOutOfView=%ld\n nonLeavesOccluded=%ld\n pointInside_calls=%ld\n occludes_calls=%ld\n intersects_calls=%ld\n", position.x, position.y, args.totalVoxels, args.coloredVoxels, args.occludedVoxels, args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped, @@ -1371,9 +1374,9 @@ bool VoxelSystem::falseColorizeOccludedV2Operation(VoxelNode* node, void* extraD args->occludedVoxels++; } else if (result == V2_STORED) { args->notOccludedVoxels++; - //printLog("***** falseColorizeOccludedOperation() NODE is STORED *****\n"); + //qDebug("***** falseColorizeOccludedOperation() NODE is STORED *****\n"); } else if (result == V2_DOESNT_FIT) { - //printLog("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n"); + //qDebug("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n"); } delete voxelPolygon; // V2 maps don't store polygons, so we're always in charge of freeing } @@ -1410,7 +1413,7 @@ void VoxelSystem::falseColorizeOccludedV2() { _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedV2Operation, position, (void*)&args); - printLog("falseColorizeOccludedV2()\n position=(%f,%f)\n total=%ld\n colored=%ld\n occluded=%ld\n notOccluded=%ld\n outOfView=%ld\n subtreeVoxelsSkipped=%ld\n stagedForDeletion=%ld\n nonLeaves=%ld\n nonLeavesOutOfView=%ld\n nonLeavesOccluded=%ld\n pointInside_calls=%ld\n occludes_calls=%ld\n intersects_calls=%ld\n", + qDebug("falseColorizeOccludedV2()\n position=(%f,%f)\n total=%ld\n colored=%ld\n occluded=%ld\n notOccluded=%ld\n outOfView=%ld\n subtreeVoxelsSkipped=%ld\n stagedForDeletion=%ld\n nonLeaves=%ld\n nonLeavesOutOfView=%ld\n nonLeavesOccluded=%ld\n pointInside_calls=%ld\n occludes_calls=%ld\n intersects_calls=%ld\n", position.x, position.y, args.totalVoxels, args.coloredVoxels, args.occludedVoxels, args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped, diff --git a/interface/src/Webcam.cpp b/interface/src/Webcam.cpp index cc83c784f2..aac0616244 100644 --- a/interface/src/Webcam.cpp +++ b/interface/src/Webcam.cpp @@ -15,7 +15,6 @@ #include #endif -#include #include #include "Application.h" @@ -158,7 +157,7 @@ void Webcam::setFrame(const Mat& color, int format, const Mat& depth, const Rota glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _textureSize.width = colorImage.width, _textureSize.height = colorImage.height, 0, format, GL_UNSIGNED_BYTE, colorImage.imageData); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - printLog("Capturing video at %gx%g.\n", _textureSize.width, _textureSize.height); + qDebug("Capturing video at %gx%g.\n", _textureSize.width, _textureSize.height); } else { glBindTexture(GL_TEXTURE_2D, _colorTextureID); @@ -327,26 +326,26 @@ static glm::quat xnToGLM(const XnMatrix3X3& matrix) { } static void XN_CALLBACK_TYPE newUser(UserGenerator& generator, XnUserID id, void* cookie) { - printLog("Found user %d.\n", id); + qDebug("Found user %d.\n", id); generator.GetSkeletonCap().RequestCalibration(id, false); } static void XN_CALLBACK_TYPE lostUser(UserGenerator& generator, XnUserID id, void* cookie) { - printLog("Lost user %d.\n", id); + qDebug("Lost user %d.\n", id); } static void XN_CALLBACK_TYPE calibrationStarted(SkeletonCapability& capability, XnUserID id, void* cookie) { - printLog("Calibration started for user %d.\n", id); + qDebug("Calibration started for user %d.\n", id); } static void XN_CALLBACK_TYPE calibrationCompleted(SkeletonCapability& capability, XnUserID id, XnCalibrationStatus status, void* cookie) { if (status == XN_CALIBRATION_STATUS_OK) { - printLog("Calibration completed for user %d.\n", id); + qDebug("Calibration completed for user %d.\n", id); capability.StartTracking(id); } else { - printLog("Calibration failed to user %d.\n", id); + qDebug("Calibration failed to user %d.\n", id); capability.RequestCalibration(id, true); } } @@ -441,7 +440,7 @@ void FrameGrabber::grabFrame() { // make sure it's in the format we expect if (image->nChannels != 3 || image->depth != IPL_DEPTH_8U || image->dataOrder != IPL_DATA_ORDER_PIXEL || image->origin != 0) { - printLog("Invalid webcam image format.\n"); + qDebug("Invalid webcam image format.\n"); return; } color = image; @@ -629,7 +628,7 @@ bool FrameGrabber::init() { // load our face cascade switchToResourcesParentIfRequired(); if (_faceCascade.empty() && !_faceCascade.load("resources/haarcascades/haarcascade_frontalface_alt.xml")) { - printLog("Failed to load Haar cascade for face tracking.\n"); + qDebug("Failed to load Haar cascade for face tracking.\n"); return false; } @@ -662,7 +661,7 @@ bool FrameGrabber::init() { // next, an ordinary webcam if ((_capture = cvCaptureFromCAM(-1)) == 0) { - printLog("Failed to open webcam.\n"); + qDebug("Failed to open webcam.\n"); return false; } const int IDEAL_FRAME_WIDTH = 320; diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index eef7aa9b43..ddb78f595b 100755 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -5,24 +5,25 @@ // Created by Philip Rosedale on 9/11/12. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +#include + #include #include #include -#include + +#include +#include +#include +#include #include -#include "world.h" + #include "Application.h" #include "Avatar.h" #include "Hand.h" #include "Head.h" -#include "Log.h" #include "Physics.h" +#include "world.h" #include "ui/TextRenderer.h" -#include -#include -#include -#include - using namespace std; @@ -97,6 +98,7 @@ Avatar::Avatar(Node* owningNode) : _elapsedTimeMoving(0.0f), _elapsedTimeStopped(0.0f), _elapsedTimeSinceCollision(0.0f), + _lastCollisionPosition(0, 0, 0), _speedBrakes(false), _isThrustOn(false), _voxels(this) @@ -548,13 +550,13 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { // For gravity, always move the avatar by the amount driven by gravity, so that the collision // routines will detect it and collide every frame when pulled by gravity to a surface // - - _velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime); - _position += _scale * _gravity * (GRAVITY_EARTH * deltaTime) * deltaTime; + const float MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY = 0.02f; + if (glm::length(_position - _lastCollisionPosition) > MIN_DISTANCE_AFTER_COLLISION_FOR_GRAVITY) { + _velocity += _scale * _gravity * (GRAVITY_EARTH * deltaTime); + } } - - updateCollisionWithEnvironment(); - updateCollisionWithVoxels(); + updateCollisionWithEnvironment(deltaTime); + updateCollisionWithVoxels(deltaTime); updateAvatarCollisions(deltaTime); } @@ -826,6 +828,15 @@ void Avatar::updateHandMovementAndTouching(float deltaTime, bool enableHandMovem } else { _avatarTouch.setHasInteractingOther(false); } + + // If there's a leap-interaction hand visible, use that as the endpoint + for (size_t i = 0; i < getHand().getPalms().size(); ++i) { + PalmData& palm = getHand().getPalms()[i]; + if (palm.isActive()) { + _skeleton.joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position = palm.getPosition(); + } + } + }//if (_isMine) //constrain right arm length and re-adjust elbow position as it bends @@ -875,29 +886,40 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d } } -void Avatar::updateCollisionWithEnvironment() { +void Avatar::updateCollisionWithEnvironment(float deltaTime) { glm::vec3 up = getBodyUpDirection(); float radius = _height * 0.125f; const float ENVIRONMENT_SURFACE_ELASTICITY = 1.0f; const float ENVIRONMENT_SURFACE_DAMPING = 0.01; + const float ENVIRONMENT_COLLISION_FREQUENCY = 0.05f; + const float VISIBLE_GROUND_COLLISION_VELOCITY = 0.2f; glm::vec3 penetration; if (Application::getInstance()->getEnvironment()->findCapsulePenetration( _position - up * (_pelvisFloatingHeight - radius), _position + up * (_height - _pelvisFloatingHeight - radius), radius, penetration)) { + float velocityTowardCollision = glm::dot(_velocity, glm::normalize(penetration)); + if (velocityTowardCollision > VISIBLE_GROUND_COLLISION_VELOCITY) { + Application::getInstance()->setGroundPlaneImpact(1.0f); + } + _lastCollisionPosition = _position; + updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY); applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING); } } -void Avatar::updateCollisionWithVoxels() { +void Avatar::updateCollisionWithVoxels(float deltaTime) { float radius = _height * 0.125f; const float VOXEL_ELASTICITY = 1.4f; const float VOXEL_DAMPING = 0.0; + const float VOXEL_COLLISION_FREQUENCY = 0.5f; glm::vec3 penetration; if (Application::getInstance()->getVoxels()->findCapsulePenetration( _position - glm::vec3(0.0f, _pelvisFloatingHeight - radius, 0.0f), _position + glm::vec3(0.0f, _height - _pelvisFloatingHeight - radius, 0.0f), radius, penetration)) { + _lastCollisionPosition = _position; + updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY); applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING); } } @@ -926,6 +948,36 @@ void Avatar::applyHardCollision(const glm::vec3& penetration, float elasticity, } } +void Avatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { + // consider whether to have the collision make a sound + const float AUDIBLE_COLLISION_THRESHOLD = 0.02f; + const float COLLISION_LOUDNESS = 1.f; + const float DURATION_SCALING = 0.004f; + const float NOISE_SCALING = 0.1f; + glm::vec3 velocity = _velocity; + glm::vec3 gravity = getGravity(); + + if (glm::length(gravity) > EPSILON) { + // If gravity is on, remove the effect of gravity on velocity for this + // frame, so that we are not constantly colliding with the surface + velocity -= _scale * glm::length(gravity) * GRAVITY_EARTH * deltaTime * glm::normalize(gravity); + } + float velocityTowardCollision = glm::dot(velocity, glm::normalize(penetration)); + float velocityTangentToCollision = glm::length(velocity) - velocityTowardCollision; + + if (velocityTowardCollision > AUDIBLE_COLLISION_THRESHOLD) { + // Volume is proportional to collision velocity + // Base frequency is modified upward by the angle of the collision + // Noise is a function of the angle of collision + // Duration of the sound is a function of both base frequency and velocity of impact + Application::getInstance()->getAudio()->startCollisionSound( + fmin(COLLISION_LOUDNESS * velocityTowardCollision, 1.f), + frequency * (1.f + velocityTangentToCollision / velocityTowardCollision), + fmin(velocityTangentToCollision / velocityTowardCollision * NOISE_SCALING, 1.f), + 1.f - DURATION_SCALING * powf(frequency, 0.5f) / velocityTowardCollision); + } +} + void Avatar::updateAvatarCollisions(float deltaTime) { // Reset detector for nearest avatar @@ -1055,7 +1107,7 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) { } glPushMatrix(); - glm::vec3 chatPosition = _bodyBall[BODY_BALL_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight; + glm::vec3 chatPosition = _bodyBall[BODY_BALL_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight * _scale; glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z); glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation(); glm::vec3 chatAxis = glm::axis(chatRotation); @@ -1065,7 +1117,7 @@ void Avatar::render(bool lookingInMirror, bool renderAvatarBalls) { glColor3f(0, 0.8, 0); glRotatef(180, 0, 1, 0); glRotatef(180, 0, 0, 1); - glScalef(chatMessageScale, chatMessageScale, 1.0f); + glScalef(_scale * chatMessageScale, _scale * chatMessageScale, 1.0f); glDisable(GL_LIGHTING); glDepthMask(false); diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 643a187a67..75e0ab2f9b 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -10,18 +10,21 @@ #include #include -#include + #include -#include "world.h" + +#include + #include "AvatarTouch.h" #include "AvatarVoxelSystem.h" -#include "InterfaceConfig.h" -#include "SerialInterface.h" #include "Balls.h" #include "Hand.h" #include "Head.h" +#include "InterfaceConfig.h" #include "Skeleton.h" +#include "SerialInterface.h" #include "Transmitter.h" +#include "world.h" const float BODY_BALL_RADIUS_PELVIS = 0.07; const float BODY_BALL_RADIUS_TORSO = 0.065; @@ -115,7 +118,8 @@ public: const glm::vec3& amplifyAngle, float yawFromTouch, float pitchFromTouch); - void addBodyYaw(float y) {_bodyYaw += y;}; + void addBodyYaw(float bodyYaw) {_bodyYaw += bodyYaw;}; + void addBodyYawDelta(float bodyYawDelta) {_bodyYawDelta += bodyYawDelta;} void render(bool lookingInMirror, bool renderAvatarBalls); //setters @@ -152,6 +156,7 @@ public: float getElapsedTimeStopped () const { return _elapsedTimeStopped;} float getElapsedTimeMoving () const { return _elapsedTimeMoving;} float getElapsedTimeSinceCollision() const { return _elapsedTimeSinceCollision;} + const glm::vec3& getLastCollisionPosition () const { return _lastCollisionPosition;} float getAbsoluteHeadYaw () const; float getAbsoluteHeadPitch () const; Head& getHead () {return _head; } @@ -159,6 +164,8 @@ public: glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; + glm::vec3 getGravity () const { return _gravity; } + glm::vec3 getUprightHeadPosition() const; AvatarVoxelSystem* getVoxels() { return &_voxels; } @@ -240,6 +247,7 @@ private: float _elapsedTimeMoving; // Timers to drive camera transitions when moving float _elapsedTimeStopped; float _elapsedTimeSinceCollision; + glm::vec3 _lastCollisionPosition; bool _speedBrakes; bool _isThrustOn; @@ -259,9 +267,10 @@ private: void updateAvatarCollisions(float deltaTime); void updateArmIKAndConstraints( float deltaTime ); void updateCollisionWithSphere( glm::vec3 position, float radius, float deltaTime ); - void updateCollisionWithEnvironment(); - void updateCollisionWithVoxels(); + void updateCollisionWithEnvironment(float deltaTime); + void updateCollisionWithVoxels(float deltaTime); void applyHardCollision(const glm::vec3& penetration, float elasticity, float damping); + void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void applyCollisionWithOtherAvatar( Avatar * other, float deltaTime ); void checkForMouseRayTouching(); }; diff --git a/interface/src/avatar/AvatarVoxelSystem.cpp b/interface/src/avatar/AvatarVoxelSystem.cpp index 99514ce7d0..c85ea1a343 100644 --- a/interface/src/avatar/AvatarVoxelSystem.cpp +++ b/interface/src/avatar/AvatarVoxelSystem.cpp @@ -93,7 +93,7 @@ const Mode MODES[] = { void AvatarVoxelSystem::cycleMode() { _mode = (_mode + 1) % (sizeof(MODES) / sizeof(MODES[0])); - printLog("Voxeltar bind mode %d.\n", _mode); + qDebug("Voxeltar bind mode %d.\n", _mode); // rebind QUrl url = _voxelURL; @@ -255,7 +255,7 @@ void AvatarVoxelSystem::handleVoxelDownloadProgress(qint64 bytesReceived, qint64 } void AvatarVoxelSystem::handleVoxelReplyError() { - printLog("%s\n", _voxelReply->errorString().toAscii().constData()); + qDebug("%s\n", _voxelReply->errorString().toAscii().constData()); _voxelReply->disconnect(this); _voxelReply->deleteLater(); diff --git a/interface/src/avatar/Hand.cpp b/interface/src/avatar/Hand.cpp index 29a2c32bf1..69d8ddfaac 100755 --- a/interface/src/avatar/Hand.cpp +++ b/interface/src/avatar/Hand.cpp @@ -22,9 +22,12 @@ Hand::Hand(Avatar* owningAvatar) : _renderAlpha(1.0), _lookingInMirror(false), _ballColor(0.0, 0.0, 0.4), - _position(0.0, 0.4, 0.0), - _orientation(0.0, 0.0, 0.0, 1.0) + _particleSystemInitialized(false) { + // initialize all finger particle emitters with an invalid id as default + for (int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { + _fingerParticleEmitter[f] = -1; + } } void Hand::init() { @@ -40,46 +43,89 @@ void Hand::reset() { } void Hand::simulate(float deltaTime, bool isMine) { -} - -glm::vec3 Hand::leapPositionToWorldPosition(const glm::vec3& leapPosition) { - float unitScale = 0.001; // convert mm to meters - return _position + _orientation * (leapPosition * unitScale); + if (_isRaveGloveActive) { + updateFingerParticles(deltaTime); + } } void Hand::calculateGeometry() { glm::vec3 offset(0.2, -0.2, -0.3); // place the hand in front of the face where we can see it Head& head = _owningAvatar->getHead(); - _position = head.getPosition() + head.getOrientation() * offset; - _orientation = head.getOrientation(); + _basePosition = head.getPosition() + head.getOrientation() * offset; + _baseOrientation = head.getOrientation(); - int numLeapBalls = _fingerTips.size(); - _leapBalls.resize(numLeapBalls); - - for (int i = 0; i < _fingerTips.size(); ++i) { - _leapBalls[i].rotation = _orientation; - _leapBalls[i].position = leapPositionToWorldPosition(_fingerTips[i]); - _leapBalls[i].radius = 0.01; - _leapBalls[i].touchForce = 0.0; - _leapBalls[i].isCollidable = true; + _leapBalls.clear(); + for (size_t i = 0; i < getNumPalms(); ++i) { + PalmData& palm = getPalms()[i]; + if (palm.isActive()) { + for (size_t f = 0; f < palm.getNumFingers(); ++f) { + FingerData& finger = palm.getFingers()[f]; + if (finger.isActive()) { + const float standardBallRadius = 0.01f; + _leapBalls.resize(_leapBalls.size() + 1); + HandBall& ball = _leapBalls.back(); + ball.rotation = _baseOrientation; + ball.position = finger.getTipPosition(); + ball.radius = standardBallRadius; + ball.touchForce = 0.0; + ball.isCollidable = true; + } + } + } } } void Hand::render(bool lookingInMirror) { - + _renderAlpha = 1.0; _lookingInMirror = lookingInMirror; calculateGeometry(); + if (_isRaveGloveActive) { + renderRaveGloveStage(); + + if (_particleSystemInitialized) { + _particleSystem.render(); + } + } + glEnable(GL_DEPTH_TEST); glEnable(GL_RESCALE_NORMAL); renderHandSpheres(); } +void Hand::renderRaveGloveStage() { + if (_owningAvatar && _owningAvatar->isMyAvatar()) { + Head& head = _owningAvatar->getHead(); + glm::quat headOrientation = head.getOrientation(); + glm::vec3 headPosition = head.getPosition(); + float scale = 100.0f; + glm::vec3 vc = headOrientation * glm::vec3( 0.0f, 0.0f, -30.0f) + headPosition; + glm::vec3 v0 = headOrientation * (glm::vec3(-1.0f, -1.0f, 0.0f) * scale) + vc; + glm::vec3 v1 = headOrientation * (glm::vec3( 1.0f, -1.0f, 0.0f) * scale) + vc; + glm::vec3 v2 = headOrientation * (glm::vec3( 1.0f, 1.0f, 0.0f) * scale) + vc; + glm::vec3 v3 = headOrientation * (glm::vec3(-1.0f, 1.0f, 0.0f) * scale) + vc; + + glDisable(GL_DEPTH_TEST); + glEnable(GL_BLEND); + glBegin(GL_TRIANGLE_FAN); + glColor4f(0.0f, 0.0f, 0.0f, 1.0f); + glVertex3fv((float*)&vc); + glColor4f(0.0f, 0.0f, 0.0f, 0.5f); + glVertex3fv((float*)&v0); + glVertex3fv((float*)&v1); + glVertex3fv((float*)&v2); + glVertex3fv((float*)&v3); + glVertex3fv((float*)&v0); + glEnd(); + glEnable(GL_DEPTH_TEST); + } +} + void Hand::renderHandSpheres() { glPushMatrix(); // Draw the leap balls @@ -97,21 +143,29 @@ void Hand::renderHandSpheres() { } // Draw the finger root cones - if (_fingerTips.size() == _fingerRoots.size()) { - for (size_t i = 0; i < _fingerTips.size(); ++i) { - glColor4f(_ballColor.r, _ballColor.g, _ballColor.b, 0.5); - glm::vec3 tip = leapPositionToWorldPosition(_fingerTips[i]); - glm::vec3 root = leapPositionToWorldPosition(_fingerRoots[i]); - Avatar::renderJointConnectingCone(root, tip, 0.001, 0.003); + for (size_t i = 0; i < getNumPalms(); ++i) { + PalmData& palm = getPalms()[i]; + if (palm.isActive()) { + for (size_t f = 0; f < palm.getNumFingers(); ++f) { + FingerData& finger = palm.getFingers()[f]; + if (finger.isActive()) { + glColor4f(_ballColor.r, _ballColor.g, _ballColor.b, 0.5); + glm::vec3 tip = finger.getTipPosition(); + glm::vec3 root = finger.getRootPosition(); + Avatar::renderJointConnectingCone(root, tip, 0.001, 0.003); + } + } } } // Draw the palms - if (_handPositions.size() == _handNormals.size()) { - for (size_t i = 0; i < _handPositions.size(); ++i) { + for (size_t i = 0; i < getNumPalms(); ++i) { + PalmData& palm = getPalms()[i]; + if (palm.isActive()) { + const float palmThickness = 0.002f; glColor4f(_ballColor.r, _ballColor.g, _ballColor.b, 0.25); - glm::vec3 tip = leapPositionToWorldPosition(_handPositions[i]); - glm::vec3 root = leapPositionToWorldPosition(_handPositions[i] + (_handNormals[i] * 2.0f)); + glm::vec3 tip = palm.getPosition(); + glm::vec3 root = palm.getPosition() + palm.getNormal() * palmThickness; Avatar::renderJointConnectingCone(root, tip, 0.05, 0.03); } } @@ -121,14 +175,133 @@ void Hand::renderHandSpheres() { void Hand::setLeapFingers(const std::vector& fingerTips, const std::vector& fingerRoots) { - _fingerTips = fingerTips; - _fingerRoots = fingerRoots; + // TODO: add id-checking here to increase finger stability + + size_t fingerIndex = 0; + for (size_t i = 0; i < getNumPalms(); ++i) { + PalmData& palm = getPalms()[i]; + for (size_t f = 0; f < palm.getNumFingers(); ++f) { + FingerData& finger = palm.getFingers()[f]; + if (fingerIndex < fingerTips.size()) { + finger.setActive(true); + finger.setRawTipPosition(fingerTips[fingerIndex]); + finger.setRawRootPosition(fingerRoots[fingerIndex]); + fingerIndex++; + } + else { + finger.setActive(false); + } + } + } } void Hand::setLeapHands(const std::vector& handPositions, const std::vector& handNormals) { - _handPositions = handPositions; - _handNormals = handNormals; + for (size_t i = 0; i < getNumPalms(); ++i) { + PalmData& palm = getPalms()[i]; + if (i < handPositions.size()) { + palm.setActive(true); + palm.setRawPosition(handPositions[i]); + palm.setRawNormal(handNormals[i]); + } + else { + palm.setActive(false); + } + } } +void Hand::updateFingerParticles(float deltaTime) { + + if (!_particleSystemInitialized) { + + for ( int f = 0; f< NUM_FINGERS_PER_HAND; f ++ ) { + + _particleSystem.setShowingEmitter(f, true ); + + _fingerParticleEmitter[f] = _particleSystem.addEmitter(); + + assert( _fingerParticleEmitter[f] != -1 ); + + ParticleSystem::ParticleAttributes attributes; + + // set attributes for each life stage of the particle: + attributes.radius = 0.0f; + attributes.color = glm::vec4( 1.0f, 1.0f, 0.5f, 0.5f); + attributes.gravity = 0.0f; + attributes.airFriction = 0.0f; + attributes.jitter = 0.002f; + attributes.emitterAttraction = 0.0f; + attributes.tornadoForce = 0.0f; + attributes.neighborAttraction = 0.0f; + attributes.neighborRepulsion = 0.0f; + attributes.bounce = 1.0f; + attributes.usingCollisionSphere = false; + _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 0, attributes); + + attributes.radius = 0.01f; + attributes.jitter = 0.0f; + attributes.gravity = -0.005f; + attributes.color = glm::vec4( 1.0f, 0.2f, 0.0f, 0.4f); + _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 1, attributes); + + attributes.radius = 0.01f; + attributes.gravity = 0.0f; + attributes.color = glm::vec4( 0.0f, 0.0f, 0.0f, 0.2f); + _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 2, attributes); + + attributes.radius = 0.02f; + attributes.color = glm::vec4( 0.0f, 0.0f, 0.0f, 0.0f); + _particleSystem.setParticleAttributes(_fingerParticleEmitter[f], 3, attributes); + } + + _particleSystemInitialized = true; + } else { + // update the particles + + static float t = 0.0f; + t += deltaTime; + + int fingerIndex = 0; + for (size_t i = 0; i < getNumPalms(); ++i) { + PalmData& palm = getPalms()[i]; + if (palm.isActive()) { + for (size_t f = 0; f < palm.getNumFingers(); ++f) { + FingerData& finger = palm.getFingers()[f]; + if (finger.isActive()) { + if (_fingerParticleEmitter[fingerIndex] != -1) { + + glm::vec3 particleEmitterPosition = finger.getTipPosition(); + + glm::vec3 fingerDirection = particleEmitterPosition - leapPositionToWorldPosition(finger.getRootPosition()); + float fingerLength = glm::length(fingerDirection); + + if (fingerLength > 0.0f) { + fingerDirection /= fingerLength; + } else { + fingerDirection = IDENTITY_UP; + } + + glm::quat particleEmitterRotation = rotationBetween(palm.getNormal(), fingerDirection); + + //glm::quat particleEmitterRotation = glm::angleAxis(0.0f, fingerDirection); + + _particleSystem.setEmitterPosition(_fingerParticleEmitter[f], particleEmitterPosition); + _particleSystem.setEmitterRotation(_fingerParticleEmitter[f], particleEmitterRotation); + + const glm::vec3 velocity = fingerDirection * 0.002f; + const float lifespan = 1.0f; + _particleSystem.emitParticlesNow(_fingerParticleEmitter[f], 1, velocity, lifespan); + } + } + } + } + } + + _particleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f)); + _particleSystem.simulate(deltaTime); + } +} + + + diff --git a/interface/src/avatar/Hand.h b/interface/src/avatar/Hand.h index 1c25c85fbc..fb6b863458 100755 --- a/interface/src/avatar/Hand.h +++ b/interface/src/avatar/Hand.h @@ -15,10 +15,10 @@ #include "world.h" #include "InterfaceConfig.h" #include "SerialInterface.h" +#include "ParticleSystem.h" #include #include - class Avatar; class ProgramObject; @@ -46,27 +46,33 @@ public: const std::vector& fingerRoots); void setLeapHands (const std::vector& handPositions, const std::vector& handNormals); + void updateFingerParticles(float deltaTime); + void setRaveGloveActive(bool active) { _isRaveGloveActive = active; } + // getters const glm::vec3& getLeapBallPosition (int ball) const { return _leapBalls[ball].position;} - - // position conversion - glm::vec3 leapPositionToWorldPosition(const glm::vec3& leapPosition); + bool isRaveGloveActive () const { return _isRaveGloveActive; } private: // disallow copies of the Hand, copy of owning Avatar is disallowed too Hand(const Hand&); Hand& operator= (const Hand&); + + ParticleSystem _particleSystem; Avatar* _owningAvatar; float _renderAlpha; bool _lookingInMirror; + bool _isRaveGloveActive; glm::vec3 _ballColor; - glm::vec3 _position; - glm::quat _orientation; std::vector _leapBalls; + bool _particleSystemInitialized; + int _fingerParticleEmitter[NUM_FINGERS_PER_HAND]; + // private methods + void renderRaveGloveStage(); void renderHandSpheres(); void calculateGeometry(); }; diff --git a/interface/src/avatar/Head.cpp b/interface/src/avatar/Head.cpp index d9b13aabb3..8ebd5d33df 100644 --- a/interface/src/avatar/Head.cpp +++ b/interface/src/avatar/Head.cpp @@ -227,8 +227,9 @@ void Head::simulate(float deltaTime, bool isMine) { const float CAMERA_FOLLOW_HEAD_RATE_START = 0.01f; const float CAMERA_FOLLOW_HEAD_RATE_MAX = 0.5f; const float CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE = 1.05f; - const float CAMERA_STOP_TOLERANCE_DEGREES = 0.1f; - const float CAMERA_START_TOLERANCE_DEGREES = 2.0f; + const float CAMERA_STOP_TOLERANCE_DEGREES = 0.5f; + const float CAMERA_PITCH_START_TOLERANCE_DEGREES = 20.0f; + const float CAMERA_YAW_START_TOLERANCE_DEGREES = 10.0f; float cameraHeadAngleDifference = glm::length(glm::vec2(_pitch - _cameraPitch, _yaw - _cameraYaw)); if (_isCameraMoving) { _cameraFollowHeadRate = glm::clamp(_cameraFollowHeadRate * CAMERA_FOLLOW_HEAD_RATE_RAMP_RATE, @@ -241,7 +242,8 @@ void Head::simulate(float deltaTime, bool isMine) { _isCameraMoving = false; } } else { - if (cameraHeadAngleDifference > CAMERA_START_TOLERANCE_DEGREES) { + if ((fabs(_pitch - _cameraPitch) > CAMERA_PITCH_START_TOLERANCE_DEGREES) || + (fabs(_yaw - _cameraYaw) > CAMERA_YAW_START_TOLERANCE_DEGREES)) { _isCameraMoving = true; _cameraFollowHeadRate = CAMERA_FOLLOW_HEAD_RATE_START; } diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 20347014f0..98ed4fb231 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -16,15 +16,16 @@ // #include "Application.h" -#include "Log.h" + +#include int main(int argc, const char * argv[]) { timeval startup_time; gettimeofday(&startup_time, NULL); Application app(argc, const_cast(argv), startup_time); - printLog( "Created QT Application.\n" ); + qDebug( "Created QT Application.\n" ); int exitCode = app.exec(); - printLog("Normal exit.\n"); + qDebug("Normal exit.\n"); return exitCode; } diff --git a/interface/src/starfield/Config.h b/interface/src/starfield/Config.h index c11fe68e38..3cbff171c7 100644 --- a/interface/src/starfield/Config.h +++ b/interface/src/starfield/Config.h @@ -39,7 +39,6 @@ #include "InterfaceConfig.h" #include "renderer/ProgramObject.h" -#include "Log.h" #include #include diff --git a/interface/src/starfield/Loader.h b/interface/src/starfield/Loader.h index e4e87516ea..e2f6105f33 100644 --- a/interface/src/starfield/Loader.h +++ b/interface/src/starfield/Loader.h @@ -38,12 +38,12 @@ namespace starfield { if (! UrlReader::readUrl(url, *this, cacheFile)) { - printLog("%s:%d: %s\n", + qDebug("%s:%d: %s\n", _urlStr, _lineNo, getError()); return false; } - printLog("Loaded %u stars.\n", _recordsRead); + qDebug("Loaded %u stars.\n", _recordsRead); return true; } @@ -63,7 +63,7 @@ namespace starfield { _vertices->clear(); _vertices->reserve(_limit); -// printLog("Stars.cpp: loader begin %s\n", url); +// qDebug("Stars.cpp: loader begin %s\n", url); } size_t transfer(char* input, size_t bytes) { @@ -103,7 +103,7 @@ namespace starfield { } else { - printLog("Stars.cpp:%d: Bad input from %s\n", + qDebug("Stars.cpp:%d: Bad input from %s\n", _lineNo, _urlStr); } @@ -128,7 +128,7 @@ namespace starfield { // remember the brightness at its top if (_recordsRead == _limit) { -// printLog("Stars.cpp: vertex limit reached -> heap mode\n"); +// qDebug("Stars.cpp: vertex limit reached -> heap mode\n"); make_heap( _vertices->begin(), _vertices->end(), diff --git a/interface/src/ui/BandwidthDialog.cpp b/interface/src/ui/BandwidthDialog.cpp index 1e0e2e616e..4ff9a9878e 100644 --- a/interface/src/ui/BandwidthDialog.cpp +++ b/interface/src/ui/BandwidthDialog.cpp @@ -7,8 +7,6 @@ #include #include -#include "Log.h" - BandwidthDialog::BandwidthDialog(QWidget* parent, BandwidthMeter* model) : QDialog(parent, Qt::Window | Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint), _model(model) { diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index e198336f54..01907b92f4 100755 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -18,6 +18,8 @@ using namespace std; +static const float fingerVectorRadix = 4; // bits of precision when converting from float<->fixed + AvatarData::AvatarData(Node* owningNode) : NodeData(owningNode), _handPosition(0,0,0), @@ -127,36 +129,22 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { *destinationBuffer++ = bitItems; // leap hand data - // In order to make the hand data version-robust, hand data packing is just a series of vec3's, - // with conventions. If a client doesn't know the conventions, they can just get the vec3's - // and render them as balls, or ignore them, without crashing or disrupting anyone. - // Current convention: - // Zero or more fingetTip positions, followed by the same number of fingerRoot positions - - const std::vector& fingerTips = _handData->getFingerTips(); - const std::vector& fingerRoots = _handData->getFingerRoots(); - size_t numFingerVectors = fingerTips.size() + fingerRoots.size(); - if (numFingerVectors > 255) - numFingerVectors = 0; // safety. We shouldn't ever get over 255, so consider that invalid. + std::vector fingerVectors; + _handData->encodeRemoteData(fingerVectors); ///////////////////////////////// // Temporarily disable Leap finger sending, as it's causing a crash whenever someone's got a Leap connected - numFingerVectors = 0; + fingerVectors.clear(); ///////////////////////////////// - - *destinationBuffer++ = (unsigned char)numFingerVectors; - - if (numFingerVectors > 0) { - for (size_t i = 0; i < fingerTips.size(); ++i) { - destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerTips[i].x, 4); - destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerTips[i].y, 4); - destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerTips[i].z, 4); - } - for (size_t i = 0; i < fingerRoots.size(); ++i) { - destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerRoots[i].x, 4); - destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerRoots[i].y, 4); - destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerRoots[i].z, 4); - } + if (fingerVectors.size() > 255) + fingerVectors.clear(); // safety. We shouldn't ever get over 255, so consider that invalid. + + *destinationBuffer++ = (unsigned char)fingerVectors.size(); + + for (size_t i = 0; i < fingerVectors.size(); ++i) { + destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerVectors[i].x, fingerVectorRadix); + destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerVectors[i].y, fingerVectorRadix); + destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerVectors[i].z, fingerVectorRadix); } // skeleton joints @@ -222,7 +210,7 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { memcpy(&handPositionRelative, sourceBuffer, sizeof(float) * 3); _handPosition = _position + handPositionRelative; sourceBuffer += sizeof(float) * 3; - + // Lookat Position memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition)); sourceBuffer += sizeof(_headData->_lookAtPosition); @@ -263,25 +251,16 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { // leap hand data if (sourceBuffer - startPosition < numBytes) // safety check { - std::vector fingerTips; - std::vector fingerRoots; unsigned int numFingerVectors = *sourceBuffer++; - unsigned int numFingerTips = numFingerVectors / 2; - unsigned int numFingerRoots = numFingerVectors - numFingerTips; - fingerTips.resize(numFingerTips); - fingerRoots.resize(numFingerRoots); - for (size_t i = 0; i < numFingerTips; ++i) { - sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerTips[i].x), 4); - sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerTips[i].y), 4); - sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerTips[i].z), 4); + if (numFingerVectors > 0) { + std::vector fingerVectors(numFingerVectors); + for (size_t i = 0; i < numFingerVectors; ++i) { + sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].x), fingerVectorRadix); + sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].y), fingerVectorRadix); + sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].z), fingerVectorRadix); + } + _handData->decodeRemoteData(fingerVectors); } - for (size_t i = 0; i < numFingerRoots; ++i) { - sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerRoots[i].x), 4); - sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerRoots[i].y), 4); - sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerRoots[i].z), 4); - } - _handData->setFingerTips(fingerTips); - _handData->setFingerRoots(fingerRoots); } // skeleton joints @@ -430,4 +409,3 @@ int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy) { value = ((float)holder / (float) 255) * scaleBy; return sizeof(holder); } - diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 1724b8d73a..209d822426 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -29,7 +29,6 @@ const int WANT_OCCLUSION_CULLING_BIT = 7; // 8th bit const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation - enum KeyState { NO_KEY_DOWN = 0, diff --git a/libraries/avatars/src/HandData.cpp b/libraries/avatars/src/HandData.cpp index 986d030a3c..32e83b352d 100755 --- a/libraries/avatars/src/HandData.cpp +++ b/libraries/avatars/src/HandData.cpp @@ -9,7 +9,74 @@ #include "HandData.h" HandData::HandData(AvatarData* owningAvatar) : + _basePosition(0.0f, 0.0f, 0.0f), + _baseOrientation(0.0f, 0.0f, 0.0f, 1.0f), _owningAvatarData(owningAvatar) { - + for (int i = 0; i < 2; ++i) { + _palms.push_back(PalmData(this)); + } } + +PalmData::PalmData(HandData* owningHandData) : +_rawPosition(0, 0, 0), +_rawNormal(0, 1, 0), +_isActive(false), +_owningHandData(owningHandData) +{ + for (int i = 0; i < NUM_FINGERS_PER_HAND; ++i) { + _fingers.push_back(FingerData(this, owningHandData)); + } +} + +FingerData::FingerData(PalmData* owningPalmData, HandData* owningHandData) : +_tipRawPosition(0, 0, 0), +_rootRawPosition(0, 0, 0), +_isActive(false), +_owningPalmData(owningPalmData), +_owningHandData(owningHandData) +{ +} + +void HandData::encodeRemoteData(std::vector& fingerVectors) { + fingerVectors.clear(); + for (size_t i = 0; i < getNumPalms(); ++i) { + PalmData& palm = getPalms()[i]; + fingerVectors.push_back(palm.getRawPosition()); + fingerVectors.push_back(palm.getRawNormal()); + for (size_t f = 0; f < palm.getNumFingers(); ++f) { + FingerData& finger = palm.getFingers()[f]; + if (finger.isActive()) { + fingerVectors.push_back(finger.getTipRawPosition()); + fingerVectors.push_back(finger.getRootRawPosition()); + } + else { + fingerVectors.push_back(glm::vec3(0,0,0)); + fingerVectors.push_back(glm::vec3(0,0,0)); + } + } + } +} + +void HandData::decodeRemoteData(const std::vector& fingerVectors) { + size_t vectorIndex = 0; + for (size_t i = 0; i < getNumPalms(); ++i) { + PalmData& palm = getPalms()[i]; + // If a palm is active, there will be + // 1 vector for its position + // 1 vector for normal + // 10 vectors for fingers (5 tip/root pairs) + bool palmActive = fingerVectors.size() >= i * 12; + palm.setActive(palmActive); + if (palmActive) { + palm.setRawPosition(fingerVectors[vectorIndex++]); + palm.setRawNormal(fingerVectors[vectorIndex++]); + for (size_t f = 0; f < NUM_FINGERS_PER_HAND; ++f) { + FingerData& finger = palm.getFingers()[i]; + finger.setRawTipPosition(fingerVectors[vectorIndex++]); + finger.setRawRootPosition(fingerVectors[vectorIndex++]); + } + } + } +} + diff --git a/libraries/avatars/src/HandData.h b/libraries/avatars/src/HandData.h index 50a4843153..65b32ff5c6 100755 --- a/libraries/avatars/src/HandData.h +++ b/libraries/avatars/src/HandData.h @@ -13,8 +13,13 @@ #include #include +#include class AvatarData; +class FingerData; +class PalmData; + +const int NUM_FINGERS_PER_HAND = 5; class HandData { public: @@ -22,26 +27,79 @@ public: // These methods return the positions in Leap-relative space. // To convert to world coordinates, use Hand::leapPositionToWorldPosition. - const std::vector& getFingerTips() const { return _fingerTips; } - const std::vector& getFingerRoots() const { return _fingerRoots; } - const std::vector& getHandPositions() const { return _handPositions; } - const std::vector& getHandNormals() const { return _handNormals; } - void setFingerTips(const std::vector& fingerTips) { _fingerTips = fingerTips; } - void setFingerRoots(const std::vector& fingerRoots) { _fingerRoots = fingerRoots; } - void setHandPositions(const std::vector& handPositons) { _handPositions = handPositons; } - void setHandNormals(const std::vector& handNormals) { _handNormals = handNormals; } + + // position conversion + glm::vec3 leapPositionToWorldPosition(const glm::vec3& leapPosition) { + const float unitScale = 0.001; // convert mm to meters + return _basePosition + _baseOrientation * (leapPosition * unitScale); + } + glm::vec3 leapDirectionToWorldDirection(const glm::vec3& leapDirection) { + return glm::normalize(_baseOrientation * leapDirection); + } + + std::vector& getPalms() { return _palms; } + size_t getNumPalms() { return _palms.size(); } + + // Use these for sending and receiving hand data + void encodeRemoteData(std::vector& fingerVectors); + void decodeRemoteData(const std::vector& fingerVectors); friend class AvatarData; protected: - std::vector _fingerTips; - std::vector _fingerRoots; - std::vector _handPositions; - std::vector _handNormals; + glm::vec3 _basePosition; // Hands are placed relative to this + glm::quat _baseOrientation; // Hands are placed relative to this AvatarData* _owningAvatarData; + std::vector _palms; private: // privatize copy ctor and assignment operator so copies of this object cannot be made HandData(const HandData&); HandData& operator= (const HandData&); }; +class FingerData { +public: + FingerData(PalmData* owningPalmData, HandData* owningHandData); + + glm::vec3 getTipPosition() const { return _owningHandData->leapPositionToWorldPosition(_tipRawPosition); } + glm::vec3 getRootPosition() const { return _owningHandData->leapPositionToWorldPosition(_rootRawPosition); } + const glm::vec3& getTipRawPosition() const { return _tipRawPosition; } + const glm::vec3& getRootRawPosition() const { return _rootRawPosition; } + bool isActive() const { return _isActive; } + + void setActive(bool active) { _isActive = active; } + void setRawTipPosition(const glm::vec3& pos) { _tipRawPosition = pos; } + void setRawRootPosition(const glm::vec3& pos) { _rootRawPosition = pos; } + +private: + glm::vec3 _tipRawPosition; + glm::vec3 _rootRawPosition; + bool _isActive; // This has current valid data + PalmData* _owningPalmData; + HandData* _owningHandData; +}; + +class PalmData { +public: + PalmData(HandData* owningHandData); + glm::vec3 getPosition() const { return _owningHandData->leapPositionToWorldPosition(_rawPosition); } + glm::vec3 getNormal() const { return _owningHandData->leapDirectionToWorldDirection(_rawNormal); } + const glm::vec3& getRawPosition() const { return _rawPosition; } + const glm::vec3& getRawNormal() const { return _rawNormal; } + bool isActive() const { return _isActive; } + + std::vector& getFingers() { return _fingers; } + size_t getNumFingers() { return _fingers.size(); } + + void setActive(bool active) { _isActive = active; } + void setRawPosition(const glm::vec3& pos) { _rawPosition = pos; } + void setRawNormal(const glm::vec3& normal) { _rawNormal = normal; } + +private: + std::vector _fingers; + glm::vec3 _rawPosition; + glm::vec3 _rawNormal; + bool _isActive; // This has current valid data + HandData* _owningHandData; +}; + #endif /* defined(__hifi__HandData__) */ diff --git a/libraries/shared/CMakeLists.txt b/libraries/shared/CMakeLists.txt index 23f198f730..cf1c603b7d 100644 --- a/libraries/shared/CMakeLists.txt +++ b/libraries/shared/CMakeLists.txt @@ -1,14 +1,13 @@ cmake_minimum_required(VERSION 2.8) +set(ROOT_DIR ../..) +set(MACRO_DIR ${ROOT_DIR}/cmake/macros) + set(TARGET_NAME shared) project(${TARGET_NAME}) -# grab the implemenation and header files -file(GLOB HIFI_SHARED_SRCS src/*.h src/*.cpp) - -# create a library and set the property so it can be referenced later -add_library(${TARGET_NAME} ${HIFI_SHARED_SRCS}) -set(HIFI_SHARED_LIBRARY ${TARGET_NAME}) +include(${MACRO_DIR}/SetupHifiLibrary.cmake) +setup_hifi_library(${TARGET_NAME}) set(EXTERNAL_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/external) diff --git a/libraries/shared/src/Log.cpp b/libraries/shared/src/Log.cpp deleted file mode 100644 index 2db1ab4288..0000000000 --- a/libraries/shared/src/Log.cpp +++ /dev/null @@ -1,15 +0,0 @@ -// -// Log.cpp -// hifi -// -// Created by Tobias Schwinger on 4/17/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include "Log.h" - -#include - -using namespace std; -int (* printLog)(char const*, ...) = & printf; - diff --git a/libraries/shared/src/Log.h b/libraries/shared/src/Log.h deleted file mode 100644 index e2bc77e1e8..0000000000 --- a/libraries/shared/src/Log.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// Log.h -// hifi -// -// Created by Tobias Schwinger on 4/17/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __hifi__shared_Log__ -#define __hifi__shared_Log__ - -// -// Pointer to log function -// -// An application may reset this variable to receive the log messages -// issued using 'printLog'. It defaults to a pointer to 'printf'. -// -extern int (* printLog)(char const*, ...); - -#endif /* defined(__hifi__shared_Log__) */ - diff --git a/libraries/shared/src/Node.cpp b/libraries/shared/src/Node.cpp index f7c9758fd0..d7cf429558 100644 --- a/libraries/shared/src/Node.cpp +++ b/libraries/shared/src/Node.cpp @@ -6,15 +6,9 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#include "stdio.h" - -#include -#include "Node.h" -#include "NodeTypes.h" #include -#include "Log.h" -#include "UDPSocket.h" -#include "SharedUtil.h" +#include +#include #ifdef _WIN32 #include "Syssocket.h" @@ -22,6 +16,13 @@ #include #endif +#include "Node.h" +#include "NodeTypes.h" +#include "SharedUtil.h" +#include "UDPSocket.h" + +#include + int unpackNodeId(unsigned char* packedData, uint16_t* nodeId) { memcpy(nodeId, packedData, sizeof(uint16_t)); return sizeof(uint16_t); @@ -140,18 +141,14 @@ float Node::getAverageKilobitsPerSecond() { } } -void Node::printLog(Node const& node) { - +QDebug operator<<(QDebug debug, const Node &node) { char publicAddressBuffer[16] = {'\0'}; - unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, node._publicSocket); + unsigned short publicAddressPort = loadBufferWithSocketInfo(publicAddressBuffer, node.getPublicSocket()); //char localAddressBuffer[16] = {'\0'}; //unsigned short localAddressPort = loadBufferWithSocketInfo(localAddressBuffer, node.localSocket); - ::printLog("# %d %s (%c) @ %s:%d\n", - node._nodeID, - node.getTypeName(), - node._type, - publicAddressBuffer, - publicAddressPort); + debug << "#" << node.getNodeID() << node.getTypeName() << node.getType(); + debug.nospace() << publicAddressBuffer << ":" << publicAddressPort; + return debug.nospace(); } diff --git a/libraries/shared/src/Node.h b/libraries/shared/src/Node.h index aa88cb158c..46bf90ed43 100644 --- a/libraries/shared/src/Node.h +++ b/libraries/shared/src/Node.h @@ -9,8 +9,8 @@ #ifndef __hifi__Node__ #define __hifi__Node__ -#include #include +#include #ifdef _WIN32 #include "Syssocket.h" @@ -18,8 +18,10 @@ #include #endif -#include "SimpleMovingAverage.h" +#include + #include "NodeData.h" +#include "SimpleMovingAverage.h" class Node { public: @@ -89,8 +91,9 @@ private: pthread_mutex_t _mutex; }; - int unpackNodeId(unsigned char *packedData, uint16_t *nodeId); int packNodeId(unsigned char *packStore, uint16_t nodeId); +QDebug operator<<(QDebug debug, const Node &message); + #endif /* defined(__hifi__Node__) */ diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index 004568584d..91fe1f4a21 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -11,11 +11,12 @@ #include #include +#include + #include "NodeList.h" #include "NodeTypes.h" #include "PacketHeaders.h" #include "SharedUtil.h" -#include "Log.h" #ifdef _WIN32 #include "Syssocket.h" @@ -42,7 +43,7 @@ NodeList* NodeList::createInstance(char ownerType, unsigned int socketListenPort if (!_sharedInstance) { _sharedInstance = new NodeList(ownerType, socketListenPort); } else { - printLog("NodeList createInstance called with existing instance.\n"); + qDebug("NodeList createInstance called with existing instance.\n"); } return _sharedInstance; @@ -50,7 +51,7 @@ NodeList* NodeList::createInstance(char ownerType, unsigned int socketListenPort NodeList* NodeList::getInstance() { if (!_sharedInstance) { - printLog("NodeList getInstance called before call to createInstance. Returning NULL pointer.\n"); + qDebug("NodeList getInstance called before call to createInstance. Returning NULL pointer.\n"); } return _sharedInstance; @@ -274,12 +275,13 @@ void NodeList::sendDomainServerCheckIn() { sockaddr_in tempAddress; memcpy(&tempAddress.sin_addr, pHostInfo->h_addr_list[0], pHostInfo->h_length); strcpy(_domainIP, inet_ntoa(tempAddress.sin_addr)); - printLog("Domain Server: %s \n", _domainHostname); + + qDebug("Domain Server: %s\n", _domainHostname); } else { - printLog("Failed domain server lookup\n"); + qDebug("Failed domain server lookup\n"); } } else if (!printedDomainServerIP) { - printLog("Domain Server IP: %s\n", _domainIP); + qDebug("Domain Server IP: %s\n", _domainIP); printedDomainServerIP = true; } @@ -418,8 +420,7 @@ void NodeList::addNodeToList(Node* newNode) { ++_numNodes; - printLog("Added "); - Node::printLog(*newNode); + qDebug() << "Added" << *newNode << "\n"; } unsigned NodeList::broadcastToNodes(unsigned char *broadcastData, size_t dataBytes, const char* nodeTypes, int numNodeTypes) { @@ -471,11 +472,9 @@ void *removeSilentNodes(void *args) { for(NodeList::iterator node = nodeList->begin(); node != nodeList->end(); ++node) { - if ((checkTimeUSecs - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS - && node->getType() != NODE_TYPE_VOXEL_SERVER) { + if ((checkTimeUSecs - node->getLastHeardMicrostamp()) > NODE_SILENCE_THRESHOLD_USECS) { - printLog("Killed "); - Node::printLog(*node); + qDebug() << "Killed" << *node << "\n"; node->setAlive(false); } diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index 20eaddc738..0c8a68d38c 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -32,7 +32,7 @@ const int DOMAIN_SERVER_CHECK_IN_USECS = 1 * 1000000; extern const char SOLO_NODE_TYPES[3]; -const int MAX_HOSTNAME_BYTES = 255; +const int MAX_HOSTNAME_BYTES = 256; extern const char DEFAULT_DOMAIN_HOSTNAME[MAX_HOSTNAME_BYTES]; extern const char DEFAULT_DOMAIN_IP[INET_ADDRSTRLEN]; // IP Address will be re-set by lookup on startup diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index e9eaa1c49a..b085a146a2 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -6,14 +6,18 @@ // Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // -#include #include // std:min +#include +#include #include + +#include + #include "SharedUtil.h" #include "OctalCode.h" -#include "Log.h" int numberOfThreeBitSectionsInCode(unsigned char * octalCode) { + assert(octalCode); if (*octalCode == 255) { return *octalCode + numberOfThreeBitSectionsInCode(octalCode + 1); } else { @@ -23,12 +27,12 @@ int numberOfThreeBitSectionsInCode(unsigned char * octalCode) { void printOctalCode(unsigned char * octalCode) { if (!octalCode) { - printLog("NULL\n"); + qDebug("NULL\n"); } else { for (int i = 0; i < bytesRequiredForCodeLength(*octalCode); i++) { outputBits(octalCode[i],false); } - printLog("\n"); + qDebug("\n"); } } diff --git a/libraries/shared/src/PacketHeaders.cpp b/libraries/shared/src/PacketHeaders.cpp index 230ca5bacc..821a2d0247 100644 --- a/libraries/shared/src/PacketHeaders.cpp +++ b/libraries/shared/src/PacketHeaders.cpp @@ -8,13 +8,14 @@ #include +#include + #include "PacketHeaders.h" -#include "Log.h" PACKET_VERSION versionForPacketType(PACKET_TYPE type) { switch (type) { case PACKET_TYPE_HEAD_DATA: - return 1; + return 2; break; default: return 0; @@ -28,7 +29,7 @@ bool packetVersionMatch(unsigned char* packetHeader) { if (packetHeader[1] == versionForPacketType(packetHeader[0])) { return true; } else { - printLog("There is a packet version mismatch for packet with header %c\n", packetHeader[0]); + qDebug("There is a packet version mismatch for packet with header %c\n", packetHeader[0]); return false; } } diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index d3547b384e..86985eb038 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -10,12 +10,13 @@ // // -#include "PerfStat.h" #include -#include #include +#include -#include "Log.h" +#include + +#include "PerfStat.h" // Static class members initialization here! std::map > PerfStat::groupHistoryMap; @@ -58,11 +59,11 @@ PerfStat::~PerfStat() { } if (wantDebugOut) { - printLog("PerfStats: %s elapsed:%f average:%lf count:%ld total:%lf ut:%d us:%d ue:%d t:%ld s:%ld e:%ld\n", - this->group.c_str(),elapsed,average,count,totalTime, - (end.tv_usec-start.tv_usec),start.tv_usec,end.tv_usec, - (end.tv_sec-start.tv_sec),start.tv_sec,end.tv_sec - ); + qDebug("PerfStats: %s elapsed:%f average:%lf count:%ld total:%lf ut:%d us:%d ue:%d t:%ld s:%ld e:%ld\n", + this->group.c_str(),elapsed,average,count,totalTime, + (end.tv_usec-start.tv_usec),start.tv_usec,end.tv_usec, + (end.tv_sec-start.tv_sec),start.tv_sec,end.tv_sec + ); } }; @@ -110,12 +111,12 @@ PerformanceWarning::~PerformanceWarning() { if ((_alwaysDisplay || _renderWarningsOn) && elapsedmsec > 1) { if (elapsedmsec > 1000) { double elapsedsec = (end - _start) / 1000000.0; - printLog("%s%s took %lf seconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedsec); + qDebug("%s%s took %lf seconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedsec); } else { - printLog("%s%s took %lf milliseconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedmsec); + qDebug("%s%s took %lf milliseconds\n", (_alwaysDisplay ? "" : "WARNING!"), _message, elapsedmsec); } } else if (_alwaysDisplay) { - printLog("%s took %lf milliseconds\n", _message, elapsedmsec); + qDebug("%s took %lf milliseconds\n", _message, elapsedmsec); } }; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index eb46458b2c..72b5b02f15 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -20,7 +20,8 @@ #include #endif -#include "Log.h" +#include + #include "OctalCode.h" #include "PacketHeaders.h" #include "SharedUtil.h" @@ -64,24 +65,24 @@ void outputBufferBits(unsigned char* buffer, int length, bool withNewLine) { outputBits(buffer[i], false); } if (withNewLine) { - printLog("\n"); + qDebug("\n"); } } void outputBits(unsigned char byte, bool withNewLine) { if (isalnum(byte)) { - printLog("[ %d (%c): ", byte, byte); + qDebug("[ %d (%c): ", byte, byte); } else { - printLog("[ %d (0x%x): ", byte, byte); + qDebug("[ %d (0x%x): ", byte, byte); } for (int i = 0; i < 8; i++) { - printLog("%d", byte >> (7 - i) & 1); + qDebug("%d", byte >> (7 - i) & 1); } - printLog(" ] "); + qDebug(" ] "); if (withNewLine) { - printLog("\n"); + qDebug("\n"); } } @@ -187,6 +188,10 @@ bool cmdOptionExists(int argc, const char * argv[],const char* option) { return false; } +void sharedMessageHandler(QtMsgType type, const char* message) { + fprintf(stdout, "%s", message); +} + ////////////////////////////////////////////////////////////////////////////////////////// // Function: createVoxelEditMessage() // Description: creates an "insert" or "remove" voxel message for a voxel code @@ -385,14 +390,14 @@ void printVoxelCode(unsigned char* voxelCode) { unsigned int voxelSizeInOctets = (voxelSizeInBits/3); unsigned int voxelBufferSize = voxelSizeInBytes+1+3; // 1 for size, 3 for color - printLog("octets=%d\n",octets); - printLog("voxelSizeInBits=%d\n",voxelSizeInBits); - printLog("voxelSizeInBytes=%d\n",voxelSizeInBytes); - printLog("voxelSizeInOctets=%d\n",voxelSizeInOctets); - printLog("voxelBufferSize=%d\n",voxelBufferSize); + qDebug("octets=%d\n",octets); + qDebug("voxelSizeInBits=%d\n",voxelSizeInBits); + qDebug("voxelSizeInBytes=%d\n",voxelSizeInBytes); + qDebug("voxelSizeInOctets=%d\n",voxelSizeInOctets); + qDebug("voxelBufferSize=%d\n",voxelBufferSize); for(int i=0;i #include #include -#include + +#include #ifdef _WIN32 #include "Systime.h" @@ -66,6 +68,8 @@ void loadRandomIdentifier(unsigned char* identifierBuffer, int numBytes); const char* getCmdOption(int argc, const char * argv[],const char* option); bool cmdOptionExists(int argc, const char * argv[],const char* option); +void sharedMessageHandler(QtMsgType type, const char* message); + struct VoxelDetail { float x; float y; diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index 72f1472eac..0cd8efb723 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -6,10 +6,9 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#include "UDPSocket.h" -#include #include #include +#include #include #ifdef _WIN32 @@ -21,7 +20,9 @@ #include #endif -#include "Log.h" +#include + +#include "UDPSocket.h" sockaddr_in destSockaddr, senderAddress; @@ -123,7 +124,7 @@ UDPSocket::UDPSocket(int listeningPort) : listeningPort(listeningPort), blocking handle = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if (handle <= 0) { - printLog("Failed to create socket.\n"); + qDebug("Failed to create socket.\n"); return; } @@ -136,7 +137,7 @@ UDPSocket::UDPSocket(int listeningPort) : listeningPort(listeningPort), blocking bind_address.sin_port = htons((uint16_t) listeningPort); if (bind(handle, (const sockaddr*) &bind_address, sizeof(sockaddr_in)) < 0) { - printLog("Failed to bind socket to port %d.\n", listeningPort); + qDebug("Failed to bind socket to port %d.\n", listeningPort); return; } @@ -153,7 +154,7 @@ UDPSocket::UDPSocket(int listeningPort) : listeningPort(listeningPort), blocking tv.tv_usec = 500000; setsockopt(handle, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof tv); - printLog("Created UDP socket listening on port %d.\n", listeningPort); + qDebug("Created UDP socket listening on port %d.\n", listeningPort); } UDPSocket::~UDPSocket() { @@ -233,7 +234,7 @@ int UDPSocket::send(sockaddr* destAddress, const void* data, size_t byteLength) 0, (sockaddr *) destAddress, sizeof(sockaddr_in)); if (sent_bytes != byteLength) { - printLog("Failed to send packet: %s\n", strerror(errno)); + qDebug("Failed to send packet: %s\n", strerror(errno)); return false; } diff --git a/libraries/shared/src/UrlReader.cpp b/libraries/shared/src/UrlReader.cpp index 638134f4dd..3f98326726 100644 --- a/libraries/shared/src/UrlReader.cpp +++ b/libraries/shared/src/UrlReader.cpp @@ -6,20 +6,17 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#include "UrlReader.h" - #include #include #include -#include "Log.h" - #ifndef _WIN32 // (Windows port is incomplete and the build files do not support CURL, yet) #include +#include "UrlReader.h" // // ATTENTION: A certain part of the implementation lives in inlined code diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp index d30e0a4290..634c67a71c 100644 --- a/libraries/voxels/src/CoverageMap.cpp +++ b/libraries/voxels/src/CoverageMap.cpp @@ -6,10 +6,13 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#include "CoverageMap.h" -#include #include -#include "Log.h" + +#include + +#include + +#include "CoverageMap.h" int CoverageMap::_mapCount = 0; int CoverageMap::_checkMapRootCalls = 0; @@ -60,7 +63,7 @@ CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygo { _mapCount++; init(); - //printLog("CoverageMap created... _mapCount=%d\n",_mapCount); + //qDebug("CoverageMap created... _mapCount=%d\n",_mapCount); }; CoverageMap::~CoverageMap() { @@ -68,19 +71,19 @@ CoverageMap::~CoverageMap() { }; void CoverageMap::printStats() { - printLog("CoverageMap::printStats()...\n"); - printLog("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE); - printLog("_mapCount=%d\n",_mapCount); - printLog("_checkMapRootCalls=%d\n",_checkMapRootCalls); - printLog("_notAllInView=%d\n",_notAllInView); - printLog("_maxPolygonsUsed=%d\n",CoverageRegion::_maxPolygonsUsed); - printLog("_totalPolygons=%d\n",CoverageRegion::_totalPolygons); - printLog("_occlusionTests=%d\n",CoverageRegion::_occlusionTests); - printLog("_regionSkips=%d\n",CoverageRegion::_regionSkips); - printLog("_tooSmallSkips=%d\n",CoverageRegion::_tooSmallSkips); - printLog("_regionFullSkips=%d\n",CoverageRegion::_regionFullSkips); - printLog("_outOfOrderPolygon=%d\n",CoverageRegion::_outOfOrderPolygon); - printLog("_clippedPolygons=%d\n",CoverageRegion::_clippedPolygons); + qDebug("CoverageMap::printStats()...\n"); + qDebug("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE); + qDebug("_mapCount=%d\n",_mapCount); + qDebug("_checkMapRootCalls=%d\n",_checkMapRootCalls); + qDebug("_notAllInView=%d\n",_notAllInView); + qDebug("_maxPolygonsUsed=%d\n",CoverageRegion::_maxPolygonsUsed); + qDebug("_totalPolygons=%d\n",CoverageRegion::_totalPolygons); + qDebug("_occlusionTests=%d\n",CoverageRegion::_occlusionTests); + qDebug("_regionSkips=%d\n",CoverageRegion::_regionSkips); + qDebug("_tooSmallSkips=%d\n",CoverageRegion::_tooSmallSkips); + qDebug("_regionFullSkips=%d\n",CoverageRegion::_regionFullSkips); + qDebug("_outOfOrderPolygon=%d\n",CoverageRegion::_outOfOrderPolygon); + qDebug("_clippedPolygons=%d\n",CoverageRegion::_clippedPolygons); } void CoverageMap::erase() { @@ -99,7 +102,7 @@ void CoverageMap::erase() { } if (_isRoot && wantDebugging) { - printLog("CoverageMap last to be deleted...\n"); + qDebug("CoverageMap last to be deleted...\n"); printStats(); CoverageRegion::_maxPolygonsUsed = 0; @@ -184,7 +187,7 @@ CoverageMapStorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, b if (_isRoot) { _checkMapRootCalls++; - //printLog("CoverageMap::checkMap()... storeIt=%s\n", debug::valueOf(storeIt)); + //qDebug("CoverageMap::checkMap()... storeIt=%s\n", debug::valueOf(storeIt)); //polygon->printDebugDetails(); } @@ -193,7 +196,7 @@ CoverageMapStorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, b // not in view, then we just discard it with a DOESNT_FIT, this saves us time checking values later. if (!polygon->getAllInView()) { _notAllInView++; - //printLog("CoverageMap2::checkMap()... V2_OCCLUDED\n"); + //qDebug("CoverageMap2::checkMap()... V2_OCCLUDED\n"); return DOESNT_FIT; } @@ -240,9 +243,9 @@ CoverageMapStorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, b /* if (result == STORED) - printLog("CoverageMap2::checkMap()... STORED\n"); + qDebug("CoverageMap2::checkMap()... STORED\n"); else - printLog("CoverageMap2::checkMap()... OCCLUDED\n"); + qDebug("CoverageMap2::checkMap()... OCCLUDED\n"); */ return result; @@ -265,16 +268,16 @@ CoverageMapStorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, b /* switch (result) { case STORED: - printLog("checkMap() = STORED\n"); + qDebug("checkMap() = STORED\n"); break; case NOT_STORED: - printLog("checkMap() = NOT_STORED\n"); + qDebug("checkMap() = NOT_STORED\n"); break; case OCCLUDED: - printLog("checkMap() = OCCLUDED\n"); + qDebug("checkMap() = OCCLUDED\n"); break; default: - printLog("checkMap() = ????? \n"); + qDebug("checkMap() = ????? \n"); break; } */ @@ -287,27 +290,27 @@ CoverageMapStorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, b // any of our child bounding boxes, so we should add it here. if (storeIt) { if (polygon->getBoundingBox().area() > CoverageMap::MINIMUM_POLYGON_AREA_TO_STORE) { - //printLog("storing polygon of area: %f\n",polygon->getBoundingBox().area()); + //qDebug("storing polygon of area: %f\n",polygon->getBoundingBox().area()); if (storeIn->getPolygonCount() < MAX_POLYGONS_PER_REGION) { storeIn->storeInArray(polygon); - //printLog("CoverageMap2::checkMap()... STORED\n"); + //qDebug("CoverageMap2::checkMap()... STORED\n"); return STORED; } else { CoverageRegion::_regionFullSkips++; - //printLog("CoverageMap2::checkMap()... NOT_STORED\n"); + //qDebug("CoverageMap2::checkMap()... NOT_STORED\n"); return NOT_STORED; } } else { CoverageRegion::_tooSmallSkips++; - //printLog("CoverageMap2::checkMap()... NOT_STORED\n"); + //qDebug("CoverageMap2::checkMap()... NOT_STORED\n"); return NOT_STORED; } } else { - //printLog("CoverageMap2::checkMap()... NOT_STORED\n"); + //qDebug("CoverageMap2::checkMap()... NOT_STORED\n"); return NOT_STORED; } } - //printLog("CoverageMap2::checkMap()... DOESNT_FIT\n"); + //qDebug("CoverageMap2::checkMap()... DOESNT_FIT\n"); return DOESNT_FIT; } @@ -338,11 +341,11 @@ void CoverageRegion::erase() { /** if (_polygonCount) { - printLog("CoverageRegion::erase()...\n"); - printLog("_polygonCount=%d\n",_polygonCount); + qDebug("CoverageRegion::erase()...\n"); + qDebug("_polygonCount=%d\n",_polygonCount); _myBoundingBox.printDebugDetails(getRegionName()); //for (int i = 0; i < _polygonCount; i++) { - // printLog("_polygons[%d]=",i); + // qDebug("_polygons[%d]=",i); // _polygons[i]->getBoundingBox().printDebugDetails(); //} } @@ -390,7 +393,7 @@ void CoverageRegion::growPolygonArray() { _polygonDistances = newDistances; _polygonSizes = newSizes; _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; - //printLog("CoverageMap::growPolygonArray() _polygonArraySize=%d...\n",_polygonArraySize); + //qDebug("CoverageMap::growPolygonArray() _polygonArraySize=%d...\n",_polygonArraySize); } const char* CoverageRegion::getRegionName() const { @@ -427,15 +430,15 @@ bool CoverageRegion::mergeItemsInArray(VoxelProjectedPolygon* seed, bool seedInA otherPolygon->merge(*seed); if (seedInArray) { - const int IGNORED = NULL; + int* IGNORED_ADDRESS = NULL; // remove this otherOtherPolygon for our polygon array _polygonCount = removeFromSortedArrays((void*)seed, - (void**)_polygons, _polygonDistances, IGNORED, + (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, _polygonCount, _polygonArraySize); _totalPolygons--; } - //printLog("_polygonCount=%d\n",_polygonCount); + //qDebug("_polygonCount=%d\n",_polygonCount); // clean up if (_managePolygons) { @@ -476,31 +479,31 @@ void CoverageRegion::storeInArray(VoxelProjectedPolygon* polygon) { // in the list. We still check to see if the polygon is "in front" of the target polygon before we test occlusion. Since // sometimes things come out of order. const bool SORT_BY_SIZE = false; - const int IGNORED = NULL; + const int IGNORED = 0; + int* IGNORED_ADDRESS = NULL; if (SORT_BY_SIZE) { // This old code assumes that polygons will always be added in z-buffer order, but that doesn't seem to // be a good assumption. So instead, we will need to sort this by distance. Use a binary search to find the // insertion point in this array, and shift the array accordingly float area = polygon->getBoundingBox().area(); float reverseArea = 4.0f - area; - //printLog("store by size area=%f reverse area=%f\n", area, reverseArea); + //qDebug("store by size area=%f reverse area=%f\n", area, reverseArea); _polygonCount = insertIntoSortedArrays((void*)polygon, reverseArea, IGNORED, - (void**)_polygons, _polygonSizes, IGNORED, + (void**)_polygons, _polygonSizes, IGNORED_ADDRESS, _polygonCount, _polygonArraySize); } else { - const int IGNORED = NULL; _polygonCount = insertIntoSortedArrays((void*)polygon, polygon->getDistance(), IGNORED, - (void**)_polygons, _polygonDistances, IGNORED, + (void**)_polygons, _polygonDistances, IGNORED_ADDRESS, _polygonCount, _polygonArraySize); } // Debugging and Optimization Tuning code. if (_polygonCount > _maxPolygonsUsed) { _maxPolygonsUsed = _polygonCount; - //printLog("CoverageRegion new _maxPolygonsUsed reached=%d region=%s\n",_maxPolygonsUsed, getRegionName()); + //qDebug("CoverageRegion new _maxPolygonsUsed reached=%d region=%s\n",_maxPolygonsUsed, getRegionName()); //_myBoundingBox.printDebugDetails("map._myBoundingBox"); } else { - //printLog("CoverageRegion::storeInArray() _polygonCount=%d region=%s\n",_polygonCount, getRegionName()); + //qDebug("CoverageRegion::storeInArray() _polygonCount=%d region=%s\n",_polygonCount, getRegionName()); } } diff --git a/libraries/voxels/src/CoverageMapV2.cpp b/libraries/voxels/src/CoverageMapV2.cpp index f5591bb324..0e382d7f12 100644 --- a/libraries/voxels/src/CoverageMapV2.cpp +++ b/libraries/voxels/src/CoverageMapV2.cpp @@ -7,11 +7,13 @@ // #include +#include + +#include + +#include #include "CoverageMapV2.h" -#include -#include -#include "Log.h" int CoverageMapV2::_mapCount = 0; int CoverageMapV2::_checkMapRootCalls = 0; @@ -59,7 +61,7 @@ CoverageMapV2::CoverageMapV2(BoundingBox boundingBox, bool isRoot, bool isCovere { _mapCount++; init(); - //printLog("CoverageMapV2 created... _mapCount=%d\n",_mapCount); + //qDebug("CoverageMapV2 created... _mapCount=%d\n",_mapCount); }; CoverageMapV2::~CoverageMapV2() { @@ -76,11 +78,11 @@ void CoverageMapV2::erase() { } if (_isRoot && wantDebugging) { - printLog("CoverageMapV2 last to be deleted...\n"); - printLog("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE); - printLog("_mapCount=%d\n",_mapCount); - printLog("_checkMapRootCalls=%d\n",_checkMapRootCalls); - printLog("_notAllInView=%d\n",_notAllInView); + qDebug("CoverageMapV2 last to be deleted...\n"); + qDebug("MINIMUM_POLYGON_AREA_TO_STORE=%f\n",MINIMUM_POLYGON_AREA_TO_STORE); + qDebug("_mapCount=%d\n",_mapCount); + qDebug("_checkMapRootCalls=%d\n",_checkMapRootCalls); + qDebug("_notAllInView=%d\n",_notAllInView); _mapCount = 0; _checkMapRootCalls = 0; _notAllInView = 0; diff --git a/libraries/voxels/src/GeometryUtil.cpp b/libraries/voxels/src/GeometryUtil.cpp index af2a6dfc95..894f43ee3c 100644 --- a/libraries/voxels/src/GeometryUtil.cpp +++ b/libraries/voxels/src/GeometryUtil.cpp @@ -7,7 +7,8 @@ #include -#include +#include + #include #include "GeometryUtil.h" diff --git a/libraries/voxels/src/Plane.cpp b/libraries/voxels/src/Plane.cpp index 5a99bf29c4..0a1a7ed86c 100755 --- a/libraries/voxels/src/Plane.cpp +++ b/libraries/voxels/src/Plane.cpp @@ -12,8 +12,6 @@ #include -#include "Log.h" - // These are some useful utilities that vec3 is missing void printVec3(const char* name, const glm::vec3& v) { printf("%s x=%f y=%f z=%f\n", name, v.x, v.y, v.z); diff --git a/libraries/voxels/src/Tags.cpp b/libraries/voxels/src/Tags.cpp index 8f7dab5390..e6875f36a6 100644 --- a/libraries/voxels/src/Tags.cpp +++ b/libraries/voxels/src/Tags.cpp @@ -6,14 +6,13 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#include "Tags.h" -#include - -#include -#include - #include +#include +#include + +#include "Tags.h" + Tag::Tag(int tagId, std::stringstream &ss) : _tagId(tagId) { int size = ss.get() << 8 | ss.get(); diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index dd4562cd8d..c13da815f8 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -3,24 +3,23 @@ // hifi // // Created by Brad Hefta-Gaub on 04/11/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // // Simple view frustum class. // -// #include #include -#include "SharedUtil.h" -#include "Log.h" +#include #include "CoverageMap.h" #include "GeometryUtil.h" +#include "SharedUtil.h" #include "ViewFrustum.h" #include "VoxelConstants.h" - using namespace std; ViewFrustum::ViewFrustum() : @@ -323,40 +322,40 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const { testMatches(compareTo._eyeOffsetOrientation, _eyeOffsetOrientation); if (!result && debug) { - printLog("ViewFrustum::matches()... result=%s\n", debug::valueOf(result)); - printLog("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f\n", + qDebug("ViewFrustum::matches()... result=%s\n", debug::valueOf(result)); + qDebug("%s -- compareTo._position=%f,%f,%f _position=%f,%f,%f\n", (testMatches(compareTo._position,_position) ? "MATCHES " : "NO MATCH"), compareTo._position.x, compareTo._position.y, compareTo._position.z, _position.x, _position.y, _position.z ); - printLog("%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f\n", + qDebug("%s -- compareTo._direction=%f,%f,%f _direction=%f,%f,%f\n", (testMatches(compareTo._direction, _direction) ? "MATCHES " : "NO MATCH"), compareTo._direction.x, compareTo._direction.y, compareTo._direction.z, _direction.x, _direction.y, _direction.z ); - printLog("%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f\n", + qDebug("%s -- compareTo._up=%f,%f,%f _up=%f,%f,%f\n", (testMatches(compareTo._up, _up) ? "MATCHES " : "NO MATCH"), compareTo._up.x, compareTo._up.y, compareTo._up.z, _up.x, _up.y, _up.z ); - printLog("%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f\n", + qDebug("%s -- compareTo._right=%f,%f,%f _right=%f,%f,%f\n", (testMatches(compareTo._right, _right) ? "MATCHES " : "NO MATCH"), compareTo._right.x, compareTo._right.y, compareTo._right.z, _right.x, _right.y, _right.z ); - printLog("%s -- compareTo._fieldOfView=%f _fieldOfView=%f\n", + qDebug("%s -- compareTo._fieldOfView=%f _fieldOfView=%f\n", (testMatches(compareTo._fieldOfView, _fieldOfView) ? "MATCHES " : "NO MATCH"), compareTo._fieldOfView, _fieldOfView); - printLog("%s -- compareTo._aspectRatio=%f _aspectRatio=%f\n", + qDebug("%s -- compareTo._aspectRatio=%f _aspectRatio=%f\n", (testMatches(compareTo._aspectRatio, _aspectRatio) ? "MATCHES " : "NO MATCH"), compareTo._aspectRatio, _aspectRatio); - printLog("%s -- compareTo._nearClip=%f _nearClip=%f\n", + qDebug("%s -- compareTo._nearClip=%f _nearClip=%f\n", (testMatches(compareTo._nearClip, _nearClip) ? "MATCHES " : "NO MATCH"), compareTo._nearClip, _nearClip); - printLog("%s -- compareTo._farClip=%f _farClip=%f\n", + qDebug("%s -- compareTo._farClip=%f _farClip=%f\n", (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), compareTo._farClip, _farClip); - printLog("%s -- compareTo._eyeOffsetPosition=%f,%f,%f _eyeOffsetPosition=%f,%f,%f\n", + qDebug("%s -- compareTo._eyeOffsetPosition=%f,%f,%f _eyeOffsetPosition=%f,%f,%f\n", (testMatches(compareTo._eyeOffsetPosition, _eyeOffsetPosition) ? "MATCHES " : "NO MATCH"), compareTo._eyeOffsetPosition.x, compareTo._eyeOffsetPosition.y, compareTo._eyeOffsetPosition.z, _eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z); - printLog("%s -- compareTo._eyeOffsetOrientation=%f,%f,%f,%f _eyeOffsetOrientation=%f,%f,%f,%f\n", + qDebug("%s -- compareTo._eyeOffsetOrientation=%f,%f,%f,%f _eyeOffsetOrientation=%f,%f,%f,%f\n", (testMatches(compareTo._eyeOffsetOrientation, _eyeOffsetOrientation) ? "MATCHES " : "NO MATCH"), compareTo._eyeOffsetOrientation.x, compareTo._eyeOffsetOrientation.y, compareTo._eyeOffsetOrientation.z, compareTo._eyeOffsetOrientation.w, @@ -419,17 +418,17 @@ void ViewFrustum::computeOffAxisFrustum(float& left, float& right, float& bottom } void ViewFrustum::printDebugDetails() const { - printLog("ViewFrustum::printDebugDetails()... \n"); - printLog("_position=%f,%f,%f\n", _position.x, _position.y, _position.z ); - printLog("_direction=%f,%f,%f\n", _direction.x, _direction.y, _direction.z ); - printLog("_up=%f,%f,%f\n", _up.x, _up.y, _up.z ); - printLog("_right=%f,%f,%f\n", _right.x, _right.y, _right.z ); - printLog("_fieldOfView=%f\n", _fieldOfView); - printLog("_aspectRatio=%f\n", _aspectRatio); - printLog("_nearClip=%f\n", _nearClip); - printLog("_farClip=%f\n", _farClip); - printLog("_eyeOffsetPosition=%f,%f,%f\n", _eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z ); - printLog("_eyeOffsetOrientation=%f,%f,%f,%f\n", _eyeOffsetOrientation.x, _eyeOffsetOrientation.y, _eyeOffsetOrientation.z, + qDebug("ViewFrustum::printDebugDetails()... \n"); + qDebug("_position=%f,%f,%f\n", _position.x, _position.y, _position.z ); + qDebug("_direction=%f,%f,%f\n", _direction.x, _direction.y, _direction.z ); + qDebug("_up=%f,%f,%f\n", _up.x, _up.y, _up.z ); + qDebug("_right=%f,%f,%f\n", _right.x, _right.y, _right.z ); + qDebug("_fieldOfView=%f\n", _fieldOfView); + qDebug("_aspectRatio=%f\n", _aspectRatio); + qDebug("_nearClip=%f\n", _nearClip); + qDebug("_farClip=%f\n", _farClip); + qDebug("_eyeOffsetPosition=%f,%f,%f\n", _eyeOffsetPosition.x, _eyeOffsetPosition.y, _eyeOffsetPosition.z ); + qDebug("_eyeOffsetOrientation=%f,%f,%f,%f\n", _eyeOffsetOrientation.x, _eyeOffsetOrientation.y, _eyeOffsetOrientation.z, _eyeOffsetOrientation.w ); } diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index e364816c59..188b85c0de 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -3,18 +3,20 @@ // hifi // // Created by Brad Hefta-Gaub on 04/11/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // // Simple view frustum class. // -// #ifndef __hifi__ViewFrustum__ #define __hifi__ViewFrustum__ #include #include -#include "Plane.h" + #include "AABox.h" +#include "Plane.h" + #include "VoxelProjectedPolygon.h" const float DEFAULT_KEYHOLE_RADIUS = 3.0f; @@ -135,7 +137,7 @@ private: glm::vec3 _nearBottomLeft; glm::vec3 _nearBottomRight; enum { TOP_PLANE = 0, BOTTOM_PLANE, LEFT_PLANE, RIGHT_PLANE, NEAR_PLANE, FAR_PLANE }; - Plane _planes[6]; // How will this be used? + ::Plane _planes[6]; // How will this be used? const char* debugPlaneName (int plane) const; diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 421c03f3b6..55dff0c69a 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -21,8 +21,10 @@ const glm::vec3 IDENTITY_UP = glm::vec3( 0.0f, 1.0f, 0.0f); const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f,-1.0f); const bool LOW_RES_MONO = false; // while in "low res mode" do voxels switch to monochrome +const uint64_t CHANGE_FUDGE = 1000 * 200; // useconds of fudge in determining if we want to resend changed voxels -const int TREE_SCALE = 128; +const int TREE_SCALE = 128; // This is the number of meters of the 0.0 to 1.0 voxel universe +const float VOXEL_SIZE_SCALE = 50000.0f; // This controls the LOD bigger will make smaller voxels visible at greater distance const int NUMBER_OF_CHILDREN = 8; const int MAX_VOXEL_PACKET_SIZE = 1492; @@ -39,4 +41,4 @@ const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX; const float SIXTY_FPS_IN_MILLISECONDS = 1000.0f / 60.0f; const float VIEW_CULLING_RATE_IN_MILLISECONDS = 1000.0f; // once a second is fine -#endif +#endif \ No newline at end of file diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 61a174f90b..1268449ac6 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -3,19 +3,21 @@ // hifi // // Created by Stephen Birarda on 3/13/13. -// +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // -#include #include #include +#include + +#include + +#include "AABox.h" +#include "OctalCode.h" #include "SharedUtil.h" -#include "Log.h" +#include "VoxelConstants.h" #include "VoxelNode.h" #include "VoxelTree.h" -#include "VoxelConstants.h" -#include "OctalCode.h" -#include "AABox.h" VoxelNode::VoxelNode() { unsigned char* rootCode = new unsigned char[1]; @@ -52,6 +54,8 @@ void VoxelNode::init(unsigned char * octalCode) { } VoxelNode::~VoxelNode() { + notifyDeleteHooks(); + delete[] _octalCode; // delete all of this node's children @@ -257,7 +261,7 @@ bool VoxelNode::collapseIdenticalLeaves() { // if no child, child isn't a leaf, or child doesn't have a color if (!_children[i] || _children[i]->isStagedForDeletion() || !_children[i]->isLeaf() || !_children[i]->isColored()) { allChildrenMatch=false; - //printLog("SADNESS child missing or not colored! i=%d\n",i); + //qDebug("SADNESS child missing or not colored! i=%d\n",i); break; } else { if (i==0) { @@ -274,7 +278,7 @@ bool VoxelNode::collapseIdenticalLeaves() { if (allChildrenMatch) { - //printLog("allChildrenMatch: pruning tree\n"); + //qDebug("allChildrenMatch: pruning tree\n"); for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { delete _children[i]; // delete all the child nodes _children[i]=NULL; // set it to NULL @@ -308,13 +312,13 @@ void VoxelNode::printDebugDetails(const char* label) const { } } - printLog("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isColored=%s (%d,%d,%d,%d) isDirty=%s shouldRender=%s\n children=", label, + qDebug("%s - Voxel at corner=(%f,%f,%f) size=%f\n isLeaf=%s isColored=%s (%d,%d,%d,%d) isDirty=%s shouldRender=%s\n children=", label, _box.getCorner().x, _box.getCorner().y, _box.getCorner().z, _box.getSize().x, debug::valueOf(isLeaf()), debug::valueOf(isColored()), getColor()[0], getColor()[1], getColor()[2], getColor()[3], debug::valueOf(isDirty()), debug::valueOf(getShouldRender())); outputBits(childBits, false); - printLog("\n octalCode="); + qDebug("\n octalCode="); printOctalCode(_octalCode); } @@ -385,3 +389,44 @@ float VoxelNode::distanceToPoint(const glm::vec3& point) const { float distance = sqrtf(glm::dot(temp, temp)); return distance; } + +VoxelNodeDeleteHook VoxelNode::_hooks[VOXEL_NODE_MAX_DELETE_HOOKS]; +void* VoxelNode::_hooksExtraData[VOXEL_NODE_MAX_DELETE_HOOKS]; +int VoxelNode::_hooksInUse = 0; + +int VoxelNode::addDeleteHook(VoxelNodeDeleteHook hook, void* extraData) { + // If first use, initialize the _hooks array + if (_hooksInUse == 0) { + memset(_hooks, 0, sizeof(_hooks)); + memset(_hooksExtraData, 0, sizeof(_hooksExtraData)); + } + // find first available slot + for (int i = 0; i < VOXEL_NODE_MAX_DELETE_HOOKS; i++) { + if (!_hooks[i]) { + _hooks[i] = hook; + _hooksExtraData[i] = extraData; + _hooksInUse++; + return i; + } + } + // if we got here, then we're out of room in our hooks, return error + return VOXEL_NODE_NO_MORE_HOOKS_AVAILABLE; +} + +void VoxelNode::removeDeleteHook(int hookID) { + if (_hooks[hookID]) { + _hooks[hookID] = NULL; + _hooksExtraData[hookID] = NULL; + _hooksInUse--; + } +} + +void VoxelNode::notifyDeleteHooks() { + if (_hooksInUse > 0) { + for (int i = 0; i < VOXEL_NODE_MAX_DELETE_HOOKS; i++) { + if (_hooks[i]) { + _hooks[i](this, _hooksExtraData[i]); + } + } + } +} diff --git a/libraries/voxels/src/VoxelNode.h b/libraries/voxels/src/VoxelNode.h index 461a723a8a..431592c2f9 100644 --- a/libraries/voxels/src/VoxelNode.h +++ b/libraries/voxels/src/VoxelNode.h @@ -15,33 +15,19 @@ #include "VoxelConstants.h" class VoxelTree; // forward delclaration +class VoxelNode; // forward delclaration typedef unsigned char colorPart; typedef unsigned char nodeColor[4]; typedef unsigned char rgbColor[3]; +// Callback function, for delete hook +typedef void (*VoxelNodeDeleteHook)(VoxelNode* node, void* extraData); +const int VOXEL_NODE_MAX_DELETE_HOOKS = 100; +const int VOXEL_NODE_NO_MORE_HOOKS_AVAILABLE = -1; + + class VoxelNode { -private: - nodeColor _trueColor; -#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color - nodeColor _currentColor; - bool _falseColored; -#endif - glBufferIndex _glBufferIndex; - bool _isDirty; - uint64_t _lastChanged; - bool _shouldRender; - bool _isStagedForDeletion; - AABox _box; - unsigned char* _octalCode; - VoxelNode* _children[8]; - int _childCount; - float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside - - void calculateAABox(); - - void init(unsigned char * octalCode); - public: VoxelNode(); // root node constructor VoxelNode(unsigned char * octalCode); // regular constructor @@ -85,6 +71,7 @@ public: void clearDirtyBit() { _isDirty = false; }; bool hasChangedSince(uint64_t time) const { return (_lastChanged > time); }; void markWithChangedTime() { _lastChanged = usecTimestampNow(); }; + uint64_t getLastChanged() const { return _lastChanged; }; void handleSubtreeChanged(VoxelTree* myTree); glBufferIndex getBufferIndex() const { return _glBufferIndex; }; @@ -117,6 +104,33 @@ public: const nodeColor& getTrueColor() const { return _trueColor; }; const nodeColor& getColor() const { return _trueColor; }; #endif + + static int addDeleteHook(VoxelNodeDeleteHook hook, void* extraData = NULL); + static void removeDeleteHook(int hookID); +private: + void calculateAABox(); + void init(unsigned char * octalCode); + void notifyDeleteHooks(); + + nodeColor _trueColor; +#ifndef NO_FALSE_COLOR // !NO_FALSE_COLOR means, does have false color + nodeColor _currentColor; + bool _falseColored; +#endif + glBufferIndex _glBufferIndex; + bool _isDirty; + uint64_t _lastChanged; + bool _shouldRender; + bool _isStagedForDeletion; + AABox _box; + unsigned char* _octalCode; + VoxelNode* _children[8]; + int _childCount; + float _density; // If leaf: density = 1, if internal node: 0-1 density of voxels inside + + static VoxelNodeDeleteHook _hooks[VOXEL_NODE_MAX_DELETE_HOOKS]; + static void* _hooksExtraData[VOXEL_NODE_MAX_DELETE_HOOKS]; + static int _hooksInUse; }; #endif /* defined(__hifi__VoxelNode__) */ diff --git a/libraries/voxels/src/VoxelNodeBag.cpp b/libraries/voxels/src/VoxelNodeBag.cpp index 20a469dec8..4f355116e4 100644 --- a/libraries/voxels/src/VoxelNodeBag.cpp +++ b/libraries/voxels/src/VoxelNodeBag.cpp @@ -9,7 +9,15 @@ #include "VoxelNodeBag.h" #include +VoxelNodeBag::VoxelNodeBag() : + _bagElements(NULL), + _elementsInUse(0), + _sizeOfElementsArray(0) { + _hookID = VoxelNode::addDeleteHook(voxelNodeDeleteHook, (void*)this); +}; + VoxelNodeBag::~VoxelNodeBag() { + VoxelNode::removeDeleteHook(_hookID); deleteAll(); } @@ -118,3 +126,9 @@ void VoxelNodeBag::remove(VoxelNode* node) { } } +void VoxelNodeBag::voxelNodeDeleteHook(VoxelNode* node, void* extraData) { + VoxelNodeBag* theBag = (VoxelNodeBag*)extraData; + theBag->remove(node); // note: remove can safely handle nodes that aren't in it, so we don't need to check contains() +} + + diff --git a/libraries/voxels/src/VoxelNodeBag.h b/libraries/voxels/src/VoxelNodeBag.h index ee6e5045d0..27bd4e5b60 100644 --- a/libraries/voxels/src/VoxelNodeBag.h +++ b/libraries/voxels/src/VoxelNodeBag.h @@ -19,11 +19,7 @@ class VoxelNodeBag { public: - VoxelNodeBag() : - _bagElements(NULL), - _elementsInUse(0), - _sizeOfElementsArray(0) {}; - + VoxelNodeBag(); ~VoxelNodeBag(); void insert(VoxelNode* node); // put a node into the bag @@ -36,11 +32,14 @@ public: void deleteAll(); + static void voxelNodeDeleteHook(VoxelNode* node, void* extraData); + private: VoxelNode** _bagElements; int _elementsInUse; int _sizeOfElementsArray; + int _hookID; }; #endif /* defined(__hifi__VoxelNodeBag__) */ diff --git a/libraries/voxels/src/VoxelProjectedPolygon.cpp b/libraries/voxels/src/VoxelProjectedPolygon.cpp index 95c66b6821..8a39d7f358 100644 --- a/libraries/voxels/src/VoxelProjectedPolygon.cpp +++ b/libraries/voxels/src/VoxelProjectedPolygon.cpp @@ -6,10 +6,13 @@ // #include -#include "VoxelProjectedPolygon.h" + +#include + #include "GeometryUtil.h" -#include "Log.h" #include "SharedUtil.h" +#include "VoxelProjectedPolygon.h" + glm::vec2 BoundingBox::getVertex(int vertexNumber) const { switch (vertexNumber) { @@ -88,11 +91,11 @@ void BoundingBox::explandToInclude(const BoundingBox& box) { void BoundingBox::printDebugDetails(const char* label) const { if (label) { - printLog(label); + qDebug() << label; } else { - printLog("BoundingBox"); + qDebug("BoundingBox"); } - printLog("\n _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]\n", + qDebug("\n _set=%s\n corner=%f,%f size=%f,%f\n bounds=[(%f,%f) to (%f,%f)]\n", debug::valueOf(_set), corner.x, corner.y, size.x, size.y, corner.x, corner.y, corner.x+size.x, corner.y+size.y); } diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 66fa81c425..9cb6a85f93 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -9,33 +9,34 @@ #ifdef _WIN32 #define _USE_MATH_DEFINES #endif + #include #include #include -#include "SharedUtil.h" -#include "Log.h" -#include "PacketHeaders.h" -#include "OctalCode.h" -#include "GeometryUtil.h" -#include "VoxelTree.h" -#include "VoxelNodeBag.h" -#include "ViewFrustum.h" #include // to load voxels from file -#include "VoxelConstants.h" -#include "CoverageMap.h" -#include "SquarePixelMap.h" -#include "Tags.h" - #include +#include + +#include "CoverageMap.h" +#include "GeometryUtil.h" +#include "OctalCode.h" +#include "PacketHeaders.h" +#include "SharedUtil.h" +#include "SquarePixelMap.h" +#include "Tags.h" +#include "ViewFrustum.h" +#include "VoxelConstants.h" +#include "VoxelNodeBag.h" +#include "VoxelTree.h" + float boundaryDistanceForRenderLevel(unsigned int renderLevel) { - const float voxelSizeScale = 50000.0f; - return voxelSizeScale / powf(2, renderLevel); + return ::VOXEL_SIZE_SCALE / powf(2, renderLevel); } float boundaryDistanceSquaredForRenderLevel(unsigned int renderLevel) { - const float voxelSizeScale = (50000.0f/TREE_SCALE) * (50000.0f/TREE_SCALE); + const float voxelSizeScale = (::VOXEL_SIZE_SCALE/TREE_SCALE) * (::VOXEL_SIZE_SCALE/TREE_SCALE); return voxelSizeScale / powf(2, (2 * renderLevel)); } @@ -155,7 +156,7 @@ void VoxelTree::recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseV if (childNode) { // chance to optimize, doesn't need to be actual distance!! Could be distance squared float distanceSquared = childNode->distanceSquareToPoint(point); - //printLog("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance); + //qDebug("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance); //childNode->printDebugDetails(""); currentCount = insertIntoSortedArrays((void*)childNode, distanceSquared, i, (void**)&sortedChildren, (float*)&distancesToChildren, @@ -166,7 +167,7 @@ void VoxelTree::recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseV for (int i = 0; i < currentCount; i++) { VoxelNode* childNode = sortedChildren[i]; if (childNode) { - //printLog("recurseNodeWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]); + //qDebug("recurseNodeWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]); //childNode->printDebugDetails(""); recurseNodeWithOperationDistanceSorted(childNode, operation, point, extraData); } @@ -371,7 +372,6 @@ void VoxelTree::deleteVoxelAt(float x, float y, float z, float s, bool stage) { delete[] octalCode; // cleanup memory } - class DeleteVoxelCodeFromTreeArgs { public: bool stage; @@ -458,7 +458,7 @@ void VoxelTree::deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraDat // isn't a colored leaf, and the child branch doesn't exist, so there's nothing to do below and // we can safely return, ending the recursion and unwinding if (!childNode) { - //printLog("new___deleteVoxelCodeFromTree() child branch doesn't exist, but parent is not a leaf, just unwind\n"); + //qDebug("new___deleteVoxelCodeFromTree() child branch doesn't exist, but parent is not a leaf, just unwind\n"); return; } @@ -546,7 +546,7 @@ void VoxelTree::readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraD } } else { if (!node->isLeaf()) { - printLog("WARNING! operation would require deleting children, add Voxel ignored!\n "); + qDebug("WARNING! operation would require deleting children, add Voxel ignored!\n "); } } @@ -619,13 +619,13 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { } } - printLog("color mask: "); + qDebug("color mask: "); outputBits(colorMask); // output the colors we have for (int j = 0; j < NUMBER_OF_CHILDREN; j++) { if (startNode->getChildAtIndex(j) && startNode->getChildAtIndex(j)->isColored()) { - printLog("color %d : ",j); + qDebug("color %d : ",j); for (int c = 0; c < 3; c++) { outputBits(startNode->getChildAtIndex(j)->getTrueColor()[c],false); } @@ -641,7 +641,7 @@ void VoxelTree::printTreeForDebugging(VoxelNode *startNode) { } } - printLog("child mask: "); + qDebug("child mask: "); outputBits(childMask); if (childMask > 0) { @@ -686,7 +686,7 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { int totalBytesRead = 0; if(file.is_open()) { - printLog("loading file...\n"); + qDebug("loading file...\n"); bool bail = false; while (!file.eof() && !bail) { file.get(octets); @@ -711,14 +711,14 @@ void VoxelTree::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) { file.get(colorRead); blue = (unsigned char)colorRead; - printLog("voxel color from file red:%d, green:%d, blue:%d \n",red,green,blue); + qDebug("voxel color from file red:%d, green:%d, blue:%d \n",red,green,blue); vCount++; int colorRandomizer = wantColorRandomizer ? randIntInRange (-5, 5) : 0; voxelData[lengthInBytes+1] = std::max(0,std::min(255,red + colorRandomizer)); voxelData[lengthInBytes+2] = std::max(0,std::min(255,green + colorRandomizer)); voxelData[lengthInBytes+3] = std::max(0,std::min(255,blue + colorRandomizer)); - printLog("voxel color after rand red:%d, green:%d, blue:%d\n", + qDebug("voxel color after rand red:%d, green:%d, blue:%d\n", voxelData[lengthInBytes+1], voxelData[lengthInBytes+2], voxelData[lengthInBytes+3]); //printVoxelCode(voxelData); @@ -819,7 +819,7 @@ void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float v if (debug) { int percentComplete = 100 * (thisRadius/radius); - printLog("percentComplete=%d\n",percentComplete); + qDebug("percentComplete=%d\n",percentComplete); } for (float theta=0.0; theta <= 2 * M_PI; theta += angleDelta) { @@ -835,7 +835,7 @@ void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float v // 2) In all modes, we will use our "outer" color to draw the voxels. Otherwise we will use the average color if (lastLayer) { if (false && debug) { - printLog("adding candy shell: theta=%f phi=%f thisRadius=%f radius=%f\n", + qDebug("adding candy shell: theta=%f phi=%f thisRadius=%f radius=%f\n", theta, phi, thisRadius,radius); } switch (mode) { @@ -859,7 +859,7 @@ void VoxelTree::createSphere(float radius, float xc, float yc, float zc, float v green = (unsigned char)std::min(255, std::max(0, (int)(g1 + ((g2 - g1) * gradient)))); blue = (unsigned char)std::min(255, std::max(0, (int)(b1 + ((b2 - b1) * gradient)))); if (debug) { - printLog("perlin=%f gradient=%f color=(%d,%d,%d)\n",perlin, gradient, red, green, blue); + qDebug("perlin=%f gradient=%f color=(%d,%d,%d)\n",perlin, gradient, red, green, blue); } } break; } @@ -1003,17 +1003,18 @@ bool VoxelTree::findCapsulePenetration(const glm::vec3& start, const glm::vec3& return args.found; } + int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, EncodeBitstreamParams& params) const { // How many bytes have we written so far at this level; int bytesWritten = 0; - + // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! if (params.viewFrustum && !node->isInView(*params.viewFrustum)) { return bytesWritten; } - + // write the octal code int codeLength; if (params.chopLevels) { @@ -1072,7 +1073,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp if (currentEncodeLevel >= params.maxEncodeLevel) { return bytesAtThisLevel; } - + // caller can pass NULL as viewFrustum if they want everything if (params.viewFrustum) { float distance = node->distanceToCamera(*params.viewFrustum); @@ -1105,10 +1106,19 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp } } - // If we were in view, then bail out early! - if (wasInView) { + // If we were previously in the view, then we normally will return out of here and stop recursing. But + // if we're in deltaViewFrustum mode, and this node has changed since it was last sent, then we do + // need to send it. + if (wasInView && !(params.deltaViewFrustum && node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))) { return bytesAtThisLevel; - } + } + + // If we're not in delta sending mode, and we weren't asked to do a force send, and the voxel hasn't changed, + // then we can also bail early and save bits + if (!params.forceSendScene && !params.deltaViewFrustum && + !node->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE)) { + return bytesAtThisLevel; + } // If the user also asked for occlusion culling, check if this node is occluded, but only if it's not a leaf. // leaf occlusion is handled down below when we check child nodes @@ -1176,7 +1186,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp if (childNode) { // chance to optimize, doesn't need to be actual distance!! Could be distance squared //float distanceSquared = childNode->distanceSquareToPoint(point); - //printLog("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance); + //qDebug("recurseNodeWithOperationDistanceSorted() CHECKING child[%d] point=%f,%f center=%f,%f distance=%f...\n", i, point.x, point.y, center.x, center.y, distance); //childNode->printDebugDetails(""); float distance = params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; @@ -1268,8 +1278,12 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp } } - // If our child wasn't in view (or we're ignoring wasInView) then we add it to our sending items - if (!childWasInView) { + // If our child wasn't in view (or we're ignoring wasInView) then we add it to our sending items. + // Or if we were previously in the view, but this node has changed since it was last sent, then we do + // need to send it. + if (!childWasInView || + (params.deltaViewFrustum && + childNode->hasChangedSince(params.lastViewFrustumSent - CHANGE_FUDGE))){ childrenColoredBits += (1 << (7 - originalIndex)); inViewWithColorCount++; } else { @@ -1353,7 +1367,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp if (oneAtBit(childrenExistInPacketBits, originalIndex)) { int thisLevel = currentEncodeLevel; - // remember this for reshuffling recursiveSliceStarts[originalIndex] = outputBuffer; @@ -1432,7 +1445,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp bool VoxelTree::readFromSVOFile(const char* fileName) { std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate); if(file.is_open()) { - printLog("loading file %s...\n", fileName); + qDebug("loading file %s...\n", fileName); // get file length.... unsigned long fileLength = file.tellg(); @@ -1460,14 +1473,14 @@ bool VoxelTree::readFromSchematicFile(const char *fileName) { std::stringstream ss; int err = retrieveData(fileName, ss); if (err && ss.get() != TAG_Compound) { - printLog("[ERROR] Invalid schematic file.\n"); + qDebug("[ERROR] Invalid schematic file.\n"); return false; } ss.get(); TagCompound schematics(ss); if (!schematics.getBlocksId() || !schematics.getBlocksData()) { - printLog("[ERROR] Invalid schematic file.\n"); + qDebug("[ERROR] Invalid schematic file.\n"); return false; } @@ -1530,7 +1543,7 @@ bool VoxelTree::readFromSchematicFile(const char *fileName) { } } - printLog("Created %d voxels from minecraft import.\n", count); + qDebug("Created %d voxels from minecraft import.\n", count); return true; } @@ -1540,7 +1553,7 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) const { std::ofstream file(fileName, std::ios::out|std::ios::binary); if(file.is_open()) { - printLog("saving to file %s...\n", fileName); + qDebug("saving to file %s...\n", fileName); VoxelNodeBag nodeBag; // If we were given a specific node, start from there, otherwise start from root diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 9c8e6e7d16..e5db6526e9 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -35,6 +35,7 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; #define DONT_CHOP 0 #define NO_BOUNDARY_ADJUST 0 #define LOW_RES_MOVING_ADJUST 1 +#define IGNORE_LAST_SENT 0 class EncodeBitstreamParams { public: @@ -49,7 +50,8 @@ public: bool wantOcclusionCulling; long childWasInViewDiscarded; int boundaryLevelAdjust; - + uint64_t lastViewFrustumSent; + bool forceSendScene; CoverageMap* map; EncodeBitstreamParams( @@ -62,7 +64,9 @@ public: const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, bool wantOcclusionCulling= NO_OCCLUSION_CULLING, CoverageMap* map = IGNORE_COVERAGE_MAP, - int boundaryLevelAdjust = NO_BOUNDARY_ADJUST) : + int boundaryLevelAdjust = NO_BOUNDARY_ADJUST, + uint64_t lastViewFrustumSent = IGNORE_LAST_SENT, + bool forceSendScene = true) : maxEncodeLevel (maxEncodeLevel), maxLevelReached (0), viewFrustum (viewFrustum), @@ -74,6 +78,8 @@ public: wantOcclusionCulling (wantOcclusionCulling), childWasInViewDiscarded (0), boundaryLevelAdjust (boundaryLevelAdjust), + lastViewFrustumSent (lastViewFrustumSent), + forceSendScene (forceSendScene), map (map) {} }; diff --git a/pairing-server/CMakeLists.txt b/pairing-server/CMakeLists.txt index 9feb1aa424..5e0adcb378 100644 --- a/pairing-server/CMakeLists.txt +++ b/pairing-server/CMakeLists.txt @@ -6,7 +6,7 @@ set(MACRO_DIR ${ROOT_DIR}/cmake/macros) set(TARGET_NAME pairing-server) include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} TRUE) # link the shared hifi library include(${MACRO_DIR}/LinkHifiLibrary.cmake) diff --git a/space-server/CMakeLists.txt b/space-server/CMakeLists.txt index 5b34f86a4c..c821992378 100644 --- a/space-server/CMakeLists.txt +++ b/space-server/CMakeLists.txt @@ -7,7 +7,7 @@ set(TARGET_NAME space-server) include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} TRUE) include(${MACRO_DIR}/LinkHifiLibrary.cmake) link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file diff --git a/voxel-edit/CMakeLists.txt b/voxel-edit/CMakeLists.txt index f7acb26e92..e025099dc5 100644 --- a/voxel-edit/CMakeLists.txt +++ b/voxel-edit/CMakeLists.txt @@ -14,7 +14,7 @@ include_glm(${TARGET_NAME} ${ROOT_DIR}) include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} TRUE) # link in the shared library include(${MACRO_DIR}/LinkHifiLibrary.cmake) diff --git a/voxel-server/CMakeLists.txt b/voxel-server/CMakeLists.txt index 2bdba8f6e3..c401a8033c 100644 --- a/voxel-server/CMakeLists.txt +++ b/voxel-server/CMakeLists.txt @@ -14,7 +14,7 @@ include_glm(${TARGET_NAME} ${ROOT_DIR}) include(${MACRO_DIR}/SetupHifiProject.cmake) -setup_hifi_project(${TARGET_NAME}) +setup_hifi_project(${TARGET_NAME} TRUE) # link in the shared library include(${MACRO_DIR}/LinkHifiLibrary.cmake) diff --git a/voxel-server/src/VoxelNodeData.cpp b/voxel-server/src/VoxelNodeData.cpp index 971b6f8eaa..c4b8ee8b79 100644 --- a/voxel-server/src/VoxelNodeData.cpp +++ b/voxel-server/src/VoxelNodeData.cpp @@ -7,6 +7,7 @@ // #include "PacketHeaders.h" +#include "SharedUtil.h" #include "VoxelNodeData.h" #include #include @@ -19,11 +20,11 @@ VoxelNodeData::VoxelNodeData(Node* owningNode) : _maxLevelReachedInLastSearch(1), _lastTimeBagEmpty(0), _viewFrustumChanging(false), + _viewFrustumJustStoppedChanging(true), _currentPacketIsColor(true) { _voxelPacket = new unsigned char[MAX_VOXEL_PACKET_SIZE]; _voxelPacketAt = _voxelPacket; - resetVoxelPacket(); } @@ -69,10 +70,25 @@ bool VoxelNodeData::updateCurrentViewFrustum() { _currentViewFrustum.calculate(); currentViewFrustumChanged = true; } + + // When we first detect that the view stopped changing, we record this. + // but we don't change it back to false until we've completely sent this + // scene. + if (_viewFrustumChanging && !currentViewFrustumChanged) { + _viewFrustumJustStoppedChanging = true; + } _viewFrustumChanging = currentViewFrustumChanged; return currentViewFrustumChanged; } +void VoxelNodeData::setViewSent(bool viewSent) { + _viewSent = viewSent; + if (viewSent) { + _viewFrustumJustStoppedChanging = false; + } +} + + void VoxelNodeData::updateLastKnownViewFrustum() { bool frustumChanges = !_lastKnownViewFrustum.matches(_currentViewFrustum); @@ -80,5 +96,9 @@ void VoxelNodeData::updateLastKnownViewFrustum() { // save our currentViewFrustum into our lastKnownViewFrustum _lastKnownViewFrustum = _currentViewFrustum; } + + // save that we know the view has been sent. + uint64_t now = usecTimestampNow(); + setLastTimeBagEmpty(now); // is this what we want? poor names } diff --git a/voxel-server/src/VoxelNodeData.h b/voxel-server/src/VoxelNodeData.h index 0f96a07c3d..96b61db963 100644 --- a/voxel-server/src/VoxelNodeData.h +++ b/voxel-server/src/VoxelNodeData.h @@ -48,7 +48,11 @@ public: void updateLastKnownViewFrustum(); bool getViewSent() const { return _viewSent; }; - void setViewSent(bool viewSent) { _viewSent = viewSent; } + void setViewSent(bool viewSent); + + bool getViewFrustumChanging() const { return _viewFrustumChanging; }; + bool getViewFrustumJustStoppedChanging() const { return _viewFrustumJustStoppedChanging; }; + uint64_t getLastTimeBagEmpty() const { return _lastTimeBagEmpty; }; void setLastTimeBagEmpty(uint64_t lastTimeBagEmpty) { _lastTimeBagEmpty = lastTimeBagEmpty; }; @@ -69,6 +73,7 @@ private: ViewFrustum _lastKnownViewFrustum; uint64_t _lastTimeBagEmpty; bool _viewFrustumChanging; + bool _viewFrustumJustStoppedChanging; bool _currentPacketIsColor; }; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index df7011585d..8a8048035b 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -44,9 +44,9 @@ const int MIN_BRIGHTNESS = 64; const float DEATH_STAR_RADIUS = 4.0; const float MAX_CUBE = 0.05f; -const int VOXEL_SEND_INTERVAL_USECS = 100 * 1000; -int PACKETS_PER_CLIENT_PER_INTERVAL = 30; -const int SENDING_TIME_TO_SPARE = 20 * 1000; // usec of sending interval to spare for calculating voxels +const int VOXEL_SEND_INTERVAL_USECS = 17 * 1000; // approximately 60fps +int PACKETS_PER_CLIENT_PER_INTERVAL = 20; +const int SENDING_TIME_TO_SPARE = 5 * 1000; // usec of sending interval to spare for calculating voxels const int MAX_VOXEL_TREE_DEPTH_LEVELS = 4; @@ -173,10 +173,10 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, // If the current view frustum has changed OR we have nothing to send, then search against // the current view frustum for things to send. if (viewFrustumChanged || nodeData->nodeBag.isEmpty()) { + uint64_t now = usecTimestampNow(); if (::debugVoxelSending) { printf("(viewFrustumChanged=%s || nodeData->nodeBag.isEmpty() =%s)...\n", debug::valueOf(viewFrustumChanged), debug::valueOf(nodeData->nodeBag.isEmpty())); - uint64_t now = usecTimestampNow(); if (nodeData->getLastTimeBagEmpty() > 0) { float elapsedSceneSend = (now - nodeData->getLastTimeBagEmpty()) / 1000000.0f; if (viewFrustumChanged) { @@ -188,15 +188,24 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, debug::valueOf(nodeData->getWantOcclusionCulling()), debug::valueOf(wantDelta), debug::valueOf(wantColor)); } - nodeData->setLastTimeBagEmpty(now); // huh? why is this inside debug? probably not what we want } // if our view has changed, we need to reset these things... if (viewFrustumChanged) { nodeData->nodeBag.deleteAll(); nodeData->map.erase(); + } + + if (!viewFrustumChanged && !nodeData->getWantDelta()) { + // only set our last sent time if we weren't resetting due to frustum change + uint64_t now = usecTimestampNow(); + nodeData->setLastTimeBagEmpty(now); + if (::debugVoxelSending) { + printf("ENTIRE SCENE SENT! nodeData->setLastTimeBagEmpty(now=[%lld])\n", now); + } } + // This is the start of "resending" the scene. nodeData->nodeBag.insert(serverTree.rootNode); } @@ -233,15 +242,13 @@ void deepestLevelVoxelDistributor(NodeList* nodeList, EncodeBitstreamParams params(INT_MAX, &nodeData->getCurrentViewFrustum(), wantColor, WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, - wantOcclusionCulling, coverageMap, boundaryLevelAdjust); - + wantOcclusionCulling, coverageMap, boundaryLevelAdjust, + nodeData->getLastTimeBagEmpty(), + nodeData->getViewFrustumJustStoppedChanging()); + bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeData->nodeBag, params); - if (::debugVoxelSending && wantDelta) { - printf("encodeTreeBitstream() childWasInViewDiscarded=%ld\n", params.childWasInViewDiscarded); - } - if (nodeData->getAvailable() >= bytesWritten) { nodeData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } else { @@ -375,9 +382,10 @@ void attachVoxelNodeDataToNode(Node* newNode) { } int main(int argc, const char * argv[]) { - pthread_mutex_init(&::treeLock, NULL); - + + qInstallMsgHandler(sharedMessageHandler); + NodeList* nodeList = NodeList::createInstance(NODE_TYPE_VOXEL_SERVER, VOXEL_LISTEN_PORT); setvbuf(stdout, NULL, _IOLBF, 0);