diff --git a/interface/resources/shaders/point_size.vert b/interface/resources/shaders/point_size.vert new file mode 100644 index 0000000000..9c93385768 --- /dev/null +++ b/interface/resources/shaders/point_size.vert @@ -0,0 +1,164 @@ +#version 120 + +attribute float voxelSizeIn; +varying float voxelSize; + +uniform float viewportWidth; +uniform float viewportHeight; +uniform vec3 cameraPosition; + +// Bit codes for faces +const int NONE = 0; +const int RIGHT = 1; +const int LEFT = 2; +const int BOTTOM = 4; +const int BOTTOM_RIGHT = BOTTOM + RIGHT; +const int BOTTOM_LEFT = BOTTOM + LEFT; +const int TOP = 8; +const int TOP_RIGHT = TOP + RIGHT; +const int TOP_LEFT = TOP + LEFT; +const int NEAR = 16; +const int NEAR_RIGHT = NEAR + RIGHT; +const int NEAR_LEFT = NEAR + LEFT; +const int NEAR_BOTTOM = NEAR + BOTTOM; +const int NEAR_BOTTOM_RIGHT = NEAR + BOTTOM + RIGHT; +const int NEAR_BOTTOM_LEFT = NEAR + BOTTOM + LEFT; +const int NEAR_TOP = NEAR + TOP; +const int NEAR_TOP_RIGHT = NEAR + TOP + RIGHT; +const int NEAR_TOP_LEFT = NEAR + TOP + LEFT; +const int FAR = 32; +const int FAR_RIGHT = FAR + RIGHT; +const int FAR_LEFT = FAR + LEFT; +const int FAR_BOTTOM = FAR + BOTTOM; +const int FAR_BOTTOM_RIGHT = FAR + BOTTOM + RIGHT; +const int FAR_BOTTOM_LEFT = FAR + BOTTOM + LEFT; +const int FAR_TOP = FAR + TOP; +const int FAR_TOP_RIGHT = FAR + TOP + RIGHT; +const int FAR_TOP_LEFT = FAR + TOP + LEFT; + +// If we know the position of the camera relative to the voxel, we can a priori know the vertices that make the visible hull +// polygon. This also tells us which two vertices are known to make the longest possible distance between any pair of these +// vertices for the projected polygon. This is a visibleFaces table based on this knowledge. + +void main(void) { + // Note: the gl_Vertex in this case are in "world coordinates" meaning they've already been scaled to TREE_SCALE + // this is also true for voxelSizeIn. + vec4 bottomNearRight = gl_Vertex; + vec4 topFarLeft = (gl_Vertex + vec4(voxelSizeIn, voxelSizeIn, voxelSizeIn, 0.0)); + + int visibleFaces = NONE; + + // In order to use our visibleFaces "table" (implemented as if statements) below, we need to encode the 6-bit code to + // orient camera relative to the 6 defining faces of the voxel. Based on camera position relative to the bottomNearRight + // corner and the topFarLeft corner, we can calculate which hull and therefore which two vertices are furthest apart + // linearly once projected + if (cameraPosition.x < bottomNearRight.x) { + visibleFaces += RIGHT; + } + if (cameraPosition.x > topFarLeft.x) { + visibleFaces += LEFT; + } + if (cameraPosition.y < bottomNearRight.y) { + visibleFaces += BOTTOM; + } + if (cameraPosition.y > topFarLeft.y) { + visibleFaces += TOP; + } + if (cameraPosition.z < bottomNearRight.z) { + visibleFaces += NEAR; + } + if (cameraPosition.z > topFarLeft.z) { + visibleFaces += FAR; + } + + vec4 cornerAdjustOne; + vec4 cornerAdjustTwo; + + if (visibleFaces == RIGHT) { + cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(0,1,1,0) * voxelSizeIn; + } else if (visibleFaces == LEFT) { + cornerAdjustOne = vec4(1,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; + } else if (visibleFaces == BOTTOM) { + cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,0,1,0) * voxelSizeIn; + } else if (visibleFaces == TOP) { + cornerAdjustOne = vec4(0,1,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; + } else if (visibleFaces == NEAR) { + cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,0,0) * voxelSizeIn; + } else if (visibleFaces == FAR) { + cornerAdjustOne = vec4(0,0,1,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; + } else if (visibleFaces == NEAR_BOTTOM_LEFT || + visibleFaces == FAR_TOP || + visibleFaces == FAR_TOP_RIGHT) { + cornerAdjustOne = vec4(0,1,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,0,1,0) * voxelSizeIn; + } else if (visibleFaces == FAR_TOP_LEFT || + visibleFaces == NEAR_RIGHT || + visibleFaces == NEAR_BOTTOM || + visibleFaces == NEAR_BOTTOM_RIGHT) { + cornerAdjustOne = vec4(0,0,1,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,0,0) * voxelSizeIn; + } else if (visibleFaces == NEAR_TOP_RIGHT || + visibleFaces == FAR_LEFT || + visibleFaces == FAR_BOTTOM_LEFT || + visibleFaces == BOTTOM_RIGHT || + visibleFaces == TOP_LEFT) { + cornerAdjustOne = vec4(1,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(0,1,1,0) * voxelSizeIn; + + // Everything else... + //} else if (visibleFaces == BOTTOM_LEFT || + // visibleFaces == TOP_RIGHT || + // visibleFaces == NEAR_LEFT || + // visibleFaces == FAR_RIGHT || + // visibleFaces == NEAR_TOP || + // visibleFaces == NEAR_TOP_LEFT || + // visibleFaces == FAR_BOTTOM || + // visibleFaces == FAR_BOTTOM_RIGHT) { + } else { + cornerAdjustOne = vec4(0,0,0,0) * voxelSizeIn; + cornerAdjustTwo = vec4(1,1,1,0) * voxelSizeIn; + } + + // Determine our corners + vec4 cornerOne = gl_Vertex + cornerAdjustOne; + vec4 cornerTwo = gl_Vertex + cornerAdjustTwo; + + // Find their model view projections + vec4 cornerOneMVP = gl_ModelViewProjectionMatrix * cornerOne; + vec4 cornerTwoMVP = gl_ModelViewProjectionMatrix * cornerTwo; + + // Map to x, y screen coordinates + vec2 cornerOneScreen = vec2(cornerOneMVP.x / cornerOneMVP.w, cornerOneMVP.y / cornerOneMVP.w); + if (cornerOneMVP.w < 0) { + cornerOneScreen.x = -cornerOneScreen.x; + cornerOneScreen.y = -cornerOneScreen.y; + } + + vec2 cornerTwoScreen = vec2(cornerTwoMVP.x / cornerTwoMVP.w, cornerTwoMVP.y / cornerTwoMVP.w); + if (cornerTwoMVP.w < 0) { + cornerTwoScreen.x = -cornerTwoScreen.x; + cornerTwoScreen.y = -cornerTwoScreen.y; + } + + // Find the distance between them in pixels + float voxelScreenWidth = abs(cornerOneScreen.x - cornerTwoScreen.x) * viewportWidth / 2.0; + float voxelScreenHeight = abs(cornerOneScreen.y - cornerTwoScreen.y) * viewportHeight / 2.0; + float voxelScreenLength = sqrt(voxelScreenHeight * voxelScreenHeight + voxelScreenWidth * voxelScreenWidth); + + // Find the center of the voxel + vec4 centerVertex = gl_Vertex; + float halfSizeIn = voxelSizeIn / 2; + centerVertex += vec4(halfSizeIn, halfSizeIn, halfSizeIn, 0.0); + vec4 center = gl_ModelViewProjectionMatrix * centerVertex; + + // Finally place the point at the center of the voxel, with a size equal to the maximum screen length + gl_Position = center; + gl_PointSize = voxelScreenLength; + gl_FrontColor = gl_Color; +} \ No newline at end of file diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 58e9d61025..47391d1f15 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -144,6 +144,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _packetsPerSecond(0), _bytesPerSecond(0), _bytesCount(0), + _recentMaxPackets(0), + _resetRecentMaxPacketsSoon(true), _swatch(NULL), _pasteMode(false) { @@ -1304,7 +1306,10 @@ static glm::vec3 getFaceVector(BoxFace face) { } void Application::idle() { - bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + // Normally we check PipelineWarnings, but since idle will often take more than 10ms we only show these idle timing + // details if we're in ExtraDebugging mode. However, the ::update() and it's subcomponents will show their timing + // details normally. + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging); PerformanceWarning warn(showWarnings, "Application::idle()"); timeval check; @@ -1314,22 +1319,30 @@ void Application::idle() { double timeSinceLastUpdate = diffclock(&_lastTimeUpdated, &check); if (timeSinceLastUpdate > IDLE_SIMULATE_MSECS) { - - const float BIGGEST_DELTA_TIME_SECS = 0.25f; - update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS)); - _glWidget->updateGL(); - _lastTimeUpdated = check; - _idleLoopStdev.addValue(timeSinceLastUpdate); - - // Record standard deviation and reset counter if needed - const int STDEV_SAMPLES = 500; - if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) { - _idleLoopMeasuredJitter = _idleLoopStdev.getStDev(); - _idleLoopStdev.reset(); + { + PerformanceWarning warn(showWarnings, "Application::idle()... update()"); + const float BIGGEST_DELTA_TIME_SECS = 0.25f; + update(glm::clamp((float)timeSinceLastUpdate / 1000.f, 0.f, BIGGEST_DELTA_TIME_SECS)); } + { + PerformanceWarning warn(showWarnings, "Application::idle()... updateGL()"); + _glWidget->updateGL(); + } + { + PerformanceWarning warn(showWarnings, "Application::idle()... rest of it"); + _lastTimeUpdated = check; + _idleLoopStdev.addValue(timeSinceLastUpdate); + + // Record standard deviation and reset counter if needed + const int STDEV_SAMPLES = 500; + if (_idleLoopStdev.getSamples() > STDEV_SAMPLES) { + _idleLoopMeasuredJitter = _idleLoopStdev.getStDev(); + _idleLoopStdev.reset(); + } - // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. - idleTimer->start(2); + // After finishing all of the above work, restart the idle timer, allowing 2ms to process events. + idleTimer->start(2); + } } } void Application::terminate() { @@ -1665,6 +1678,7 @@ void Application::init() { _glowEffect.init(); _ambientOcclusionEffect.init(); _voxelShader.init(); + _pointShader.init(); _handControl.setScreenDimensions(_glWidget->width(), _glWidget->height()); @@ -1775,6 +1789,8 @@ static QUuid DEFAULT_NODE_ID_REF; void Application::updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection, glm::vec3& eyePosition) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateLookatTargetAvatar()"); _lookatTargetAvatar = findLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, eyePosition, DEFAULT_NODE_ID_REF); } @@ -1906,17 +1922,13 @@ void Application::updateAvatars(float deltaTime, glm::vec3 mouseRayOrigin, glm:: } } -void Application::update(float deltaTime) { +void Application::updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showWarnings, "Application::update()"); - - // tell my avatar if the mouse is being pressed... - _myAvatar.setMousePressed(_mousePressed); - - // check what's under the mouse and update the mouse voxel - glm::vec3 mouseRayOrigin, mouseRayDirection; - _viewFrustum.computePickRay(_mouseX / (float)_glWidget->width(), - _mouseY / (float)_glWidget->height(), mouseRayOrigin, mouseRayDirection); + PerformanceWarning warn(showWarnings, "Application::updateMouseRay()"); + + _viewFrustum.computePickRay(_mouseX / (float)_glWidget->width(), _mouseY / (float)_glWidget->height(), + mouseRayOrigin, mouseRayDirection); // adjust for mirroring if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { @@ -1927,12 +1939,19 @@ void Application::update(float deltaTime) { _viewFrustum.getRight() * glm::dot(_viewFrustum.getRight(), mouseRayDirection)); } + // tell my avatar if the mouse is being pressed... + _myAvatar.setMousePressed(_mousePressed); + // tell my avatar the posiion and direction of the ray projected ino the world based on the mouse position _myAvatar.setMouseRay(mouseRayOrigin, mouseRayDirection); - - // Set where I am looking based on my mouse ray (so that other people can see) - glm::vec3 lookAtSpot; +} +void Application::updateFaceshift(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection) { + + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateFaceshift()"); + // Update faceshift _faceshift.update(); @@ -1940,20 +1959,26 @@ void Application::update(float deltaTime) { if (_faceshift.isActive()) { _myAvatar.getHead().setAngularVelocity(_faceshift.getHeadAngularVelocity()); } +} - updateLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot); +void Application::updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin, + glm::vec3& lookAtRayDirection) { + + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateMyAvatarLookAtPosition()"); + if (!_lookatTargetAvatar) { if (_isHoverVoxel) { // Look at the hovered voxel lookAtSpot = getMouseVoxelWorldCoordinates(_hoverVoxel); - + } else if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { lookAtSpot = _myCamera.getPosition(); } else { // Just look in direction of the mouse ray const float FAR_AWAY_STARE = TREE_SCALE; - lookAtSpot = mouseRayOrigin + mouseRayDirection * FAR_AWAY_STARE; + lookAtSpot = lookAtRayOrigin + lookAtRayDirection * FAR_AWAY_STARE; } } if (_faceshift.isActive()) { @@ -1967,11 +1992,14 @@ void Application::update(float deltaTime) { glm::inverse(_myCamera.getRotation()) * (lookAtSpot - origin); } _myAvatar.getHead().setLookAtPosition(lookAtSpot); +} + +void Application::updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + float& distance, BoxFace& face) { + + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels()"); - // Find the voxel we are hovering over, and respond if clicked - float distance; - BoxFace face; - // If we have clicked on a voxel, update it's color if (_isHoverVoxelSounding) { VoxelNode* hoveredNode = _voxels.getVoxelAt(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s); @@ -1993,23 +2021,38 @@ void Application::update(float deltaTime) { } else { // Check for a new hover voxel glm::vec4 oldVoxel(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s); - _isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face); - if (MAKE_SOUND_ON_VOXEL_HOVER && _isHoverVoxel && glm::vec4(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s) != oldVoxel) { - _hoverVoxelOriginalColor[0] = _hoverVoxel.red; - _hoverVoxelOriginalColor[1] = _hoverVoxel.green; - _hoverVoxelOriginalColor[2] = _hoverVoxel.blue; - _hoverVoxelOriginalColor[3] = 1; - _audio.startCollisionSound(1.0, HOVER_VOXEL_FREQUENCY * _hoverVoxel.s * TREE_SCALE, 0.0, HOVER_VOXEL_DECAY); - _isHoverVoxelSounding = true; + // only do this work if MAKE_SOUND_ON_VOXEL_HOVER or MAKE_SOUND_ON_VOXEL_CLICK is enabled, + // and make sure the tree is not already busy... because otherwise you'll have to wait. + if (!_voxels.treeIsBusy()) { + { + PerformanceWarning warn(showWarnings, "Application::updateHoverVoxels() _voxels.findRayIntersection()"); + _isHoverVoxel = _voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _hoverVoxel, distance, face); + } + if (MAKE_SOUND_ON_VOXEL_HOVER && _isHoverVoxel && + glm::vec4(_hoverVoxel.x, _hoverVoxel.y, _hoverVoxel.z, _hoverVoxel.s) != oldVoxel) { + + _hoverVoxelOriginalColor[0] = _hoverVoxel.red; + _hoverVoxelOriginalColor[1] = _hoverVoxel.green; + _hoverVoxelOriginalColor[2] = _hoverVoxel.blue; + _hoverVoxelOriginalColor[3] = 1; + _audio.startCollisionSound(1.0, HOVER_VOXEL_FREQUENCY * _hoverVoxel.s * TREE_SCALE, 0.0, HOVER_VOXEL_DECAY); + _isHoverVoxelSounding = true; + } } } - +} + +void Application::updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + float& distance, BoxFace& face) { + + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateMouseVoxels()"); + _mouseVoxel.s = 0.0f; if (Menu::getInstance()->isVoxelModeActionChecked() && (fabs(_myAvatar.getVelocity().x) + fabs(_myAvatar.getVelocity().y) + fabs(_myAvatar.getVelocity().z)) / 3 < MAX_AVATAR_EDIT_VELOCITY) { - PerformanceWarning warn(showWarnings, "Application::update()... findRayIntersection()"); if (_voxels.findRayIntersection(mouseRayOrigin, mouseRayDirection, _mouseVoxel, distance, face)) { if (distance < MAX_VOXEL_EDIT_DISTANCE) { @@ -2078,12 +2121,17 @@ void Application::update(float deltaTime) { _justEditedVoxel = false; } } - +} + +void Application::updateHandAndTouch(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateHandAndTouch()"); + // walking triggers the handControl to stop if (_myAvatar.getMode() == AVATAR_MODE_WALKING) { _handControl.stop(); } - + // Update from Touch if (_isTouchPressed) { float TOUCH_YAW_SCALE = -0.25f; @@ -2094,19 +2142,29 @@ void Application::update(float deltaTime) { _lastTouchAvgX = _touchAvgX; _lastTouchAvgY = _touchAvgY; } - - // Leap finger-sensing device +} + +void Application::updateLeap(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateLeap()"); + LeapManager::enableFakeFingers(Menu::getInstance()->isOptionChecked(MenuOption::SimulateLeapHand)); _myAvatar.getHand().setRaveGloveActive(Menu::getInstance()->isOptionChecked(MenuOption::TestRaveGlove)); LeapManager::nextFrame(_myAvatar); - - // Read serial port interface devices +} + +void Application::updateSerialDevices(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateSerialDevices()"); + if (_serialHeadSensor.isActive()) { _serialHeadSensor.readData(deltaTime); } - - // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes - updateAvatar(deltaTime); +} + +void Application::updateThreads(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateThreads()"); // read incoming packets from network if (!_enableNetworkThread) { @@ -2118,12 +2176,12 @@ void Application::update(float deltaTime) { _voxelProcessor.threadRoutine(); _voxelEditSender.threadRoutine(); } +} + +void Application::updateMyAvatarSimulation(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateMyAvatarSimulation()"); - - //loop through all the other avatars and simulate them... - updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); - - // Simulate myself if (Menu::getInstance()->isOptionChecked(MenuOption::Gravity)) { _myAvatar.setGravity(_environment.getGravity(_myAvatar.getPosition())); } @@ -2136,12 +2194,21 @@ void Application::update(float deltaTime) { } else { _myAvatar.simulate(deltaTime, NULL); } - - // Simulate particle cloud movements +} + +void Application::updateParticles(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateParticles()"); + if (Menu::getInstance()->isOptionChecked(MenuOption::ParticleCloud)) { _cloud.simulate(deltaTime); } - +} + +void Application::updateTransmitter(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateTransmitter()"); + // no transmitter drive implies transmitter pick if (!Menu::getInstance()->isOptionChecked(MenuOption::TransmitterDrive) && _myTransmitter.isConnected()) { _transmitterPickStart = _myAvatar.getSkeleton().joint[AVATAR_JOINT_CHEST].position; @@ -2176,7 +2243,12 @@ void Application::update(float deltaTime) { } else { _transmitterPickStart = _transmitterPickEnd = glm::vec3(); } - +} + +void Application::updateCamera(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateCamera()"); + if (!OculusManager::isConnected()) { if (Menu::getInstance()->isOptionChecked(MenuOption::FullscreenMirror)) { if (_myCamera.getMode() != CAMERA_MODE_MIRROR) { @@ -2211,7 +2283,12 @@ void Application::update(float deltaTime) { } } } - +} + +void Application::updateDialogs(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateDialogs()"); + // Update bandwidth dialog, if any BandwidthDialog* bandwidthDialog = Menu::getInstance()->getBandwidthDialog(); if (bandwidthDialog) { @@ -2222,6 +2299,11 @@ void Application::update(float deltaTime) { if (voxelStatsDialog) { voxelStatsDialog->update(); } +} + +void Application::updateAudio(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateAudio()"); // Update audio stats for procedural sounds #ifndef _WIN32 @@ -2229,7 +2311,12 @@ void Application::update(float deltaTime) { _audio.setLastVelocity(_myAvatar.getVelocity()); _audio.eventuallyAnalyzePing(); #endif - +} + +void Application::updateCursor(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::updateCursor()"); + // watch mouse position, if it hasn't moved, hide the cursor bool underMouse = _glWidget->underMouse(); if (!_mouseHidden) { @@ -2250,6 +2337,43 @@ void Application::update(float deltaTime) { } } +void Application::update(float deltaTime) { + bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); + PerformanceWarning warn(showWarnings, "Application::update()"); + + // check what's under the mouse and update the mouse voxel + glm::vec3 mouseRayOrigin, mouseRayDirection; + updateMouseRay(deltaTime, mouseRayOrigin, mouseRayDirection); + + // Set where I am looking based on my mouse ray (so that other people can see) + glm::vec3 lookAtSpot; + glm::vec3 lookAtRayOrigin = mouseRayOrigin, lookAtRayDirection = mouseRayDirection; + + updateFaceshift(deltaTime, mouseRayOrigin, mouseRayDirection, lookAtRayOrigin, lookAtRayDirection); + updateLookatTargetAvatar(mouseRayOrigin, mouseRayDirection, lookAtSpot); + updateMyAvatarLookAtPosition(lookAtSpot, lookAtRayOrigin, lookAtRayDirection); + + // Find the voxel we are hovering over, and respond if clicked + float distance; + BoxFace face; + + updateHoverVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // clicking on voxels and making sounds + updateMouseVoxels(deltaTime, mouseRayOrigin, mouseRayDirection, distance, face); // UI/UX related to voxels + updateHandAndTouch(deltaTime); // Update state for touch sensors + updateLeap(deltaTime); // Leap finger-sensing device + updateSerialDevices(deltaTime); // Read serial port interface devices + updateAvatar(deltaTime); // Sample hardware, update view frustum if needed, and send avatar data to mixer/nodes + updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process... + updateAvatars(deltaTime, mouseRayOrigin, mouseRayDirection); //loop through all the other avatars and simulate them... + updateMyAvatarSimulation(deltaTime); // Simulate myself + updateParticles(deltaTime); // Simulate particle cloud movements + updateTransmitter(deltaTime); // transmitter drive or pick + updateCamera(deltaTime); // handle various camera tweaks like off axis projection + updateDialogs(deltaTime); // update various stats dialogs if present + updateAudio(deltaTime); // Update audio stats for procedural sounds + updateCursor(deltaTime); // Handle cursor updates +} + void Application::updateAvatar(float deltaTime) { bool showWarnings = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); PerformanceWarning warn(showWarnings, "Application::updateAvatar()"); @@ -3256,6 +3380,8 @@ void Application::displayStats() { drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, avatarStats); + QLocale locale(QLocale::English); + std::stringstream voxelStats; voxelStats.precision(4); voxelStats << "Voxels " << @@ -3278,11 +3404,19 @@ void Application::displayStats() { statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); + unsigned long localTotal = VoxelNode::getNodeCount(); + unsigned long localInternal = VoxelNode::getInternalNodeCount(); + unsigned long localLeaves = VoxelNode::getLeafNodeCount(); + QString localTotalString = locale.toString((uint)localTotal); // consider adding: .rightJustified(10, ' '); + QString localInternalString = locale.toString((uint)localInternal); + QString localLeavesString = locale.toString((uint)localLeaves); + + voxelStats.str(""); voxelStats << - "Local Voxels Total: " << VoxelNode::getNodeCount() << ", " << - "Internal: " << VoxelNode::getInternalNodeCount() << " , " << - "Leaves: " << VoxelNode::getLeafNodeCount() << ""; + "Local Voxels Total: " << localTotalString.toLocal8Bit().constData() << " / " << + "Internal: " << localInternalString.toLocal8Bit().constData() << " / " << + "Leaves: " << localLeavesString.toLocal8Bit().constData() << ""; statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); @@ -3309,6 +3443,29 @@ void Application::displayStats() { voxelStats << "Sending Mode: " << voxelDetails; statsVerticalOffset += PELS_PER_LINE; drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); + + voxelStats.str(""); + int voxelPacketsToProcess = _voxelProcessor.packetsToProcessCount(); + QString packetsString = locale.toString((int)voxelPacketsToProcess); + QString maxString = locale.toString((int)_recentMaxPackets); + + voxelStats << "Voxel Packets to Process: " << packetsString.toLocal8Bit().constData() + << " [Recent Max: " << maxString.toLocal8Bit().constData() << "]"; + + if (_resetRecentMaxPacketsSoon && voxelPacketsToProcess > 0) { + _recentMaxPackets = 0; + _resetRecentMaxPacketsSoon = false; + } + if (voxelPacketsToProcess == 0) { + _resetRecentMaxPacketsSoon = true; + } else { + if (voxelPacketsToProcess > _recentMaxPackets) { + _recentMaxPackets = voxelPacketsToProcess; + } + } + statsVerticalOffset += PELS_PER_LINE; + drawtext(10, statsVerticalOffset, 0.10f, 0, 1.0, 0, (char*)voxelStats.str().c_str()); + Node *avatarMixer = NodeList::getInstance()->soloNodeOfType(NODE_TYPE_AVATAR_MIXER); char avatarMixerStats[200]; diff --git a/interface/src/Application.h b/interface/src/Application.h index f888442dbd..ff8ae2f882 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -55,6 +55,7 @@ #include "renderer/GeometryCache.h" #include "renderer/GlowEffect.h" #include "renderer/VoxelShader.h" +#include "renderer/PointShader.h" #include "renderer/TextureCache.h" #include "ui/BandwidthDialog.h" #include "ui/ChatEntry.h" @@ -162,6 +163,9 @@ public: virtual void domainChanged(QString domain); VoxelShader& getVoxelShader() { return _voxelShader; } + PointShader& getPointShader() { return _pointShader; } + + glm::vec2 getViewportDimensions() const{ return glm::vec2(_glWidget->width(),_glWidget->height()); } public slots: void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data); @@ -219,9 +223,30 @@ private: void init(); void update(float deltaTime); - + + // Various helper functions called during update() + void updateMouseRay(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection); + void updateFaceshift(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection); + void updateMyAvatarLookAtPosition(glm::vec3& lookAtSpot, glm::vec3& lookAtRayOrigin, glm::vec3& lookAtRayDirection); + void updateHoverVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + float& distance, BoxFace& face); + void updateMouseVoxels(float deltaTime, glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection, + float& distance, BoxFace& face); void updateLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection, glm::vec3& eyePosition); + void updateHandAndTouch(float deltaTime); + void updateLeap(float deltaTime); + void updateSerialDevices(float deltaTime); + void updateThreads(float deltaTime); + void updateMyAvatarSimulation(float deltaTime); + void updateParticles(float deltaTime); + void updateTransmitter(float deltaTime); + void updateCamera(float deltaTime); + void updateDialogs(float deltaTime); + void updateAudio(float deltaTime); + void updateCursor(float deltaTime); + Avatar* findLookatTargetAvatar(const glm::vec3& mouseRayOrigin, const glm::vec3& mouseRayDirection, glm::vec3& eyePosition, QUuid &nodeUUID); bool isLookingAtMyAvatar(Avatar* avatar); @@ -383,6 +408,7 @@ private: GlowEffect _glowEffect; AmbientOcclusionEffect _ambientOcclusionEffect; VoxelShader _voxelShader; + PointShader _pointShader; #ifndef _WIN32 Audio _audio; @@ -402,6 +428,9 @@ private: int _bytesPerSecond; int _bytesCount; + int _recentMaxPackets; // recent max incoming voxel packets to process + bool _resetRecentMaxPacketsSoon; + StDev _idleLoopStdev; float _idleLoopMeasuredJitter; diff --git a/interface/src/VoxelPacketProcessor.cpp b/interface/src/VoxelPacketProcessor.cpp index 76075c6fa5..9087a5a545 100644 --- a/interface/src/VoxelPacketProcessor.cpp +++ b/interface/src/VoxelPacketProcessor.cpp @@ -19,7 +19,7 @@ void VoxelPacketProcessor::processPacket(sockaddr& senderAddress, unsigned char* "VoxelPacketProcessor::processPacket()"); const int WAY_BEHIND = 300; - if (packetsToProcessCount() > WAY_BEHIND && Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { + if (packetsToProcessCount() > WAY_BEHIND && Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { qDebug("VoxelPacketProcessor::processPacket() packets to process=%d\n", packetsToProcessCount()); } ssize_t messageLength = packetLength; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 9e2c6ec63e..1219548b4d 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -110,6 +110,7 @@ VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) _culledOnce = false; _inhideOutOfView = false; + _treeIsBusy = false; } void VoxelSystem::voxelDeleted(VoxelNode* node) { @@ -595,9 +596,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { "readBitstreamToTree()"); // ask the VoxelTree to read the bitstream into the tree ReadBitstreamToTreeParams args(WANT_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); - pthread_mutex_unlock(&_treeLock); + unlockTree(); } break; case PACKET_TYPE_VOXEL_DATA_MONOCHROME: { @@ -605,9 +606,9 @@ int VoxelSystem::parseData(unsigned char* sourceBuffer, int numBytes) { "readBitstreamToTree()"); // ask the VoxelTree to read the MONOCHROME bitstream into the tree ReadBitstreamToTreeParams args(NO_COLOR, WANT_EXISTS_BITS, NULL, getDataSourceUUID()); - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->readBitstreamToTree(voxelData, numBytes - numBytesPacketHeader, args); - pthread_mutex_unlock(&_treeLock); + unlockTree(); } break; case PACKET_TYPE_Z_COMMAND: @@ -1002,7 +1003,9 @@ int VoxelSystem::updateNodeInArrays(VoxelNode* node, bool reuseIndex, bool force // not render these Voxels. We need to think about ways to keep the entire scene intact but maybe lower quality // possibly shifting down to lower LOD or something. This debug message is to help identify, if/when/how this // state actually occurs. - qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n"); + if (Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging)) { + qDebug("OHHHH NOOOOOO!!!! updateNodeInArrays() BAILING (_voxelsInWriteArrays >= _maxVoxels)\n"); + } return 0; } @@ -1257,13 +1260,27 @@ void VoxelSystem::render(bool texture) { if (!_voxelsAsPoints) { Application::getInstance()->getVoxelShader().begin(); - attributeLocation = Application::getInstance()->getVoxelShader().attributeLocation("voxelSizeIn"); glEnableVertexAttribArray(attributeLocation); glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); } else { - const float POINT_SIZE = 4.0; - glPointSize(POINT_SIZE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + + glm::vec2 viewDimensions = Application::getInstance()->getViewportDimensions(); + float viewportWidth = viewDimensions.x; + float viewportHeight = viewDimensions.y; + glm::vec3 cameraPosition = Application::getInstance()->getViewFrustum()->getPosition(); + PointShader& pointShader = Application::getInstance()->getPointShader(); + + pointShader.begin(); + + pointShader.setUniformValue(pointShader.uniformLocation("viewportWidth"), viewportWidth); + pointShader.setUniformValue(pointShader.uniformLocation("viewportHeight"), viewportHeight); + pointShader.setUniformValue(pointShader.uniformLocation("cameraPosition"), cameraPosition); + + attributeLocation = pointShader.attributeLocation("voxelSizeIn"); + glEnableVertexAttribArray(attributeLocation); + glVertexAttribPointer(attributeLocation, 1, GL_FLOAT, false, sizeof(VoxelShaderVBOData), BUFFER_OFFSET(3*sizeof(float))); } @@ -1287,6 +1304,10 @@ void VoxelSystem::render(bool texture) { if (!_voxelsAsPoints) { Application::getInstance()->getVoxelShader().end(); glDisableVertexAttribArray(attributeLocation); + } else { + Application::getInstance()->getPointShader().end(); + glDisableVertexAttribArray(attributeLocation); + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); } } else { PerformanceWarning warn(showWarnings, "render().. TRIANGLES..."); @@ -1387,9 +1408,9 @@ void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { int VoxelSystem::_nodeCount = 0; void VoxelSystem::killLocalVoxels() { - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->eraseAllVoxels(); - pthread_mutex_unlock(&_treeLock); + unlockTree(); clearFreeBufferIndexes(); _voxelsInReadArrays = 0; // do we need to do this? setupNewVoxelsForDrawing(); @@ -1408,9 +1429,9 @@ bool VoxelSystem::clearAllNodesBufferIndexOperation(VoxelNode* node, void* extra void VoxelSystem::clearAllNodesBufferIndex() { _nodeCount = 0; - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->recurseTreeWithOperation(clearAllNodesBufferIndexOperation); - pthread_mutex_unlock(&_treeLock); + unlockTree(); if (Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings)) { qDebug("clearing buffer index of %d nodes\n", _nodeCount); } @@ -1864,7 +1885,7 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { _inhideOutOfView = true; bool showDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings); - PerformanceWarning warn(showDebugDetails, "hideOutOfView()", showDebugDetails); + PerformanceWarning warn(showDebugDetails, "hideOutOfView()"); bool widenFrustum = true; // When using "delta" view frustums and only hide/show items that are in the difference @@ -1898,9 +1919,9 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { return; } - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->recurseTreeWithOperation(hideOutOfViewOperation,(void*)&args); - pthread_mutex_unlock(&_treeLock); + unlockTree(); _lastCulledViewFrustum = args.thisViewFrustum; // save last stable _culledOnce = true; @@ -1909,7 +1930,8 @@ void VoxelSystem::hideOutOfView(bool forceFullFrustum) { setupNewVoxelsForDrawingSingleNode(DONT_BAIL_EARLY); } - if (showDebugDetails) { + bool extraDebugDetails = Menu::getInstance()->isOptionChecked(MenuOption::ExtraDebugging); + if (extraDebugDetails) { qDebug("hideOutOfView() scanned=%ld removed=%ld inside=%ld intersect=%ld outside=%ld\n", args.nodesScanned, args.nodesRemoved, args.nodesInside, args.nodesIntersect, args.nodesOutside @@ -2088,10 +2110,10 @@ bool VoxelSystem::hideOutOfViewOperation(VoxelNode* node, void* extraData) { bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, VoxelDetail& detail, float& distance, BoxFace& face) { - pthread_mutex_lock(&_treeLock); + lockTree(); VoxelNode* node; if (!_tree->findRayIntersection(origin, direction, node, distance, face)) { - pthread_mutex_unlock(&_treeLock); + unlockTree(); return false; } detail.x = node->getCorner().x; @@ -2101,21 +2123,21 @@ bool VoxelSystem::findRayIntersection(const glm::vec3& origin, const glm::vec3& detail.red = node->getColor()[0]; detail.green = node->getColor()[1]; detail.blue = node->getColor()[2]; - pthread_mutex_unlock(&_treeLock); + unlockTree(); return true; } bool VoxelSystem::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) { - pthread_mutex_lock(&_treeLock); + lockTree(); bool result = _tree->findSpherePenetration(center, radius, penetration); - pthread_mutex_unlock(&_treeLock); + unlockTree(); return result; } bool VoxelSystem::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) { - pthread_mutex_lock(&_treeLock); + lockTree(); bool result = _tree->findCapsulePenetration(start, end, radius, penetration); - pthread_mutex_unlock(&_treeLock); + unlockTree(); return result; } @@ -2289,9 +2311,9 @@ void VoxelSystem::collectStatsForTreesAndVBOs() { void VoxelSystem::deleteVoxelAt(float x, float y, float z, float s) { - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->deleteVoxelAt(x, y, z, s); - pthread_mutex_unlock(&_treeLock); + unlockTree(); // redraw! setupNewVoxelsForDrawing(); // do we even need to do this? Or will the next network receive kick in? @@ -2306,9 +2328,9 @@ void VoxelSystem::createVoxel(float x, float y, float z, float s, unsigned char red, unsigned char green, unsigned char blue, bool destructive) { //qDebug("VoxelSystem::createVoxel(%f,%f,%f,%f)\n",x,y,z,s); - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->createVoxel(x, y, z, s, red, green, blue, destructive); - pthread_mutex_unlock(&_treeLock); + unlockTree(); setupNewVoxelsForDrawing(); }; @@ -2631,9 +2653,9 @@ void VoxelSystem::nodeKilled(Node* node) { if (_voxelServerCount > 0) { // Kill any voxels from the local tree that match this nodeID // commenting out for removal of 16 bit node IDs - pthread_mutex_lock(&_treeLock); + lockTree(); _tree->recurseTreeWithOperation(killSourceVoxelsOperation, &nodeUUID); - pthread_mutex_unlock(&_treeLock); + unlockTree(); _tree->setDirtyBit(); setupNewVoxelsForDrawing(); } else { @@ -2701,5 +2723,15 @@ unsigned long VoxelSystem::getVoxelMemoryUsageGPU() { return (_initialMemoryUsageGPU - currentFreeMemory); } +void VoxelSystem::lockTree() { + pthread_mutex_lock(&_treeLock); + _treeIsBusy = true; +} + +void VoxelSystem::unlockTree() { + _treeIsBusy = false; + pthread_mutex_unlock(&_treeLock); +} + diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 303c7dfb49..0fdbb5b884 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -120,6 +120,8 @@ public: virtual void nodeKilled(Node* node); virtual void domainChanged(QString domain); + bool treeIsBusy() const { return _treeIsBusy; } + signals: void importSize(float x, float y, float z); void importProgress(int progress); @@ -302,6 +304,10 @@ private: bool _useFastVoxelPipeline; bool _inhideOutOfView; + bool _treeIsBusy; // is the tree mutex locked? if so, it's busy, and if you can avoid it, don't access the tree + + void lockTree(); + void unlockTree(); }; #endif diff --git a/interface/src/renderer/PointShader.cpp b/interface/src/renderer/PointShader.cpp new file mode 100644 index 0000000000..32139903be --- /dev/null +++ b/interface/src/renderer/PointShader.cpp @@ -0,0 +1,77 @@ +// +// PointShader.cpp +// interface +// +// Created by Brad Hefta-Gaub on 10/30/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL +#include "InterfaceConfig.h" + +#include + +#include "Application.h" +#include "PointShader.h" +#include "ProgramObject.h" +#include "RenderUtil.h" + +PointShader::PointShader() + : _initialized(false) +{ + _program = NULL; +} + +PointShader::~PointShader() { + if (_initialized) { + delete _program; + } +} + +ProgramObject* PointShader::createPointShaderProgram(const QString& name) { + ProgramObject* program = new ProgramObject(); + program->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/" + name + ".vert" ); + program->link(); + return program; +} + +void PointShader::init() { + if (_initialized) { + qDebug("[ERROR] PointShader is already initialized.\n"); + return; + } + switchToResourcesParentIfRequired(); + _program = createPointShaderProgram("point_size"); + _initialized = true; +} + +void PointShader::begin() { + _program->bind(); +} + +void PointShader::end() { + _program->release(); +} + +int PointShader::attributeLocation(const char* name) const { + if (_program) { + return _program->attributeLocation(name); + } else { + return -1; + } +} + +int PointShader::uniformLocation(const char* name) const { + if (_program) { + return _program->uniformLocation(name); + } else { + return -1; + } +} + +void PointShader::setUniformValue(int uniformLocation, float value) { + _program->setUniformValue(uniformLocation, value); +} + +void PointShader::setUniformValue(int uniformLocation, const glm::vec3& value) { + _program->setUniformValue(uniformLocation, value.x, value.y, value.z); +} diff --git a/interface/src/renderer/PointShader.h b/interface/src/renderer/PointShader.h new file mode 100644 index 0000000000..b7e1b8c008 --- /dev/null +++ b/interface/src/renderer/PointShader.h @@ -0,0 +1,45 @@ +// +// PointShader.h +// interface +// +// Created by Brad Hefta-Gaub on 10/30/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__PointShader__ +#define __interface__PointShader__ + +#include + +class ProgramObject; + +/// A shader program that draws voxels as points with variable sizes +class PointShader : public QObject { + Q_OBJECT + +public: + PointShader(); + ~PointShader(); + + void init(); + + /// Starts using the voxel point shader program. + void begin(); + + /// Stops using the voxel point shader program. + void end(); + + /// Gets access to attributes from the shader program + int attributeLocation(const char* name) const; + int uniformLocation(const char* name) const; + void setUniformValue(int uniformLocation, float value); + void setUniformValue(int uniformLocation, const glm::vec3& value); + + static ProgramObject* createPointShaderProgram(const QString& name); + +private: + bool _initialized; + ProgramObject* _program; +}; + +#endif /* defined(__interface__PointShader__) */ diff --git a/libraries/shared/src/ReceivedPacketProcessor.h b/libraries/shared/src/ReceivedPacketProcessor.h index f6d49cbb09..78017bffd7 100644 --- a/libraries/shared/src/ReceivedPacketProcessor.h +++ b/libraries/shared/src/ReceivedPacketProcessor.h @@ -24,6 +24,12 @@ public: /// \param ssize_t packetLength size of received data /// \thread network receive thread void queueReceivedPacket(sockaddr& senderAddress, unsigned char* packetData, ssize_t packetLength); + + /// Are there received packets waiting to be processed + bool hasPacketsToProcess() const { return _packets.size() > 0; } + + /// How many received packets waiting are to be processed + int packetsToProcessCount() const { return _packets.size(); } protected: /// Callback for processing of recieved packets. Implement this to process the incoming packets. @@ -36,12 +42,6 @@ protected: /// Implements generic processing behavior for this thread. virtual bool process(); - /// Are there received packets waiting to be processed - bool hasPacketsToProcess() const { return _packets.size() > 0; } - - /// How many received packets waiting are to be processed - int packetsToProcessCount() const { return _packets.size(); } - private: std::vector _packets;