From f8a74acb02c35fa9e67abfe3c44aa9b4eb8edfa9 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Sep 2013 10:19:17 -0700 Subject: [PATCH 01/14] Special frustum handling for mirrored mode. --- interface/src/Application.cpp | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index eefbc69d25..296a3e2df2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -446,6 +446,13 @@ void Application::updateProjectionMatrix() { nearVal = _viewFrustumOffsetCamera.getNearClip(); farVal = _viewFrustumOffsetCamera.getFarClip(); } + + // when mirrored, we must flip left and right + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + float tmp = left; + left = -right; + right = -tmp; + } glFrustum(left, right, bottom, top, nearVal, farVal); glMatrixMode(GL_MODELVIEW); @@ -1812,8 +1819,9 @@ void Application::update(float deltaTime) { updateProjectionMatrix(); } else if (_webcam.isActive()) { - const float EYE_OFFSET_SCALE = 5.0f; - _myCamera.setEyeOffsetPosition(_webcam.getEstimatedPosition() * EYE_OFFSET_SCALE); + const float EYE_OFFSET_SCALE = 0.1f; + glm::vec3 position = _webcam.getEstimatedPosition() * EYE_OFFSET_SCALE; + _myCamera.setEyeOffsetPosition(glm::vec3(-position.x, -position.y, position.z)); updateProjectionMatrix(); } } @@ -1966,7 +1974,15 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { viewFrustum.setFieldOfView(fov); viewFrustum.setNearClip(nearClip); viewFrustum.setFarClip(farClip); - viewFrustum.setEyeOffsetPosition(camera.getEyeOffsetPosition()); + + // when mirrored, we must flip the eye offset in x to get the correct frustum + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + glm::vec3 position = camera.getEyeOffsetPosition(); + viewFrustum.setEyeOffsetPosition(glm::vec3(-position.x, position.y, position.z)); + + } else { + viewFrustum.setEyeOffsetPosition(camera.getEyeOffsetPosition()); + } viewFrustum.setEyeOffsetOrientation(camera.getEyeOffsetOrientation()); // Ask the ViewFrustum class to calculate our corners From 26411a42b1c5ad132c24fd98a47d5647d1e3f794 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Sep 2013 15:07:15 -0700 Subject: [PATCH 02/14] More focal length bits. --- interface/src/Application.cpp | 32 ++++++++++++++++++++++++---- libraries/voxels/src/ViewFrustum.cpp | 30 +++++++++++++++++--------- libraries/voxels/src/ViewFrustum.h | 15 +++++++------ 3 files changed, 57 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 296a3e2df2..741cb6ad52 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -638,8 +638,8 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_J: if (isShifted) { - _myCamera.setEyeOffsetOrientation(glm::normalize( - glm::quat(glm::vec3(0, 0.002f, 0)) * _myCamera.getEyeOffsetOrientation())); + _viewFrustum.setFocalLength(_viewFrustum.getFocalLength() - 0.1f); + } else { _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(-0.001, 0, 0)); } @@ -648,8 +648,8 @@ void Application::keyPressEvent(QKeyEvent* event) { case Qt::Key_M: if (isShifted) { - _myCamera.setEyeOffsetOrientation(glm::normalize( - glm::quat(glm::vec3(0, -0.002f, 0)) * _myCamera.getEyeOffsetOrientation())); + _viewFrustum.setFocalLength(_viewFrustum.getFocalLength() + 0.1f); + } else { _myCamera.setEyeOffsetPosition(_myCamera.getEyeOffsetPosition() + glm::vec3(0.001, 0, 0)); } @@ -2934,6 +2934,30 @@ void Application::renderViewFrustum(ViewFrustum& viewFrustum) { // left plane - top edge - viewFrustum.getNear to distant glVertex3f(viewFrustum.getNearTopLeft().x, viewFrustum.getNearTopLeft().y, viewFrustum.getNearTopLeft().z); glVertex3f(viewFrustum.getFarTopLeft().x, viewFrustum.getFarTopLeft().y, viewFrustum.getFarTopLeft().z); + + // focal plane - bottom edge + glColor3f(1.0f, 0.0f, 1.0f); + float focalProportion = (viewFrustum.getFocalLength() - viewFrustum.getNearClip()) / + (viewFrustum.getFarClip() - viewFrustum.getNearClip()); + glm::vec3 focalBottomLeft = glm::mix(viewFrustum.getNearBottomLeft(), viewFrustum.getFarBottomLeft(), focalProportion); + glm::vec3 focalBottomRight = glm::mix(viewFrustum.getNearBottomRight(), + viewFrustum.getFarBottomRight(), focalProportion); + glVertex3f(focalBottomLeft.x, focalBottomLeft.y, focalBottomLeft.z); + glVertex3f(focalBottomRight.x, focalBottomRight.y, focalBottomRight.z); + + // focal plane - top edge + glm::vec3 focalTopLeft = glm::mix(viewFrustum.getNearTopLeft(), viewFrustum.getFarTopLeft(), focalProportion); + glm::vec3 focalTopRight = glm::mix(viewFrustum.getNearTopRight(), viewFrustum.getFarTopRight(), focalProportion); + glVertex3f(focalTopLeft.x, focalTopLeft.y, focalTopLeft.z); + glVertex3f(focalTopRight.x, focalTopRight.y, focalTopRight.z); + + // focal plane - left edge + glVertex3f(focalBottomLeft.x, focalBottomLeft.y, focalBottomLeft.z); + glVertex3f(focalTopLeft.x, focalTopLeft.y, focalTopLeft.z); + + // focal plane - right edge + glVertex3f(focalBottomRight.x, focalBottomRight.y, focalBottomRight.z); + glVertex3f(focalTopRight.x, focalTopRight.y, focalTopRight.z); } glEnd(); glEnable(GL_LIGHTING); diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index a35dc49ec0..7914ad0165 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -32,6 +32,7 @@ ViewFrustum::ViewFrustum() : _aspectRatio(1.0), _nearClip(0.1), _farClip(500.0), + _focalLength(0.25f), _keyholeRadius(DEFAULT_KEYHOLE_RADIUS), _farTopLeft(0,0,0), _farTopRight(0,0,0), @@ -310,15 +311,16 @@ bool testMatches(float lhs, float rhs) { bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const { bool result = - testMatches(compareTo._position, _position ) && - testMatches(compareTo._direction, _direction ) && - testMatches(compareTo._up, _up ) && - testMatches(compareTo._right, _right ) && - testMatches(compareTo._fieldOfView, _fieldOfView ) && - testMatches(compareTo._aspectRatio, _aspectRatio ) && - testMatches(compareTo._nearClip, _nearClip ) && - testMatches(compareTo._farClip, _farClip ) && - testMatches(compareTo._eyeOffsetPosition, _eyeOffsetPosition ) && + testMatches(compareTo._position, _position) && + testMatches(compareTo._direction, _direction) && + testMatches(compareTo._up, _up) && + testMatches(compareTo._right, _right) && + testMatches(compareTo._fieldOfView, _fieldOfView) && + testMatches(compareTo._aspectRatio, _aspectRatio) && + testMatches(compareTo._nearClip, _nearClip) && + testMatches(compareTo._farClip, _farClip) && + testMatches(compareTo._focalLength, _focalLength) && + testMatches(compareTo._eyeOffsetPosition, _eyeOffsetPosition) && testMatches(compareTo._eyeOffsetOrientation, _eyeOffsetOrientation); if (!result && debug) { @@ -351,6 +353,9 @@ bool ViewFrustum::matches(const ViewFrustum& compareTo, bool debug) const { qDebug("%s -- compareTo._farClip=%f _farClip=%f\n", (testMatches(compareTo._farClip, _farClip) ? "MATCHES " : "NO MATCH"), compareTo._farClip, _farClip); + qDebug("%s -- compareTo._focalLength=%f _focalLength=%f\n", + (testMatches(compareTo._focalLength, _focalLength) ? "MATCHES " : "NO MATCH"), + compareTo._focalLength, _focalLength); 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, @@ -401,13 +406,17 @@ void ViewFrustum::computeOffAxisFrustum(float& left, float& right, float& bottom nearClipPlane = glm::vec4(-normal.x, -normal.y, -normal.z, glm::dot(normal, corners[0])); farClipPlane = glm::vec4(normal.x, normal.y, normal.z, -glm::dot(normal, corners[4])); + // compute the focal proportion (zero is near clip, one is far clip) + float focalProportion = (_focalLength - _nearClip) / (_farClip - _nearClip); + // get the extents at Z = -near left = FLT_MAX; right = -FLT_MAX; bottom = FLT_MAX; top = -FLT_MAX; for (int i = 0; i < 4; i++) { - glm::vec4 intersection = corners[i] * (-near / corners[i].z); + glm::vec4 corner = glm::mix(corners[i], corners[i + 4], focalProportion); + glm::vec4 intersection = corner * (-near / corner.z); left = min(left, intersection.x); right = max(right, intersection.x); bottom = min(bottom, intersection.y); @@ -426,6 +435,7 @@ void ViewFrustum::printDebugDetails() const { qDebug("_keyHoleRadius=%f\n", _keyholeRadius); qDebug("_nearClip=%f\n", _nearClip); qDebug("_farClip=%f\n", _farClip); + qDebug("_focalLength=%f\n", _focalLength); 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 22830cb48d..803e52908e 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -39,6 +39,7 @@ public: void setAspectRatio(float a) { _aspectRatio = a; } void setNearClip(float n) { _nearClip = n; } void setFarClip(float f) { _farClip = f; } + void setFocalLength(float length) { _focalLength = length; } void setEyeOffsetPosition(const glm::vec3& p) { _eyeOffsetPosition = p; } void setEyeOffsetOrientation(const glm::quat& o) { _eyeOffsetOrientation = o; } @@ -47,6 +48,7 @@ public: float getAspectRatio() const { return _aspectRatio; } float getNearClip() const { return _nearClip; } float getFarClip() const { return _farClip; } + float getFocalLength() const { return _focalLength; } const glm::vec3& getEyeOffsetPosition() const { return _eyeOffsetPosition; } const glm::quat& getEyeOffsetOrientation() const { return _eyeOffsetOrientation; } @@ -111,12 +113,13 @@ private: glm::vec3 _right; // Lens attributes - float _fieldOfView; - float _aspectRatio; - float _nearClip; - float _farClip; - glm::vec3 _eyeOffsetPosition; - glm::quat _eyeOffsetOrientation; + float _fieldOfView; + float _aspectRatio; + float _nearClip; + float _farClip; + float _focalLength; + glm::vec3 _eyeOffsetPosition; + glm::quat _eyeOffsetOrientation; // keyhole attributes float _keyholeRadius; From f475163072a5c6dd2f76ecf9eb36a0bd5c55583f Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Sep 2013 16:20:13 -0700 Subject: [PATCH 03/14] I believe this should fix the offset in mirror mode. --- interface/src/Application.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 741cb6ad52..a507f9c4e0 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2155,8 +2155,9 @@ void Application::displaySide(Camera& whichCamera) { // transform by eye offset // flip x if in mirror mode (also requires reversing winding order for backface culling) + float eyeOffsetSign = 1.0f; if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - glScalef(-1.0f, 1.0f, 1.0f); + glScalef(eyeOffsetSign = -1.0f, 1.0f, 1.0f); glFrontFace(GL_CW); } else { @@ -2167,7 +2168,7 @@ void Application::displaySide(Camera& whichCamera) { glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation(); glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient); glRotatef(-glm::angle(eyeOffsetOrient), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); - glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); + glTranslatef(-eyeOffsetPos.x * eyeOffsetSign, -eyeOffsetPos.y, -eyeOffsetPos.z); // transform view according to whichCamera // could be myCamera (if in normal mode) From 38dd176506cf4f4b535dd574293c2386946f838b Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Sep 2013 16:43:22 -0700 Subject: [PATCH 04/14] Fix for off-by-one-frame error. --- interface/src/Application.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a507f9c4e0..0f7cee3da6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -423,9 +423,6 @@ void Application::resizeGL(int width, int height) { resetCamerasOnResizeGL(_viewFrustumOffsetCamera, width, height); resetCamerasOnResizeGL(_myCamera, width, height); - // Tell our viewFrustum about this change, using the application camera - loadViewFrustum(_myCamera, _viewFrustum); - glViewport(0, 0, width, height); // shouldn't this account for the menu??? updateProjectionMatrix(); @@ -436,6 +433,9 @@ void Application::updateProjectionMatrix() { glMatrixMode(GL_PROJECTION); glLoadIdentity(); + // Tell our viewFrustum about this change, using the application camera + loadViewFrustum(_myCamera, _viewFrustum); + float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); From 1a767f3e081961779d56ebe58b1e01bb33f92472 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Sep 2013 16:52:32 -0700 Subject: [PATCH 05/14] Bump up the offset scale for Faceshift. --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 0f7cee3da6..43c7a8f585 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1813,7 +1813,7 @@ void Application::update(float deltaTime) { if (Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) { if (_faceshift.isActive()) { - const float EYE_OFFSET_SCALE = 0.005f; + const float EYE_OFFSET_SCALE = 0.025f; glm::vec3 position = _faceshift.getHeadTranslation() * EYE_OFFSET_SCALE; _myCamera.setEyeOffsetPosition(glm::vec3(-position.x, position.y, position.z)); updateProjectionMatrix(); From 699007691bd425770d44ca763729e4b91cd32790 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 6 Sep 2013 17:50:16 -0700 Subject: [PATCH 06/14] Simplification. --- interface/src/Application.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 43c7a8f585..a473469734 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1812,16 +1812,17 @@ void Application::update(float deltaTime) { } if (Menu::getInstance()->isOptionChecked(MenuOption::OffAxisProjection)) { + float xSign = Menu::getInstance()->isOptionChecked(MenuOption::Mirror) ? 1.0f : -1.0f; if (_faceshift.isActive()) { const float EYE_OFFSET_SCALE = 0.025f; glm::vec3 position = _faceshift.getHeadTranslation() * EYE_OFFSET_SCALE; - _myCamera.setEyeOffsetPosition(glm::vec3(-position.x, position.y, position.z)); + _myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, position.y, position.z)); updateProjectionMatrix(); } else if (_webcam.isActive()) { - const float EYE_OFFSET_SCALE = 0.1f; + const float EYE_OFFSET_SCALE = 0.5f; glm::vec3 position = _webcam.getEstimatedPosition() * EYE_OFFSET_SCALE; - _myCamera.setEyeOffsetPosition(glm::vec3(-position.x, -position.y, position.z)); + _myCamera.setEyeOffsetPosition(glm::vec3(position.x * xSign, -position.y, position.z)); updateProjectionMatrix(); } } @@ -1974,15 +1975,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { viewFrustum.setFieldOfView(fov); viewFrustum.setNearClip(nearClip); viewFrustum.setFarClip(farClip); - - // when mirrored, we must flip the eye offset in x to get the correct frustum - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - glm::vec3 position = camera.getEyeOffsetPosition(); - viewFrustum.setEyeOffsetPosition(glm::vec3(-position.x, position.y, position.z)); - - } else { - viewFrustum.setEyeOffsetPosition(camera.getEyeOffsetPosition()); - } + viewFrustum.setEyeOffsetPosition(camera.getEyeOffsetPosition()); viewFrustum.setEyeOffsetOrientation(camera.getEyeOffsetOrientation()); // Ask the ViewFrustum class to calculate our corners @@ -2155,9 +2148,8 @@ void Application::displaySide(Camera& whichCamera) { // transform by eye offset // flip x if in mirror mode (also requires reversing winding order for backface culling) - float eyeOffsetSign = 1.0f; if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - glScalef(eyeOffsetSign = -1.0f, 1.0f, 1.0f); + glScalef(-1.0f, 1.0f, 1.0f); glFrontFace(GL_CW); } else { @@ -2168,7 +2160,7 @@ void Application::displaySide(Camera& whichCamera) { glm::quat eyeOffsetOrient = whichCamera.getEyeOffsetOrientation(); glm::vec3 eyeOffsetAxis = glm::axis(eyeOffsetOrient); glRotatef(-glm::angle(eyeOffsetOrient), eyeOffsetAxis.x, eyeOffsetAxis.y, eyeOffsetAxis.z); - glTranslatef(-eyeOffsetPos.x * eyeOffsetSign, -eyeOffsetPos.y, -eyeOffsetPos.z); + glTranslatef(-eyeOffsetPos.x, -eyeOffsetPos.y, -eyeOffsetPos.z); // transform view according to whichCamera // could be myCamera (if in normal mode) From ddf92b39c76408836d4a54e1f7202f44f71fe63d Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sun, 8 Sep 2013 17:52:35 -0700 Subject: [PATCH 07/14] Fix for off-axis ambient occlusion. --- .../resources/shaders/ambient_occlusion.frag | 3 +-- interface/src/Application.cpp | 22 ++++++++++++------- interface/src/Application.h | 4 ++++ .../src/renderer/AmbientOcclusionEffect.cpp | 2 +- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/interface/resources/shaders/ambient_occlusion.frag b/interface/resources/shaders/ambient_occlusion.frag index 4e87ac3221..b3a054cc67 100644 --- a/interface/resources/shaders/ambient_occlusion.frag +++ b/interface/resources/shaders/ambient_occlusion.frag @@ -44,8 +44,7 @@ float texCoordToViewSpaceZ(vec2 texCoord) { // given a texture coordinate, returns the 3D view space coordinate vec3 texCoordToViewSpace(vec2 texCoord) { float z = texCoordToViewSpaceZ(texCoord); - return vec3(((texCoord * 2.0 - vec2(1.0 - gl_ProjectionMatrix[2][0], 1.0)) * - (rightTop - leftBottom) + rightTop + leftBottom) * z / (-2.0 * near), z); + return vec3((leftBottom + texCoord * (rightTop - leftBottom)) * (-z / near), z); } void main(void) { diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a473469734..ea61179057 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -438,7 +438,7 @@ void Application::updateProjectionMatrix() { float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; - _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); + computeOffAxisFrustum(left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); // If we're in Display Frustum mode, then we want to use the slightly adjust near/far clip values of the // _viewFrustumOffsetCamera, so that we can see more of the application content in the application's frustum @@ -446,13 +446,6 @@ void Application::updateProjectionMatrix() { nearVal = _viewFrustumOffsetCamera.getNearClip(); farVal = _viewFrustumOffsetCamera.getFarClip(); } - - // when mirrored, we must flip left and right - if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { - float tmp = left; - left = -right; - right = -tmp; - } glFrustum(left, right, bottom, top, nearVal, farVal); glMatrixMode(GL_MODELVIEW); @@ -2144,6 +2137,19 @@ void Application::setupWorldLight(Camera& whichCamera) { glMateriali(GL_FRONT, GL_SHININESS, 96); } +void Application::computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& near, + float& far, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const { + + _viewFrustum.computeOffAxisFrustum(left, right, bottom, top, near, far, nearClipPlane, farClipPlane); + + // when mirrored, we must flip left and right + if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) { + float tmp = left; + left = -right; + right = -tmp; + } +} + void Application::displaySide(Camera& whichCamera) { // transform by eye offset diff --git a/interface/src/Application.h b/interface/src/Application.h index 0630d3cbca..8bb3106375 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -135,6 +135,10 @@ public: void setupWorldLight(Camera& whichCamera); + /// Computes the off-axis frustum parameters for the view frustum, taking mirroring into account. + void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& near, + float& far, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const; + virtual void nodeAdded(Node* node); virtual void nodeKilled(Node* node); virtual void packetSentNotification(ssize_t length); diff --git a/interface/src/renderer/AmbientOcclusionEffect.cpp b/interface/src/renderer/AmbientOcclusionEffect.cpp index 2169ec00af..907ec7a863 100644 --- a/interface/src/renderer/AmbientOcclusionEffect.cpp +++ b/interface/src/renderer/AmbientOcclusionEffect.cpp @@ -103,7 +103,7 @@ void AmbientOcclusionEffect::render() { float left, right, bottom, top, nearVal, farVal; glm::vec4 nearClipPlane, farClipPlane; - Application::getInstance()->getViewFrustum()->computeOffAxisFrustum( + Application::getInstance()->computeOffAxisFrustum( left, right, bottom, top, nearVal, farVal, nearClipPlane, farClipPlane); _occlusionProgram->bind(); From 49050320901cf755937d7659cdc65d0e86943b04 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Sep 2013 09:44:43 -0700 Subject: [PATCH 08/14] allow forking of multiple assignment-clients from the main target --- assignment-client/src/main.cpp | 42 ++++++++++++++++++++++++++----- domain-server/src/main.cpp | 6 ++++- libraries/shared/src/NodeList.cpp | 18 ++++++------- libraries/shared/src/NodeList.h | 4 +-- 4 files changed, 52 insertions(+), 18 deletions(-) diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 1da0a0215a..67d2a1e021 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -18,13 +18,47 @@ const long long ASSIGNMENT_REQUEST_INTERVAL_USECS = 1 * 1000 * 1000; + int main(int argc, const char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); + sockaddr_in customAssignmentSocket = {}; + + // grab the overriden assignment-server hostname from argv, if it exists + const char* customAssignmentServer = getCmdOption(argc, argv, "-a"); + if (customAssignmentServer) { + customAssignmentSocket = socketForHostnameAndHostOrderPort(customAssignmentServer, ASSIGNMENT_SERVER_PORT); + } + + const char* NUM_FORKS_PARAMETER = "-n"; + const char* numForksIncludingParentString = getCmdOption(argc, argv, NUM_FORKS_PARAMETER); + + if (numForksIncludingParentString) { + int numForksIncludingParent = atoi(numForksIncludingParentString); + qDebug() << "Starting" << numForksIncludingParent << "assignment clients."; + + int processID = 0; + + // fire off as many children as we need (this is one less than the parent since the parent will run as well) + for (int i = 0; i < numForksIncludingParent - 1; i++) { + processID = fork(); + + if (processID == 0) { + // this is one of the children, break so we don't start a fork bomb + break; + } + } + } + // create a NodeList as an unassigned client NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); + // set the custom assignment socket if we have it + if (customAssignmentSocket.sin_addr.s_addr != 0) { + nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentSocket); + } + // change the timeout on the nodelist socket to be as often as we want to re-request nodeList->getNodeSocket()->setBlockingReceiveTimeoutInUsecs(ASSIGNMENT_REQUEST_INTERVAL_USECS); @@ -34,10 +68,8 @@ int main(int argc, const char* argv[]) { ssize_t receivedBytes = 0; // grab the assignment pool from argv, if it was passed - const char* assignmentPool = getCmdOption(argc, argv, "-p"); - - // set the overriden assignment-server hostname from argv, if it exists - nodeList->setAssignmentServerHostname(getCmdOption(argc, argv, "-a")); + const char* ASSIGNMENT_POOL_PARAMETER = "-p"; + const char* assignmentPool = getCmdOption(argc, argv, ASSIGNMENT_POOL_PARAMETER); // create a request assignment, accept all assignments, pass the desired pool (if it exists) Assignment requestAssignment(Assignment::Request, Assignment::All, assignmentPool); @@ -46,7 +78,6 @@ int main(int argc, const char* argv[]) { if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { gettimeofday(&lastRequest, NULL); // if we're here we have no assignment, so send a request - qDebug() << "Sending an assignment request -" << requestAssignment; nodeList->sendAssignment(requestAssignment); } @@ -69,7 +100,6 @@ int main(int argc, const char* argv[]) { if (deployedAssignment.getType() == Assignment::AudioMixer) { AudioMixer::run(); } else { - qDebug() << "Running as an avatar mixer!"; AvatarMixer::run(); } diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 32a88e8e08..c8916f1c59 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -89,7 +89,11 @@ int main(int argc, const char* argv[]) { const char* assignmentPool = getCmdOption(argc, argv, "-p"); // grab the overriden assignment-server hostname from argv, if it exists - nodeList->setAssignmentServerHostname(getCmdOption(argc, argv, "-a")); + const char* customAssignmentServer = getCmdOption(argc, argv, "-a"); + if (customAssignmentServer) { + sockaddr_in customAssignmentSocket = socketForHostnameAndHostOrderPort(customAssignmentServer, ASSIGNMENT_SERVER_PORT); + nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentSocket); + } // use a map to keep track of iterations of silence for assignment creation requests const long long ASSIGNMENT_SILENCE_MAX_USECS = 5 * 1000 * 1000; diff --git a/libraries/shared/src/NodeList.cpp b/libraries/shared/src/NodeList.cpp index ad5876f622..4d042b0f63 100644 --- a/libraries/shared/src/NodeList.cpp +++ b/libraries/shared/src/NodeList.cpp @@ -65,7 +65,8 @@ NodeList::NodeList(char newOwnerType, unsigned short int newSocketListenPort) : _nodeTypesOfInterest(NULL), _ownerID(UNKNOWN_NODE_ID), _lastNodeID(UNKNOWN_NODE_ID + 1), - _numNoReplyDomainCheckIns(0) + _numNoReplyDomainCheckIns(0), + _assignmentServerSocket(NULL) { memcpy(_domainHostname, DEFAULT_DOMAIN_HOSTNAME, sizeof(DEFAULT_DOMAIN_HOSTNAME)); memcpy(_domainIP, DEFAULT_DOMAIN_IP, sizeof(DEFAULT_DOMAIN_IP)); @@ -376,7 +377,8 @@ int NodeList::processDomainServerList(unsigned char* packetData, size_t dataByte } const char GLOBAL_ASSIGNMENT_SERVER_HOSTNAME[] = "assignment.highfidelity.io"; - +const sockaddr_in GLOBAL_ASSIGNMENT_SOCKET = socketForHostnameAndHostOrderPort(GLOBAL_ASSIGNMENT_SERVER_HOSTNAME, + ASSIGNMENT_SERVER_PORT); void NodeList::sendAssignment(Assignment& assignment) { unsigned char assignmentPacket[MAX_PACKET_SIZE]; @@ -387,13 +389,11 @@ void NodeList::sendAssignment(Assignment& assignment) { int numHeaderBytes = populateTypeAndVersion(assignmentPacket, assignmentPacketType); int numAssignmentBytes = assignment.packToBuffer(assignmentPacket + numHeaderBytes); - // setup the assignmentServerSocket once, use a custom assignmentServerHostname if it is present - static sockaddr_in assignmentServerSocket = socketForHostnameAndHostOrderPort((_assignmentServerHostname != NULL - ? (const char*) _assignmentServerHostname - : GLOBAL_ASSIGNMENT_SERVER_HOSTNAME), - ASSIGNMENT_SERVER_PORT); - - _nodeSocket.send((sockaddr*) &assignmentServerSocket, assignmentPacket, numHeaderBytes + numAssignmentBytes); + sockaddr* assignmentServerSocket = (_assignmentServerSocket == NULL) + ? (sockaddr*) &GLOBAL_ASSIGNMENT_SOCKET + : _assignmentServerSocket; + + _nodeSocket.send((sockaddr*) assignmentServerSocket, assignmentPacket, numHeaderBytes + numAssignmentBytes); } Node* NodeList::addOrUpdateNode(sockaddr* publicSocket, sockaddr* localSocket, char nodeType, uint16_t nodeId) { diff --git a/libraries/shared/src/NodeList.h b/libraries/shared/src/NodeList.h index dad422a29b..ea94e8c080 100644 --- a/libraries/shared/src/NodeList.h +++ b/libraries/shared/src/NodeList.h @@ -99,7 +99,7 @@ public: void sendDomainServerCheckIn(); int processDomainServerList(unsigned char *packetData, size_t dataBytes); - void setAssignmentServerHostname(const char* serverHostname) { _assignmentServerHostname = serverHostname; } + void setAssignmentServerSocket(sockaddr* serverSocket) { _assignmentServerSocket = serverSocket; } void sendAssignment(Assignment& assignment); Node* nodeWithAddress(sockaddr *senderAddress); @@ -152,7 +152,7 @@ private: pthread_t removeSilentNodesThread; pthread_t checkInWithDomainServerThread; int _numNoReplyDomainCheckIns; - const char* _assignmentServerHostname; + sockaddr* _assignmentServerSocket; void handlePingReply(sockaddr *nodeAddress); void timePingReply(sockaddr *nodeAddress, unsigned char *packetData); From 2fd043b55c2588cea2b059cc4e612e4ba2a9720f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Sep 2013 10:02:30 -0700 Subject: [PATCH 09/14] code review comments --- domain-server/src/main.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index c8916f1c59..4c13888ee3 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -85,11 +85,14 @@ int main(int argc, const char* argv[]) { timeval lastStatSendTime = {}; + const char ASSIGNMENT_POOL_OPTION = "-p"; + const char ASSIGNMENT_SERVER_OPTION = "-a"; + // set our assignment pool from argv, if it exists - const char* assignmentPool = getCmdOption(argc, argv, "-p"); + const char* assignmentPool = getCmdOption(argc, argv, ASSIGNMENT_POOL_OPTION); // grab the overriden assignment-server hostname from argv, if it exists - const char* customAssignmentServer = getCmdOption(argc, argv, "-a"); + const char* customAssignmentServer = getCmdOption(argc, argv, ASSIGNMENT_SERVER_OPTION); if (customAssignmentServer) { sockaddr_in customAssignmentSocket = socketForHostnameAndHostOrderPort(customAssignmentServer, ASSIGNMENT_SERVER_PORT); nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentSocket); @@ -100,8 +103,8 @@ int main(int argc, const char* argv[]) { // as a domain-server we will always want an audio mixer and avatar mixer // setup the create assignment pointers for those - Assignment *audioAssignment = NULL; - Assignment *avatarAssignment = NULL; + Assignment* audioAssignment = NULL; + Assignment* avatarAssignment = NULL; while (true) { if (!nodeList->soloNodeOfType(NODE_TYPE_AUDIO_MIXER)) { From 64e3c19a8c789db748a0519e67ae8440d73d29c2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Sep 2013 10:07:31 -0700 Subject: [PATCH 10/14] fix an incorrectly typed const --- domain-server/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 4c13888ee3..07b67db85d 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -85,8 +85,8 @@ int main(int argc, const char* argv[]) { timeval lastStatSendTime = {}; - const char ASSIGNMENT_POOL_OPTION = "-p"; - const char ASSIGNMENT_SERVER_OPTION = "-a"; + const char ASSIGNMENT_POOL_OPTION[] = "-p"; + const char ASSIGNMENT_SERVER_OPTION[]g = "-a"; // set our assignment pool from argv, if it exists const char* assignmentPool = getCmdOption(argc, argv, ASSIGNMENT_POOL_OPTION); From d1c602df0768960ab713ba78b7e188174de822d9 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Sep 2013 10:10:16 -0700 Subject: [PATCH 11/14] remove an extra g --- domain-server/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 07b67db85d..0d51671e0c 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -86,7 +86,7 @@ int main(int argc, const char* argv[]) { timeval lastStatSendTime = {}; const char ASSIGNMENT_POOL_OPTION[] = "-p"; - const char ASSIGNMENT_SERVER_OPTION[]g = "-a"; + const char ASSIGNMENT_SERVER_OPTION[] = "-a"; // set our assignment pool from argv, if it exists const char* assignmentPool = getCmdOption(argc, argv, ASSIGNMENT_POOL_OPTION); From bb073bdff3f4a2519ed2ae0c83cfe9549dd47b9b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Sep 2013 11:59:58 -0700 Subject: [PATCH 12/14] fork off n children and keep the parent process as a monitor --- assignment-client/src/main.cpp | 126 ++++++++++++++++++--------------- 1 file changed, 68 insertions(+), 58 deletions(-) diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 67d2a1e021..72ae826ef2 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -32,16 +32,19 @@ int main(int argc, const char* argv[]) { } const char* NUM_FORKS_PARAMETER = "-n"; - const char* numForksIncludingParentString = getCmdOption(argc, argv, NUM_FORKS_PARAMETER); + const char* numForksString = getCmdOption(argc, argv, NUM_FORKS_PARAMETER); - if (numForksIncludingParentString) { - int numForksIncludingParent = atoi(numForksIncludingParentString); - qDebug() << "Starting" << numForksIncludingParent << "assignment clients."; + int processID = 0; + int numForks = 0; + + if (numForksString) { + numForks = atoi(numForksString); + qDebug() << "Starting" << numForks << "assignment clients."; + - int processID = 0; // fire off as many children as we need (this is one less than the parent since the parent will run as well) - for (int i = 0; i < numForksIncludingParent - 1; i++) { + for (int i = 0; i < numForks; i++) { processID = fork(); if (processID == 0) { @@ -51,63 +54,70 @@ int main(int argc, const char* argv[]) { } } - // create a NodeList as an unassigned client - NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); - - // set the custom assignment socket if we have it - if (customAssignmentSocket.sin_addr.s_addr != 0) { - nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentSocket); - } - - // change the timeout on the nodelist socket to be as often as we want to re-request - nodeList->getNodeSocket()->setBlockingReceiveTimeoutInUsecs(ASSIGNMENT_REQUEST_INTERVAL_USECS); - - timeval lastRequest = {}; - - unsigned char packetData[MAX_PACKET_SIZE]; - ssize_t receivedBytes = 0; - - // grab the assignment pool from argv, if it was passed - const char* ASSIGNMENT_POOL_PARAMETER = "-p"; - const char* assignmentPool = getCmdOption(argc, argv, ASSIGNMENT_POOL_PARAMETER); - - // create a request assignment, accept all assignments, pass the desired pool (if it exists) - Assignment requestAssignment(Assignment::Request, Assignment::All, assignmentPool); - - while (true) { - if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { - gettimeofday(&lastRequest, NULL); - // if we're here we have no assignment, so send a request - nodeList->sendAssignment(requestAssignment); + if (processID == 0 || numForks == 0) { + // this is one of the child forks or there is a single assignment client, continue assignment-client execution + + // create a NodeList as an unassigned client + NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); + + // set the custom assignment socket if we have it + if (customAssignmentSocket.sin_addr.s_addr != 0) { + nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentSocket); } - if (nodeList->getNodeSocket()->receive(packetData, &receivedBytes) && - packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT && packetVersionMatch(packetData)) { + // change the timeout on the nodelist socket to be as often as we want to re-request + nodeList->getNodeSocket()->setBlockingReceiveTimeoutInUsecs(ASSIGNMENT_REQUEST_INTERVAL_USECS); + + timeval lastRequest = {}; + + unsigned char packetData[MAX_PACKET_SIZE]; + ssize_t receivedBytes = 0; + + // grab the assignment pool from argv, if it was passed + const char* ASSIGNMENT_POOL_PARAMETER = "-p"; + const char* assignmentPool = getCmdOption(argc, argv, ASSIGNMENT_POOL_PARAMETER); + + // create a request assignment, accept all assignments, pass the desired pool (if it exists) + Assignment requestAssignment(Assignment::Request, Assignment::All, assignmentPool); + + while (true) { + if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { + gettimeofday(&lastRequest, NULL); + // if we're here we have no assignment, so send a request + nodeList->sendAssignment(requestAssignment); + } - // construct the deployed assignment from the packet data - Assignment deployedAssignment(packetData, receivedBytes); - - qDebug() << "Received an assignment - " << deployedAssignment << "\n"; - - // switch our nodelist DOMAIN_IP to the ip receieved in the assignment - if (deployedAssignment.getDomainSocket()->sa_family == AF_INET) { - in_addr domainSocketAddr = ((sockaddr_in*) deployedAssignment.getDomainSocket())->sin_addr; - nodeList->setDomainIP(inet_ntoa(domainSocketAddr)); + if (nodeList->getNodeSocket()->receive(packetData, &receivedBytes) && + packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT && packetVersionMatch(packetData)) { - qDebug() << "Changed domain IP to " << inet_ntoa(domainSocketAddr); + // construct the deployed assignment from the packet data + Assignment deployedAssignment(packetData, receivedBytes); + + qDebug() << "Received an assignment - " << deployedAssignment << "\n"; + + // switch our nodelist DOMAIN_IP to the ip receieved in the assignment + if (deployedAssignment.getDomainSocket()->sa_family == AF_INET) { + in_addr domainSocketAddr = ((sockaddr_in*) deployedAssignment.getDomainSocket())->sin_addr; + nodeList->setDomainIP(inet_ntoa(domainSocketAddr)); + + qDebug() << "Changed domain IP to " << inet_ntoa(domainSocketAddr); + } + + if (deployedAssignment.getType() == Assignment::AudioMixer) { + AudioMixer::run(); + } else { + AvatarMixer::run(); + } + + qDebug() << "Assignment finished or never started - waiting for new assignment"; + + // reset our NodeList by switching back to unassigned and clearing the list + nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); + nodeList->clear(); } - - if (deployedAssignment.getType() == Assignment::AudioMixer) { - AudioMixer::run(); - } else { - AvatarMixer::run(); - } - - qDebug() << "Assignment finished or never started - waiting for new assignment"; - - // reset our NodeList by switching back to unassigned and clearing the list - nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); - nodeList->clear(); } + } else { + // don't bail until all children have finished + wait(NULL); } } \ No newline at end of file From f770dd623bb4d69c9fc7c8dee6b03ed0d39e5969 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Sep 2013 12:31:53 -0700 Subject: [PATCH 13/14] have parent assignment-client make sure there are always n --- assignment-client/src/main.cpp | 207 ++++++++++++++++++++++----------- 1 file changed, 137 insertions(+), 70 deletions(-) diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 72ae826ef2..50e4f069a5 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -7,6 +7,8 @@ // #include +#include +#include #include #include @@ -18,106 +20,171 @@ const long long ASSIGNMENT_REQUEST_INTERVAL_USECS = 1 * 1000 * 1000; +pid_t* childForks = NULL; +sockaddr_in customAssignmentSocket = {}; +const char* assignmentPool = NULL; +int numForks = 0; + +void childClient() { + // this is one of the child forks or there is a single assignment client, continue assignment-client execution + + // create a NodeList as an unassigned client + NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); + + // set the custom assignment socket if we have it + if (customAssignmentSocket.sin_addr.s_addr != 0) { + nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentSocket); + } + + // change the timeout on the nodelist socket to be as often as we want to re-request + nodeList->getNodeSocket()->setBlockingReceiveTimeoutInUsecs(ASSIGNMENT_REQUEST_INTERVAL_USECS); + + timeval lastRequest = {}; + + unsigned char packetData[MAX_PACKET_SIZE]; + ssize_t receivedBytes = 0; + + // create a request assignment, accept all assignments, pass the desired pool (if it exists) + Assignment requestAssignment(Assignment::Request, Assignment::All, assignmentPool); + + while (true) { + if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { + gettimeofday(&lastRequest, NULL); + // if we're here we have no assignment, so send a request + nodeList->sendAssignment(requestAssignment); + } + + if (nodeList->getNodeSocket()->receive(packetData, &receivedBytes) && + packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT && packetVersionMatch(packetData)) { + + // construct the deployed assignment from the packet data + Assignment deployedAssignment(packetData, receivedBytes); + + qDebug() << "Received an assignment - " << deployedAssignment << "\n"; + + // switch our nodelist DOMAIN_IP to the ip receieved in the assignment + if (deployedAssignment.getDomainSocket()->sa_family == AF_INET) { + in_addr domainSocketAddr = ((sockaddr_in*) deployedAssignment.getDomainSocket())->sin_addr; + nodeList->setDomainIP(inet_ntoa(domainSocketAddr)); + + qDebug() << "Changed domain IP to " << inet_ntoa(domainSocketAddr); + } + + if (deployedAssignment.getType() == Assignment::AudioMixer) { + AudioMixer::run(); + } else { + AvatarMixer::run(); + } + + qDebug() << "Assignment finished or never started - waiting for new assignment"; + + // reset our NodeList by switching back to unassigned and clearing the list + nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); + nodeList->clear(); + } + } +} + +void sigchldHandler(int sig) { + pid_t processID; + int status; + + while ((processID = waitpid(-1, &status, WNOHANG)) != -1) { + if (processID == 0) { + // there are no more children to process, break out of here + break; + } + + qDebug() << "Handling death of" << processID; + + int newForkProcessID = 0; + + // find the dead process in the array of child forks + for (int i = 0; i < ::numForks; i++) { + if (::childForks[i] == processID) { + qDebug() << "Matched" << ::childForks[i] << "with" << processID; + + newForkProcessID = fork(); + if (newForkProcessID == 0) { + // this is the child, call childClient + childClient(); + + // break out so we don't fork bomb + break; + } else { + // this is the parent, replace the dead process with the new one + ::childForks[i] = newForkProcessID; + break; + } + } + } + } +} + +void parentMonitor() { + + struct sigaction sa; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = sigchldHandler; + + sigaction(SIGCHLD, &sa, NULL); + + pid_t childID = 0; + + // don't bail until all children have finished + while ((childID = waitpid(-1, NULL, 0))) { + if (errno == ECHILD) { + break; + } + } + + // delete the array of pid_t holding the forked process IDs + delete[] ::childForks; +} int main(int argc, const char* argv[]) { setvbuf(stdout, NULL, _IOLBF, 0); - sockaddr_in customAssignmentSocket = {}; - // grab the overriden assignment-server hostname from argv, if it exists const char* customAssignmentServer = getCmdOption(argc, argv, "-a"); if (customAssignmentServer) { - customAssignmentSocket = socketForHostnameAndHostOrderPort(customAssignmentServer, ASSIGNMENT_SERVER_PORT); + ::customAssignmentSocket = socketForHostnameAndHostOrderPort(customAssignmentServer, ASSIGNMENT_SERVER_PORT); } const char* NUM_FORKS_PARAMETER = "-n"; const char* numForksString = getCmdOption(argc, argv, NUM_FORKS_PARAMETER); + // grab the assignment pool from argv, if it was passed + const char* ASSIGNMENT_POOL_PARAMETER = "-p"; + ::assignmentPool = getCmdOption(argc, argv, ASSIGNMENT_POOL_PARAMETER); + int processID = 0; - int numForks = 0; if (numForksString) { - numForks = atoi(numForksString); + ::numForks = atoi(numForksString); qDebug() << "Starting" << numForks << "assignment clients."; - + ::childForks = new pid_t[numForks]; // fire off as many children as we need (this is one less than the parent since the parent will run as well) for (int i = 0; i < numForks; i++) { processID = fork(); if (processID == 0) { - // this is one of the children, break so we don't start a fork bomb + // this is in one of the children, break so we don't start a fork bomb break; + } else { + // this is in the parent, save the ID of the forked process + childForks[i] = processID; } } } if (processID == 0 || numForks == 0) { - // this is one of the child forks or there is a single assignment client, continue assignment-client execution - - // create a NodeList as an unassigned client - NodeList* nodeList = NodeList::createInstance(NODE_TYPE_UNASSIGNED); - - // set the custom assignment socket if we have it - if (customAssignmentSocket.sin_addr.s_addr != 0) { - nodeList->setAssignmentServerSocket((sockaddr*) &customAssignmentSocket); - } - - // change the timeout on the nodelist socket to be as often as we want to re-request - nodeList->getNodeSocket()->setBlockingReceiveTimeoutInUsecs(ASSIGNMENT_REQUEST_INTERVAL_USECS); - - timeval lastRequest = {}; - - unsigned char packetData[MAX_PACKET_SIZE]; - ssize_t receivedBytes = 0; - - // grab the assignment pool from argv, if it was passed - const char* ASSIGNMENT_POOL_PARAMETER = "-p"; - const char* assignmentPool = getCmdOption(argc, argv, ASSIGNMENT_POOL_PARAMETER); - - // create a request assignment, accept all assignments, pass the desired pool (if it exists) - Assignment requestAssignment(Assignment::Request, Assignment::All, assignmentPool); - - while (true) { - if (usecTimestampNow() - usecTimestamp(&lastRequest) >= ASSIGNMENT_REQUEST_INTERVAL_USECS) { - gettimeofday(&lastRequest, NULL); - // if we're here we have no assignment, so send a request - nodeList->sendAssignment(requestAssignment); - } - - if (nodeList->getNodeSocket()->receive(packetData, &receivedBytes) && - packetData[0] == PACKET_TYPE_DEPLOY_ASSIGNMENT && packetVersionMatch(packetData)) { - - // construct the deployed assignment from the packet data - Assignment deployedAssignment(packetData, receivedBytes); - - qDebug() << "Received an assignment - " << deployedAssignment << "\n"; - - // switch our nodelist DOMAIN_IP to the ip receieved in the assignment - if (deployedAssignment.getDomainSocket()->sa_family == AF_INET) { - in_addr domainSocketAddr = ((sockaddr_in*) deployedAssignment.getDomainSocket())->sin_addr; - nodeList->setDomainIP(inet_ntoa(domainSocketAddr)); - - qDebug() << "Changed domain IP to " << inet_ntoa(domainSocketAddr); - } - - if (deployedAssignment.getType() == Assignment::AudioMixer) { - AudioMixer::run(); - } else { - AvatarMixer::run(); - } - - qDebug() << "Assignment finished or never started - waiting for new assignment"; - - // reset our NodeList by switching back to unassigned and clearing the list - nodeList->setOwnerType(NODE_TYPE_UNASSIGNED); - nodeList->clear(); - } - } + childClient(); } else { - // don't bail until all children have finished - wait(NULL); + parentMonitor(); } } \ No newline at end of file From 3f941a33715abe16e994ca0e2269bec8c1034152 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 9 Sep 2013 12:42:18 -0700 Subject: [PATCH 14/14] add a missing include for waitpid --- assignment-client/src/main.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/assignment-client/src/main.cpp b/assignment-client/src/main.cpp index 50e4f069a5..130cca9135 100644 --- a/assignment-client/src/main.cpp +++ b/assignment-client/src/main.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include