From a9c18c2af045cc683a69552d8060ee3cce8585c2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Jun 2013 12:28:09 -0700 Subject: [PATCH 01/67] cleaned up line spacing and tabs, added getVertex() --- libraries/voxels/src/AABox.cpp | 688 +++++++++++++++++---------------- libraries/voxels/src/AABox.h | 158 ++++---- 2 files changed, 442 insertions(+), 404 deletions(-) diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index 1b29c70b59..61cbf1ef45 100644 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -1,332 +1,356 @@ -// -// AABox.h - Axis Aligned Boxes -// hifi -// -// Added by Brad Hefta-Gaub on 04/11/13. -// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards -// -// Simple axis aligned box class. -// - -#include "SharedUtil.h" - -#include "AABox.h" -#include "GeometryUtil.h" - - -void AABox::scale(float scale) { - _corner = _corner * scale; - _size = _size * scale; - _center = _center * scale; -} - - -void AABox::setBox(const glm::vec3& corner, const glm::vec3& size) { - _corner = corner; - _size = size; - - // In the event that the caller gave us negative sizes, fix things up to be reasonable - if (_size.x < 0.0) { - _size.x = -size.x; - _corner.x -= _size.x; - } - if (_size.y < 0.0) { - _size.y = -size.y; - _corner.y -= _size.y; - } - if (_size.z < 0.0) { - _size.z = -size.z; - _corner.z -= _size.z; - } - _center = _corner + (_size * 0.5f); -} - -glm::vec3 AABox::getVertexP(const glm::vec3 &normal) const { - glm::vec3 res = _corner; - if (normal.x > 0) - res.x += _size.x; - - if (normal.y > 0) - res.y += _size.y; - - if (normal.z > 0) - res.z += _size.z; - - return(res); -} - - - -glm::vec3 AABox::getVertexN(const glm::vec3 &normal) const { - glm::vec3 res = _corner; - - if (normal.x < 0) - res.x += _size.x; - - if (normal.y < 0) - res.y += _size.y; - - if (normal.z < 0) - res.z += _size.z; - - return(res); -} - -// determines whether a value is within the extents -static bool isWithin(float value, float corner, float size) { - return value >= corner && value <= corner + size; -} - -bool AABox::contains(const glm::vec3& point) const { - return isWithin(point.x, _corner.x, _size.x) && - isWithin(point.y, _corner.y, _size.y) && - isWithin(point.z, _corner.z, _size.z); -} - -// determines whether a value is within the expanded extents -static bool isWithinExpanded(float value, float corner, float size, float expansion) { - return value >= corner - expansion && value <= corner + size + expansion; -} - -bool AABox::expandedContains(const glm::vec3& point, float expansion) const { - return isWithinExpanded(point.x, _corner.x, _size.x, expansion) && - isWithinExpanded(point.y, _corner.y, _size.y, expansion) && - isWithinExpanded(point.z, _corner.z, _size.z, expansion); -} - -// finds the intersection between a ray and the facing plane on one axis -static bool findIntersection(float origin, float direction, float corner, float size, float& distance) { - if (direction > EPSILON) { - distance = (corner - origin) / direction; - return true; - - } else if (direction < -EPSILON) { - distance = (corner + size - origin) / direction; - return true; - } - return false; -} - -bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const { - // handle the trivial cases where the expanded box contains the start or end - if (expandedContains(start, expansion) || expandedContains(end, expansion)) { - return true; - } - // check each axis - glm::vec3 expandedCorner = _corner - glm::vec3(expansion, expansion, expansion); - glm::vec3 expandedSize = _size + glm::vec3(expansion, expansion, expansion) * 2.0f; - glm::vec3 direction = end - start; - float axisDistance; - return (findIntersection(start.x, direction.x, expandedCorner.x, expandedSize.x, axisDistance) && - axisDistance >= 0.0f && axisDistance <= 1.0f && - isWithin(start.y + axisDistance*direction.y, expandedCorner.y, expandedSize.y) && - isWithin(start.z + axisDistance*direction.z, expandedCorner.z, expandedSize.z)) || - (findIntersection(start.y, direction.y, expandedCorner.y, expandedSize.y, axisDistance) && - axisDistance >= 0.0f && axisDistance <= 1.0f && - isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x) && - isWithin(start.z + axisDistance*direction.z, expandedCorner.z, expandedSize.z)) || - (findIntersection(start.z, direction.z, expandedCorner.z, expandedSize.z, axisDistance) && - axisDistance >= 0.0f && axisDistance <= 1.0f && - isWithin(start.y + axisDistance*direction.y, expandedCorner.y, expandedSize.y) && - isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x)); -} - -bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { - // handle the trivial case where the box contains the origin - if (contains(origin)) { - distance = 0; - return true; - } - // check each axis - float axisDistance; - if ((findIntersection(origin.x, direction.x, _corner.x, _size.x, axisDistance) && axisDistance >= 0 && - isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) && - isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z))) { - distance = axisDistance; - face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE; - return true; - } - if ((findIntersection(origin.y, direction.y, _corner.y, _size.y, axisDistance) && axisDistance >= 0 && - isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x) && - isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z))) { - distance = axisDistance; - face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE; - return true; - } - if ((findIntersection(origin.z, direction.z, _corner.z, _size.z, axisDistance) && axisDistance >= 0 && - isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) && - isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x))) { - distance = axisDistance; - face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; - return true; - } - return false; -} - -bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { - glm::vec4 center4 = glm::vec4(center, 1.0f); - - float minPenetrationLength = FLT_MAX; - for (int i = 0; i < FACE_COUNT; i++) { - glm::vec4 facePlane = getPlane((BoxFace)i); - glm::vec3 vector = getClosestPointOnFace(center, (BoxFace)i) - center; - if (glm::dot(center4, getPlane((BoxFace)i)) >= 0.0f) { - // outside this face, so use vector to closest point to determine penetration - return ::findSpherePenetration(vector, glm::vec3(-facePlane), radius, penetration); - } - float vectorLength = glm::length(vector); - if (vectorLength < minPenetrationLength) { - // remember the smallest penetration vector; if we're inside all faces, we'll use that - penetration = (vectorLength < EPSILON) ? glm::vec3(-facePlane) * radius : - vector * ((vectorLength + radius) / -vectorLength); - minPenetrationLength = vectorLength; - } - } - - return true; -} - -bool AABox::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const { - glm::vec4 start4 = glm::vec4(start, 1.0f); - glm::vec4 end4 = glm::vec4(end, 1.0f); - glm::vec4 startToEnd = glm::vec4(end - start, 0.0f); - - float minPenetrationLength = FLT_MAX; - for (int i = 0; i < FACE_COUNT; i++) { - // find the vector from the segment to the closest point on the face (starting from deeper end) - glm::vec4 facePlane = getPlane((BoxFace)i); - glm::vec3 closest = (glm::dot(start4, facePlane) <= glm::dot(end4, facePlane)) ? - getClosestPointOnFace(start4, startToEnd, (BoxFace)i) : getClosestPointOnFace(end4, -startToEnd, (BoxFace)i); - glm::vec3 vector = -computeVectorFromPointToSegment(closest, start, end); - if (glm::dot(vector, glm::vec3(facePlane)) < 0.0f) { - // outside this face, so use vector to closest point to determine penetration - return ::findSpherePenetration(vector, glm::vec3(-facePlane), radius, penetration); - } - float vectorLength = glm::length(vector); - if (vectorLength < minPenetrationLength) { - // remember the smallest penetration vector; if we're inside all faces, we'll use that - penetration = (vectorLength < EPSILON) ? glm::vec3(-facePlane) * radius : - vector * ((vectorLength + radius) / -vectorLength); - minPenetrationLength = vectorLength; - } - } - - return true; -} - -glm::vec3 AABox::getClosestPointOnFace(const glm::vec3& point, BoxFace face) const { - switch (face) { - case MIN_X_FACE: - return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), - glm::vec3(_corner.x, _corner.y + _size.y, _corner.z + _size.z)); - - case MAX_X_FACE: - return glm::clamp(point, glm::vec3(_corner.x + _size.x, _corner.y, _corner.z), - glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z)); - - case MIN_Y_FACE: - return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), - glm::vec3(_corner.x + _size.x, _corner.y, _corner.z + _size.z)); - - case MAX_Y_FACE: - return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _size.y, _corner.z), - glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z)); - - case MIN_Z_FACE: - return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), - glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z)); - - case MAX_Z_FACE: - return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _size.z), - glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z)); - } -} - -glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const { - // check against the four planes that border the face - BoxFace oppositeFace = getOppositeFace(face); - bool anyOutside = false; - for (int i = 0; i < FACE_COUNT; i++) { - if (i == face || i == oppositeFace) { - continue; - } - glm::vec4 iPlane = getPlane((BoxFace)i); - float originDistance = glm::dot(origin, iPlane); - if (originDistance < 0.0f) { - continue; // inside the border - } - anyOutside = true; - float divisor = glm::dot(direction, iPlane); - if (fabs(divisor) < EPSILON) { - continue; // segment is parallel to plane - } - // find intersection and see if it lies within face bounds - float directionalDistance = -originDistance / divisor; - glm::vec4 intersection = origin + direction * directionalDistance; - BoxFace iOppositeFace = getOppositeFace((BoxFace)i); - for (int j = 0; j < FACE_COUNT; j++) { - if (j == face || j == oppositeFace || j == i || j == iOppositeFace) { - continue; - } - if (glm::dot(intersection, getPlane((BoxFace)j)) > 0.0f) { - goto outerContinue; // intersection is out of bounds - } - } - return getClosestPointOnFace(glm::vec3(intersection), face); - - outerContinue: ; - } - - // if we were outside any of the sides, we must check against the diagonals - if (anyOutside) { - int faceAxis = face / 2; - int secondAxis = (faceAxis + 1) % 3; - int thirdAxis = (faceAxis + 2) % 3; - - glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2)); - glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1)); - glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1)); - - glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f, - glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _size) * 0.5f); - glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, - secondAxisMaxPlane + thirdAxisMaxPlane + offset }; - - float minDistance = FLT_MAX; - for (int i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) { - float divisor = glm::dot(direction, diagonals[i]); - if (fabs(divisor) < EPSILON) { - continue; // segment is parallel to diagonal plane - } - minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance); - } - if (minDistance != FLT_MAX) { - return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); - } - } - - // last resort or all inside: clamp origin to face - return getClosestPointOnFace(glm::vec3(origin), face); -} - -glm::vec4 AABox::getPlane(BoxFace face) const { - switch (face) { - case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x); - case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _size.x); - case MIN_Y_FACE: return glm::vec4(0.0f, -1.0f, 0.0f, _corner.y); - case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _size.y); - case MIN_Z_FACE: return glm::vec4(0.0f, 0.0f, -1.0f, _corner.z); - case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _size.z); - } -} - -BoxFace AABox::getOppositeFace(BoxFace face) { - switch (face) { - case MIN_X_FACE: return MAX_X_FACE; - case MAX_X_FACE: return MIN_X_FACE; - case MIN_Y_FACE: return MAX_Y_FACE; - case MAX_Y_FACE: return MIN_Y_FACE; - case MIN_Z_FACE: return MAX_Z_FACE; - case MAX_Z_FACE: return MIN_Z_FACE; - } -} +// +// AABox.h - Axis Aligned Boxes +// hifi +// +// Added by Brad Hefta-Gaub on 04/11/13. +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// +// Simple axis aligned box class. +// + +#include "SharedUtil.h" + +#include "AABox.h" +#include "GeometryUtil.h" + + +void AABox::scale(float scale) { + _corner = _corner * scale; + _size = _size * scale; + _center = _center * scale; +} + + +glm::vec3 AABox::getVertice(BoxVertice vertice) const { + switch (vertice) { + case BOTTOM_LEFT_NEAR: + return _corner + glm::vec3(_size.x, 0, 0); + case BOTTOM_RIGHT_NEAR: + return _corner; + case TOP_RIGHT_NEAR: + return _corner + glm::vec3(0, _size.y, 0); + case TOP_LEFT_NEAR: + return _corner + glm::vec3(_size.x, _size.y, 0); + case BOTTOM_LEFT_FAR: + return _corner + glm::vec3(_size.x, 0, _size.z); + case BOTTOM_RIGHT_FAR: + return _corner + glm::vec3(0, 0, _size.z); + case TOP_RIGHT_FAR: + return _corner + glm::vec3(0, _size.y, _size.z); + case TOP_LEFT_FAR: + return _corner + _size; + } +} + +void AABox::setBox(const glm::vec3& corner, const glm::vec3& size) { + _corner = corner; + _size = size; + + // In the event that the caller gave us negative sizes, fix things up to be reasonable + if (_size.x < 0.0) { + _size.x = -size.x; + _corner.x -= _size.x; + } + if (_size.y < 0.0) { + _size.y = -size.y; + _corner.y -= _size.y; + } + if (_size.z < 0.0) { + _size.z = -size.z; + _corner.z -= _size.z; + } + _center = _corner + (_size * 0.5f); +} + +glm::vec3 AABox::getVertexP(const glm::vec3& normal) const { + glm::vec3 res = _corner; + if (normal.x > 0) { + result.x += _size.x; + } + + if (normal.y > 0) { + result.y += _size.y; + }{ + + if (normal.z > 0) { + result.z += _size.z; + } + + return result; +} + +glm::vec3 AABox::getVertexN(const glm::vec3& normal) const { + glm::vec3 result = _corner; + + if (normal.x < 0) { + result.x += _size.x; + } + + if (normal.y < 0) { + result.y += _size.y; + } + + if (normal.z < 0) { + result.z += _size.z; + } + + return result; +} + +// determines whether a value is within the extents +static bool isWithin(float value, float corner, float size) { + return value >= corner && value <= corner + size; +} + +bool AABox::contains(const glm::vec3& point) const { + return isWithin(point.x, _corner.x, _size.x) && + isWithin(point.y, _corner.y, _size.y) && + isWithin(point.z, _corner.z, _size.z); +} + +// determines whether a value is within the expanded extents +static bool isWithinExpanded(float value, float corner, float size, float expansion) { + return value >= corner - expansion && value <= corner + size + expansion; +} + +bool AABox::expandedContains(const glm::vec3& point, float expansion) const { + return isWithinExpanded(point.x, _corner.x, _size.x, expansion) && + isWithinExpanded(point.y, _corner.y, _size.y, expansion) && + isWithinExpanded(point.z, _corner.z, _size.z, expansion); +} + +// finds the intersection between a ray and the facing plane on one axis +static bool findIntersection(float origin, float direction, float corner, float size, float& distance) { + if (direction > EPSILON) { + distance = (corner - origin) / direction; + return true; + } else if (direction < -EPSILON) { + distance = (corner + size - origin) / direction; + return true; + } + return false; +} + +bool AABox::expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const { + // handle the trivial cases where the expanded box contains the start or end + if (expandedContains(start, expansion) || expandedContains(end, expansion)) { + return true; + } + // check each axis + glm::vec3 expandedCorner = _corner - glm::vec3(expansion, expansion, expansion); + glm::vec3 expandedSize = _size + glm::vec3(expansion, expansion, expansion) * 2.0f; + glm::vec3 direction = end - start; + float axisDistance; + return (findIntersection(start.x, direction.x, expandedCorner.x, expandedSize.x, axisDistance) && + axisDistance >= 0.0f && axisDistance <= 1.0f && + isWithin(start.y + axisDistance*direction.y, expandedCorner.y, expandedSize.y) && + isWithin(start.z + axisDistance*direction.z, expandedCorner.z, expandedSize.z)) || + (findIntersection(start.y, direction.y, expandedCorner.y, expandedSize.y, axisDistance) && + axisDistance >= 0.0f && axisDistance <= 1.0f && + isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x) && + isWithin(start.z + axisDistance*direction.z, expandedCorner.z, expandedSize.z)) || + (findIntersection(start.z, direction.z, expandedCorner.z, expandedSize.z, axisDistance) && + axisDistance >= 0.0f && axisDistance <= 1.0f && + isWithin(start.y + axisDistance*direction.y, expandedCorner.y, expandedSize.y) && + isWithin(start.x + axisDistance*direction.x, expandedCorner.x, expandedSize.x)); +} + +bool AABox::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const { + // handle the trivial case where the box contains the origin + if (contains(origin)) { + distance = 0; + return true; + } + // check each axis + float axisDistance; + if ((findIntersection(origin.x, direction.x, _corner.x, _size.x, axisDistance) && axisDistance >= 0 && + isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) && + isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z))) { + distance = axisDistance; + face = direction.x > 0 ? MIN_X_FACE : MAX_X_FACE; + return true; + } + if ((findIntersection(origin.y, direction.y, _corner.y, _size.y, axisDistance) && axisDistance >= 0 && + isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x) && + isWithin(origin.z + axisDistance*direction.z, _corner.z, _size.z))) { + distance = axisDistance; + face = direction.y > 0 ? MIN_Y_FACE : MAX_Y_FACE; + return true; + } + if ((findIntersection(origin.z, direction.z, _corner.z, _size.z, axisDistance) && axisDistance >= 0 && + isWithin(origin.y + axisDistance*direction.y, _corner.y, _size.y) && + isWithin(origin.x + axisDistance*direction.x, _corner.x, _size.x))) { + distance = axisDistance; + face = direction.z > 0 ? MIN_Z_FACE : MAX_Z_FACE; + return true; + } + return false; +} + +bool AABox::findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const { + glm::vec4 center4 = glm::vec4(center, 1.0f); + + float minPenetrationLength = FLT_MAX; + for (int i = 0; i < FACE_COUNT; i++) { + glm::vec4 facePlane = getPlane((BoxFace)i); + glm::vec3 vector = getClosestPointOnFace(center, (BoxFace)i) - center; + if (glm::dot(center4, getPlane((BoxFace)i)) >= 0.0f) { + // outside this face, so use vector to closest point to determine penetration + return ::findSpherePenetration(vector, glm::vec3(-facePlane), radius, penetration); + } + float vectorLength = glm::length(vector); + if (vectorLength < minPenetrationLength) { + // remember the smallest penetration vector; if we're inside all faces, we'll use that + penetration = (vectorLength < EPSILON) ? glm::vec3(-facePlane) * radius : + vector * ((vectorLength + radius) / -vectorLength); + minPenetrationLength = vectorLength; + } + } + + return true; +} + +bool AABox::findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const { + glm::vec4 start4 = glm::vec4(start, 1.0f); + glm::vec4 end4 = glm::vec4(end, 1.0f); + glm::vec4 startToEnd = glm::vec4(end - start, 0.0f); + + float minPenetrationLength = FLT_MAX; + for (int i = 0; i < FACE_COUNT; i++) { + // find the vector from the segment to the closest point on the face (starting from deeper end) + glm::vec4 facePlane = getPlane((BoxFace)i); + glm::vec3 closest = (glm::dot(start4, facePlane) <= glm::dot(end4, facePlane)) ? + getClosestPointOnFace(start4, startToEnd, (BoxFace)i) : getClosestPointOnFace(end4, -startToEnd, (BoxFace)i); + glm::vec3 vector = -computeVectorFromPointToSegment(closest, start, end); + if (glm::dot(vector, glm::vec3(facePlane)) < 0.0f) { + // outside this face, so use vector to closest point to determine penetration + return ::findSpherePenetration(vector, glm::vec3(-facePlane), radius, penetration); + } + float vectorLength = glm::length(vector); + if (vectorLength < minPenetrationLength) { + // remember the smallest penetration vector; if we're inside all faces, we'll use that + penetration = (vectorLength < EPSILON) ? glm::vec3(-facePlane) * radius : + vector * ((vectorLength + radius) / -vectorLength); + minPenetrationLength = vectorLength; + } + } + + return true; +} + +glm::vec3 AABox::getClosestPointOnFace(const glm::vec3& point, BoxFace face) const { + switch (face) { + case MIN_X_FACE: + return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), + glm::vec3(_corner.x, _corner.y + _size.y, _corner.z + _size.z)); + + case MAX_X_FACE: + return glm::clamp(point, glm::vec3(_corner.x + _size.x, _corner.y, _corner.z), + glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z)); + + case MIN_Y_FACE: + return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), + glm::vec3(_corner.x + _size.x, _corner.y, _corner.z + _size.z)); + + case MAX_Y_FACE: + return glm::clamp(point, glm::vec3(_corner.x, _corner.y + _size.y, _corner.z), + glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z)); + + case MIN_Z_FACE: + return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z), + glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z)); + + case MAX_Z_FACE: + return glm::clamp(point, glm::vec3(_corner.x, _corner.y, _corner.z + _size.z), + glm::vec3(_corner.x + _size.x, _corner.y + _size.y, _corner.z + _size.z)); + } +} + +glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const { + // check against the four planes that border the face + BoxFace oppositeFace = getOppositeFace(face); + bool anyOutside = false; + for (int i = 0; i < FACE_COUNT; i++) { + if (i == face || i == oppositeFace) { + continue; + } + glm::vec4 iPlane = getPlane((BoxFace)i); + float originDistance = glm::dot(origin, iPlane); + if (originDistance < 0.0f) { + continue; // inside the border + } + anyOutside = true; + float divisor = glm::dot(direction, iPlane); + if (fabs(divisor) < EPSILON) { + continue; // segment is parallel to plane + } + // find intersection and see if it lies within face bounds + float directionalDistance = -originDistance / divisor; + glm::vec4 intersection = origin + direction * directionalDistance; + BoxFace iOppositeFace = getOppositeFace((BoxFace)i); + for (int j = 0; j < FACE_COUNT; j++) { + if (j == face || j == oppositeFace || j == i || j == iOppositeFace) { + continue; + } + if (glm::dot(intersection, getPlane((BoxFace)j)) > 0.0f) { + goto outerContinue; // intersection is out of bounds + } + } + return getClosestPointOnFace(glm::vec3(intersection), face); + + outerContinue: ; + } + + // if we were outside any of the sides, we must check against the diagonals + if (anyOutside) { + int faceAxis = face / 2; + int secondAxis = (faceAxis + 1) % 3; + int thirdAxis = (faceAxis + 2) % 3; + + glm::vec4 secondAxisMinPlane = getPlane((BoxFace)(secondAxis * 2)); + glm::vec4 secondAxisMaxPlane = getPlane((BoxFace)(secondAxis * 2 + 1)); + glm::vec4 thirdAxisMaxPlane = getPlane((BoxFace)(thirdAxis * 2 + 1)); + + glm::vec4 offset = glm::vec4(0.0f, 0.0f, 0.0f, + glm::dot(glm::vec3(secondAxisMaxPlane + thirdAxisMaxPlane), _size) * 0.5f); + glm::vec4 diagonals[] = { secondAxisMinPlane + thirdAxisMaxPlane + offset, + secondAxisMaxPlane + thirdAxisMaxPlane + offset }; + + float minDistance = FLT_MAX; + for (int i = 0; i < sizeof(diagonals) / sizeof(diagonals[0]); i++) { + float divisor = glm::dot(direction, diagonals[i]); + if (fabs(divisor) < EPSILON) { + continue; // segment is parallel to diagonal plane + } + minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance); + } + if (minDistance != FLT_MAX) { + return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); + } + } + + // last resort or all inside: clamp origin to face + return getClosestPointOnFace(glm::vec3(origin), face); +} + +glm::vec4 AABox::getPlane(BoxFace face) const { + switch (face) { + case MIN_X_FACE: return glm::vec4(-1.0f, 0.0f, 0.0f, _corner.x); + case MAX_X_FACE: return glm::vec4(1.0f, 0.0f, 0.0f, -_corner.x - _size.x); + case MIN_Y_FACE: return glm::vec4(0.0f, -1.0f, 0.0f, _corner.y); + case MAX_Y_FACE: return glm::vec4(0.0f, 1.0f, 0.0f, -_corner.y - _size.y); + case MIN_Z_FACE: return glm::vec4(0.0f, 0.0f, -1.0f, _corner.z); + case MAX_Z_FACE: return glm::vec4(0.0f, 0.0f, 1.0f, -_corner.z - _size.z); + } +} + +BoxFace AABox::getOppositeFace(BoxFace face) { + switch (face) { + case MIN_X_FACE: return MAX_X_FACE; + case MAX_X_FACE: return MIN_X_FACE; + case MIN_Y_FACE: return MAX_Y_FACE; + case MAX_Y_FACE: return MIN_Y_FACE; + case MIN_Z_FACE: return MAX_Z_FACE; + case MAX_Z_FACE: return MIN_Z_FACE; + } +} diff --git a/libraries/voxels/src/AABox.h b/libraries/voxels/src/AABox.h index 7acf2d54f1..9d419b9f19 100644 --- a/libraries/voxels/src/AABox.h +++ b/libraries/voxels/src/AABox.h @@ -1,72 +1,86 @@ -// -// AABox.h - Axis Aligned Boxes -// hifi -// -// Added by Brad Hefta-Gaub on 04/11/13. -// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards -// -// Simple axis aligned box class. -// - -#ifndef _AABOX_ -#define _AABOX_ - -#include - -enum BoxFace { - MIN_X_FACE, - MAX_X_FACE, - MIN_Y_FACE, - MAX_Y_FACE, - MIN_Z_FACE, - MAX_Z_FACE -}; - -const int FACE_COUNT = 6; - - class AABox -{ - -public: - - AABox(const glm::vec3& corner, float size) : _corner(corner), _size(size, size, size) { }; - AABox(const glm::vec3& corner, float x, float y, float z) : _corner(corner), _size(x, y, z) { }; - AABox(const glm::vec3& corner, const glm::vec3& size) : _corner(corner), _size(size) { }; - AABox() : _corner(0,0,0), _size(0,0,0) { } - ~AABox() { } - - void setBox(const glm::vec3& corner, float x, float y, float z) { setBox(corner,glm::vec3(x,y,z)); }; - void setBox(const glm::vec3& corner, const glm::vec3& size); - - // for use in frustum computations - glm::vec3 getVertexP(const glm::vec3& normal) const; - glm::vec3 getVertexN(const glm::vec3& normal) const; - - void scale(float scale); - - const glm::vec3& getCorner() const { return _corner; }; - const glm::vec3& getSize() const { return _size; }; - const glm::vec3& getCenter() const { return _center; }; - - bool contains(const glm::vec3& point) const; - bool expandedContains(const glm::vec3& point, float expansion) const; - bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const; - bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; - bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; - bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const; - -private: - - glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const; - glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const; - glm::vec4 getPlane(BoxFace face) const; - - static BoxFace getOppositeFace(BoxFace face); - - glm::vec3 _corner; - glm::vec3 _center; - glm::vec3 _size; -}; - - -#endif +// +// AABox.h - Axis Aligned Boxes +// hifi +// +// Added by Brad Hefta-Gaub on 04/11/13. +// Originally from lighthouse3d. Modified to utilize glm::vec3 and clean up to our coding standards +// +// Simple axis aligned box class. +// + +#ifndef _AABOX_ +#define _AABOX_ + +#include + +enum BoxFace { + MIN_X_FACE, + MAX_X_FACE, + MIN_Y_FACE, + MAX_Y_FACE, + MIN_Z_FACE, + MAX_Z_FACE +}; + + +enum BoxVertice { + BOTTOM_LEFT_NEAR = 0, + BOTTOM_RIGHT_NEAR = 1, + TOP_RIGHT_NEAR = 2, + TOP_LEFT_NEAR = 3, + BOTTOM_LEFT_FAR = 4, + BOTTOM_RIGHT_FAR = 5, + TOP_RIGHT_FAR = 6, + TOP_LEFT_FAR = 7 +}; + +const int FACE_COUNT = 6; + +class AABox +{ + +public: + + AABox(const glm::vec3& corner, float size) : _corner(corner), _size(size, size, size) { }; + AABox(const glm::vec3& corner, float x, float y, float z) : _corner(corner), _size(x, y, z) { }; + AABox(const glm::vec3& corner, const glm::vec3& size) : _corner(corner), _size(size) { }; + AABox() : _corner(0,0,0), _size(0,0,0) { } + ~AABox() { } + + void setBox(const glm::vec3& corner, float x, float y, float z) { setBox(corner,glm::vec3(x,y,z)); }; + void setBox(const glm::vec3& corner, const glm::vec3& size); + + // for use in frustum computations + glm::vec3 getVertexP(const glm::vec3& normal) const; + glm::vec3 getVertexN(const glm::vec3& normal) const; + + void scale(float scale); + + const glm::vec3& getCorner() const { return _corner; }; + const glm::vec3& getSize() const { return _size; }; + const glm::vec3& getCenter() const { return _center; }; + + glm::vec3 getVertice(BoxVertice vertice) const; + + bool contains(const glm::vec3& point) const; + bool expandedContains(const glm::vec3& point, float expansion) const; + bool expandedIntersectsSegment(const glm::vec3& start, const glm::vec3& end, float expansion) const; + bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance, BoxFace& face) const; + bool findSpherePenetration(const glm::vec3& center, float radius, glm::vec3& penetration) const; + bool findCapsulePenetration(const glm::vec3& start, const glm::vec3& end, float radius, glm::vec3& penetration) const; + +private: + + glm::vec3 getClosestPointOnFace(const glm::vec3& point, BoxFace face) const; + glm::vec3 getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& direction, BoxFace face) const; + glm::vec4 getPlane(BoxFace face) const; + + static BoxFace getOppositeFace(BoxFace face); + + glm::vec3 _corner; + glm::vec3 _center; + glm::vec3 _size; +}; + + +#endif From 658c5adfbf7a315b84e10cb45554c599910a6169 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Jun 2013 12:30:18 -0700 Subject: [PATCH 02/67] first cut at VoxelProjectedShadow class, which implements a 2D polygon that matches a voxels projected outline --- libraries/voxels/src/VoxelProjectedShadow.cpp | 112 ++++++++++++++++++ libraries/voxels/src/VoxelProjectedShadow.h | 52 ++++++++ 2 files changed, 164 insertions(+) create mode 100644 libraries/voxels/src/VoxelProjectedShadow.cpp create mode 100644 libraries/voxels/src/VoxelProjectedShadow.h diff --git a/libraries/voxels/src/VoxelProjectedShadow.cpp b/libraries/voxels/src/VoxelProjectedShadow.cpp new file mode 100644 index 0000000000..ba965d2a1b --- /dev/null +++ b/libraries/voxels/src/VoxelProjectedShadow.cpp @@ -0,0 +1,112 @@ +// +// VoxelProjectedShadow.cpp - The projected shadow (on the 2D view plane) for a voxel +// hifi +// +// Added by Brad Hefta-Gaub on 06/11/13. +// + +#include "VoxelProjectedShadow.h" +#include + +void VoxelProjectedShadow::setVertex(int vertex, const glm::vec2& point) { + _vertices[vertex] = point; + + // keep track of our bounding box + if (point.x > _maxX) { + _maxX = point.x; + } + if (point.y > _maxY) { + _maxY = point.y; + } + if (point.x < _minX) { + _minX = point.x; + } + if (point.y < _minY) { + _minY = point.y; + } + +}; + +bool VoxelProjectedShadow::occludes(const VoxelProjectedShadow& occludee) const { + + // first check the bounding boxes, the occludee mush be fully within the boounding box of this shadow + if ((occludee.getMaxX() > getMaxX()) || + (occludee.getMaxY() > getMaxY()) || + (occludee.getMinX() < getMinX()) || + (occludee.getMinY() < getMinY())) { + return false; + } + + // if we got this far, then check each vertex of the occludee, if all those points + // are inside our polygon, then the tested occludee is fully occluded + for(int i = 0; i < occludee.getVertexCount(); i++) { + if (!pointInside(occludee.getVertex(i))) { + return false; + } + } + + // if we got this far, then indeed the occludee is fully occluded by us + return true; +} + +bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk) { + return (xi <= xk || xj <= xk) && (xk <= xi || xk <= xj) && + (yi <= yk || yj <= yk) && (yk <= yi || yk <= yj); +} + +int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk) { + float a = (xk - xi) * (yj - yi); + float b = (xj - xi) * (yk - yi); + return a < b ? -1 : a > b ? 1 : 0; +} + +// Do line segments (r1p1.x, r1p1.y)--(r1p2.x, r1p2.y) and (r2p1.x, r2p1.y)--(r2p2.x, r2p2.y) intersect? +bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2) { + int d1 = computeDirection(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p1.x, r1p1.y); + int d2 = computeDirection(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p2.x, r1p2.y); + int d3 = computeDirection(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p1.x, r2p1.y); + int d4 = computeDirection(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p2.x, r2p2.y); + return (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && + ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) || + (d1 == 0 && isOnSegment(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p1.x, r1p1.y)) || + (d2 == 0 && isOnSegment(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p2.x, r1p2.y)) || + (d3 == 0 && isOnSegment(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p1.x, r2p1.y)) || + (d4 == 0 && isOnSegment(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p2.x, r2p2.y)); +} + +bool VoxelProjectedShadow::pointInside(const glm::vec2& point) const { + bool pointInside = false; // assume the worst + + // first check the bounding boxes, the point mush be fully within the boounding box of this shadow + if ((point.x > getMaxX()) || + (point.y > getMaxY()) || + (point.x < getMinX()) || + (point.y < getMinY())) { + return false; + } + + float e = (getMaxX() - getMinX()) / 100.0f; // some epsilon + + // We need to have one ray that goes from a known outside position to the point in question. We'll pick a + // start point just outside of our min X + glm::vec2 r1p1(getMinX() - e, point.y); + glm::vec2 r1p2(point); + + glm::vec2 r2p1(getVertex(getVertexCount()-1)); // start with last vertex to first vertex + glm::vec2 r2p2; + + // Test the ray against all sides + int intersections = 0; + for (int i = 0; i < getVertexCount(); i++) { + r2p2 = getVertex(i); + if (doLineSegmentsIntersect(r1p1, r1p2, r2p1, r2p2)) { + intersections++; + } + r2p1 = r2p2; // set up for next side + } + + // If odd number of intersections, we're inside + return ((intersections & 1) == 1); +} + + diff --git a/libraries/voxels/src/VoxelProjectedShadow.h b/libraries/voxels/src/VoxelProjectedShadow.h new file mode 100644 index 0000000000..6f1b4b1f79 --- /dev/null +++ b/libraries/voxels/src/VoxelProjectedShadow.h @@ -0,0 +1,52 @@ +// +// VoxelProjectedShadow.h - The projected shadow (on the 2D view plane) for a voxel +// hifi +// +// Added by Brad Hefta-Gaub on 06/11/13. +// + +#ifndef _VOXEL_PROJECTED_SHADOW_ +#define _VOXEL_PROJECTED_SHADOW_ + +#include + +const int MAX_SHADOW_VERTEX_COUNT = 6; + +typedef glm::vec2 ShadowVertices[MAX_SHADOW_VERTEX_COUNT]; + +class VoxelProjectedShadow +{ + +public: + + VoxelProjectedShadow() : _vertexCount(0), _maxX(0.0f), _maxY(0.0f), _minX(FLT_MAX), _minY(FLT_MAX) { }; + VoxelProjectedShadow(int vertexCount) : _vertexCount(vertexCount), _maxX(0.0f), _maxY(0.0f), _minX(FLT_MAX), _minY(FLT_MAX) + { }; + + ~VoxelProjectedShadow() { }; + const ShadowVertices& getVerices() const { return _vertices; }; + const glm::vec2& getVertex(int i) const { return _vertices[i]; }; + void setVertex(int vertex, const glm::vec2& point); + int getVertexCount() const { return _vertexCount; }; + void setVertexCount(int vertexCount) { _vertexCount = vertexCount; }; + + bool occludes(const VoxelProjectedShadow& occludee) const; + bool pointInside(const glm::vec2& point) const; + + float getMaxX() const { return _maxX; } + float getMaxY() const { return _maxY; } + float getMinX() const { return _minX; } + float getMinY() const { return _minY; } + +private: + int _vertexCount; + ShadowVertices _vertices; + float _maxX; + float _maxY; + float _minX; + float _minY; +}; + +bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2); + +#endif // _VOXEL_PROJECTED_SHADOW_ From 6d8826de43eef09769231ad8504e82c1c33723de Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Jun 2013 12:30:52 -0700 Subject: [PATCH 03/67] cleaned up line spacing and tabs, added getVertex() --- libraries/voxels/src/AABox.cpp | 11 ++++------- libraries/voxels/src/AABox.h | 4 ++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index 61cbf1ef45..d4b7e1383c 100644 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -21,8 +21,8 @@ void AABox::scale(float scale) { } -glm::vec3 AABox::getVertice(BoxVertice vertice) const { - switch (vertice) { +glm::vec3 AABox::getVertex(BoxVertex vertex) const { + switch (vertex) { case BOTTOM_LEFT_NEAR: return _corner + glm::vec3(_size.x, 0, 0); case BOTTOM_RIGHT_NEAR: @@ -63,19 +63,16 @@ void AABox::setBox(const glm::vec3& corner, const glm::vec3& size) { } glm::vec3 AABox::getVertexP(const glm::vec3& normal) const { - glm::vec3 res = _corner; + glm::vec3 result = _corner; if (normal.x > 0) { result.x += _size.x; } - if (normal.y > 0) { result.y += _size.y; - }{ - + } if (normal.z > 0) { result.z += _size.z; } - return result; } diff --git a/libraries/voxels/src/AABox.h b/libraries/voxels/src/AABox.h index 9d419b9f19..d295f24aea 100644 --- a/libraries/voxels/src/AABox.h +++ b/libraries/voxels/src/AABox.h @@ -23,7 +23,7 @@ enum BoxFace { }; -enum BoxVertice { +enum BoxVertex { BOTTOM_LEFT_NEAR = 0, BOTTOM_RIGHT_NEAR = 1, TOP_RIGHT_NEAR = 2, @@ -60,7 +60,7 @@ public: const glm::vec3& getSize() const { return _size; }; const glm::vec3& getCenter() const { return _center; }; - glm::vec3 getVertice(BoxVertice vertice) const; + glm::vec3 getVertex(BoxVertex vertex) const; bool contains(const glm::vec3& point) const; bool expandedContains(const glm::vec3& point, float expansion) const; From 56753fc21d2912b0454b182be30ea1a362a24cb2 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Jun 2013 12:33:18 -0700 Subject: [PATCH 04/67] added getProjectedShadow() and projectPoint() to ViewFrustum to implement support for projecting Axis Aligned Boxes to 2D --- libraries/voxels/src/ViewFrustum.cpp | 90 ++++++++++++++++++++++++++++ libraries/voxels/src/ViewFrustum.h | 4 ++ 2 files changed, 94 insertions(+) diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index b47199310c..6926a6190d 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -425,3 +425,93 @@ void ViewFrustum::printDebugDetails() const { _eyeOffsetOrientation.w ); } + +glm::vec2 ViewFrustum::projectPoint(glm::vec3 point) const { + + // Projection matrix : Field of View, ratio, display range : near to far + glm::mat4 projection = glm::perspective(_fieldOfView, _aspectRatio, _nearClip, _farClip); + glm::vec3 lookAt = _position + _direction; + glm::mat4 view = glm::lookAt(_position, lookAt, _up); + // Our ModelViewProjection : multiplication of our 3 matrices (note: model is identity, so we can drop it) + glm::mat4 VP = projection * view; // Remember, matrix multiplication is the other way around + + glm::vec4 pointVec4 = glm::vec4(point,1); + glm::vec4 projectedPointVec4 = VP * pointVec4; + glm::vec2 projectedPoint(projectedPointVec4.x / projectedPointVec4.w, projectedPointVec4.y / projectedPointVec4.w); + return projectedPoint; +} + + +const int MAX_POSSIBLE_COMBINATIONS = 43; + +const int hullVertexLookup[MAX_POSSIBLE_COMBINATIONS][MAX_SHADOW_VERTEX_COUNT+1] = { + // Number of vertices in shadow polygon for the visible faces, then a list of the index of each vertice from the AABox + {0}, // inside + {4, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR, TOP_RIGHT_NEAR}, // right + {4, BOTTOM_LEFT_NEAR, BOTTOM_LEFT_FAR, TOP_LEFT_FAR, TOP_LEFT_NEAR}, // left + {0}, // n/a + {4, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR}, // bottom + {6, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR},//bottom, right + {6, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, TOP_LEFT_FAR, TOP_LEFT_NEAR, BOTTOM_LEFT_NEAR},//bottom, left + {0}, // n/a + {4, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, TOP_LEFT_NEAR}, // top + {6, TOP_RIGHT_NEAR, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, TOP_LEFT_NEAR}, // top, right + {6, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR}, // top, left + {0}, // n/a + {0}, // n/a + {0}, // n/a + {0}, // n/a + {0}, // n/a + {4, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR, TOP_LEFT_NEAR, BOTTOM_LEFT_NEAR}, // front or near + {6, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR, TOP_RIGHT_NEAR, TOP_LEFT_NEAR, BOTTOM_LEFT_NEAR}, // front, right + {6, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR, TOP_LEFT_NEAR, TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR}, // front, left + {0}, // n/a + {6, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR, TOP_RIGHT_NEAR}, // front,bottom + {6, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR}, //front,bottom,right + {6, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, TOP_LEFT_FAR, TOP_LEFT_NEAR, TOP_RIGHT_NEAR}, //front,bottom,left + {0}, // n/a + {6, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, TOP_LEFT_NEAR, BOTTOM_LEFT_NEAR}, // front, top + {6, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, TOP_LEFT_NEAR, BOTTOM_LEFT_NEAR}, // front, top, right + {6, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR}, // front, top, left + {0}, // n/a + {0}, // n/a + {0}, // n/a + {0}, // n/a + {0}, // n/a + {4, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, BOTTOM_LEFT_FAR}, // back + {6, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_RIGHT_FAR}, // back, right + {6, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, TOP_LEFT_NEAR, BOTTOM_LEFT_NEAR, BOTTOM_LEFT_FAR}, // back, left + {0}, // n/a + {6, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR}, // back, bottom + {6, BOTTOM_RIGHT_NEAR, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR},//back, bottom, right + {6, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR, TOP_LEFT_FAR, TOP_LEFT_NEAR, BOTTOM_LEFT_NEAR},//back, bottom, left + {0}, // n/a + {6, BOTTOM_RIGHT_FAR, TOP_RIGHT_FAR, TOP_RIGHT_NEAR, TOP_LEFT_NEAR, TOP_LEFT_FAR, BOTTOM_LEFT_FAR}, // back, top + {6, BOTTOM_RIGHT_NEAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, TOP_LEFT_FAR, TOP_LEFT_NEAR, TOP_RIGHT_NEAR}, // back, top, right + {6, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR}, // back, top, left +}; + +VoxelProjectedShadow ViewFrustum::getProjectedShadow(const AABox& box) const { + glm::vec3 bottomNearRight = box.getCorner(); + glm::vec3 topFarLeft = box.getCorner() + box.getSize(); + int lookUp = ((_position.x < bottomNearRight.x) ) // 1 = right | compute 6-bit + + ((_position.x > topFarLeft.x ) << 1) // 2 = left | code to + + ((_position.y < bottomNearRight.y) << 2) // 4 = bottom | classify camera + + ((_position.y > topFarLeft.y ) << 3) // 8 = top | with respect to + + ((_position.z < bottomNearRight.z) << 4) // 16 = front/near | the 6 defining + + ((_position.z > topFarLeft.z ) << 5); // 32 = back/far | planes + + int vertexCount = hullVertexLookup[lookUp][0]; //look up number of vertices + + VoxelProjectedShadow shadow(vertexCount); + + if (vertexCount) { + for(int i = 0; i < vertexCount; i++) { + int vertexNum = hullVertexLookup[lookUp][i+1]; + glm::vec3 point = box.getVertex((BoxVertex)vertexNum); + glm::vec2 projectedPoint = projectPoint(point); + shadow.setVertex(i, projectedPoint); + } + } + return shadow; +} diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index d23f2db897..04ef0dc7a9 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -15,6 +15,7 @@ #include #include "Plane.h" #include "AABox.h" +#include "VoxelProjectedShadow.h" const float DEFAULT_KEYHOLE_RADIUS = 2.0f; @@ -87,6 +88,9 @@ public: void printDebugDetails() const; + glm::vec2 projectPoint(glm::vec3 point) const; + VoxelProjectedShadow getProjectedShadow(const AABox& box) const; + private: // Used for keyhole calculations From ab365202c854a6208d09b4f1450219b73cee2693 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Jun 2013 12:36:15 -0700 Subject: [PATCH 05/67] added some debugging routines to visualize occlusion --- interface/src/Application.cpp | 77 +++++++++++++++++++++++++++++++++++ interface/src/Application.h | 5 +++ 2 files changed, 82 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 51c6e65cb9..3dc18272c6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1884,6 +1884,78 @@ void Application::displayOculus(Camera& whichCamera) { glPopMatrix(); } + +glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { + float horizontalScale = _glWidget->width() / 2.0f; + float verticalScale = _glWidget->height() / 2.0f; + + // -1,-1 is 0,windowHeight + // 1,1 is windowWidth,0 + glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale, + ((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->height()); + + return screenPoint; +} + +glm::vec2 Application::getScreenPoint(glm::vec3 voxelPoint) { + glm::vec2 projectedPoint = _viewFrustum.projectPoint(voxelPoint * (float)TREE_SCALE); + return getScaledScreenPoint(projectedPoint); +} + +void Application::render2DTests() { + glLineWidth(2.0); + glBegin(GL_LINES); + glColor3f(1,0,0); + + AABox boxA(glm::vec3(0,0,0), 0.0125); + boxA.scale(TREE_SCALE); + VoxelProjectedShadow shadowA = _viewFrustum.getProjectedShadow(boxA); + + AABox boxB(glm::vec3(0.0125,0,0.025), 0.0125); + boxB.scale(TREE_SCALE); + VoxelProjectedShadow shadowB = _viewFrustum.getProjectedShadow(boxB); + + bool shadowAoccludesB = shadowA.occludes(shadowB); + bool shadowBoccludesA = shadowB.occludes(shadowA); + + if (shadowA.getVertexCount()) { + if (shadowBoccludesA) { + glColor3f(0,1,1); + } else { + glColor3f(1,0,0); + } + glm::vec2 firstPoint = getScaledScreenPoint(shadowA.getVertex(0)); + glm::vec2 lastPoint(firstPoint); + for (int i = 1; i < shadowA.getVertexCount(); i++) { + glm::vec2 thisPoint = getScaledScreenPoint(shadowA.getVertex(i)); + glVertex2f(lastPoint.x, lastPoint.y); + glVertex2f(thisPoint.x, thisPoint.y); + lastPoint = thisPoint; + } + glVertex2f(lastPoint.x, lastPoint.y); + glVertex2f(firstPoint.x, firstPoint.y); + } + + if (shadowB.getVertexCount()) { + if (shadowAoccludesB) { + glColor3f(0,1,0); + } else { + glColor3f(1,0,0); + } + glm::vec2 firstPoint = getScaledScreenPoint(shadowB.getVertex(0)); + glm::vec2 lastPoint(firstPoint); + for (int i = 1; i < shadowB.getVertexCount(); i++) { + glm::vec2 thisPoint = getScaledScreenPoint(shadowB.getVertex(i)); + glVertex2f(lastPoint.x, lastPoint.y); + glVertex2f(thisPoint.x, thisPoint.y); + lastPoint = thisPoint; + } + glVertex2f(lastPoint.x, lastPoint.y); + glVertex2f(firstPoint.x, firstPoint.y); + } + + glEnd(); +} void Application::displaySide(Camera& whichCamera) { // transform by eye offset @@ -2013,6 +2085,7 @@ void Application::displaySide(Camera& whichCamera) { // brad's frustum for debugging if (_frustumOn->isChecked()) renderViewFrustum(_viewFrustum); + } void Application::displayOverlay() { @@ -2165,6 +2238,10 @@ void Application::displayStats() { } delete []perfStatLinesArray; // we're responsible for cleanup } + + // testing.... + render2DTests(); + } ///////////////////////////////////////////////////////////////////////////////////// diff --git a/interface/src/Application.h b/interface/src/Application.h index 4f33f8fb1e..44ef76b801 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -139,6 +139,11 @@ private: void displaySide(Camera& whichCamera); void displayOverlay(); void displayStats(); + + // Couple of debug routines for use in debuggin/developing Occlusion Culling. Will be removed eventually + void render2DTests(); + glm::vec2 getScreenPoint(glm::vec3 voxelPoint); + glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); void renderViewFrustum(ViewFrustum& viewFrustum); From ac7fbc63208ebb3a958b5dfce3f608dff9b356ae Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Jun 2013 13:29:01 -0700 Subject: [PATCH 06/67] added occlusion tests to debug menu --- interface/src/Application.cpp | 100 +++++++++++++++++++--------------- interface/src/Application.h | 4 +- interface/src/VoxelSystem.cpp | 30 ++++++++++ interface/src/VoxelSystem.h | 2 + 4 files changed, 90 insertions(+), 46 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3dc18272c6..d97e488d90 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -964,6 +964,11 @@ void Application::doFalseColorizeInView() { _voxels.falseColorizeInView(&_viewFrustum); } +void Application::doFalseColorizeOccluded() { + _debugShowVirtualOccluders->setChecked(true); + _voxels.falseColorizeOccluded(); +} + void Application::doTrueVoxelColors() { _voxels.trueColorize(); } @@ -1316,7 +1321,9 @@ void Application::initMenu() { renderDebugMenu->addAction("FALSE Color Voxel Every Other Randomly", this, SLOT(doFalseRandomizeEveryOtherVoxelColors())); renderDebugMenu->addAction("FALSE Color Voxels by Distance", this, SLOT(doFalseColorizeByDistance())); renderDebugMenu->addAction("FALSE Color Voxel Out of View", this, SLOT(doFalseColorizeInView())); - renderDebugMenu->addAction("Show TRUE Colors", this, SLOT(doTrueVoxelColors())); + renderDebugMenu->addAction("FALSE Color Occluded Voxels", this, SLOT(doFalseColorizeOccluded()), Qt::CTRL | Qt::Key_O); + renderDebugMenu->addAction("Show TRUE Colors", this, SLOT(doTrueVoxelColors()), Qt::CTRL | Qt::Key_T); + (_debugShowVirtualOccluders = renderDebugMenu->addAction("Show Virtual Occluders"))->setCheckable(true); debugMenu->addAction("Wants Res-In", this, SLOT(setWantsResIn(bool)))->setCheckable(true); debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true); @@ -1902,59 +1909,62 @@ glm::vec2 Application::getScreenPoint(glm::vec3 voxelPoint) { return getScaledScreenPoint(projectedPoint); } -void Application::render2DTests() { - glLineWidth(2.0); - glBegin(GL_LINES); - glColor3f(1,0,0); +void Application::renderVirtualOccluders() { - AABox boxA(glm::vec3(0,0,0), 0.0125); - boxA.scale(TREE_SCALE); - VoxelProjectedShadow shadowA = _viewFrustum.getProjectedShadow(boxA); + if (_debugShowVirtualOccluders->isChecked()) { + glLineWidth(2.0); + glBegin(GL_LINES); + glColor3f(0,0,1); - AABox boxB(glm::vec3(0.0125,0,0.025), 0.0125); - boxB.scale(TREE_SCALE); - VoxelProjectedShadow shadowB = _viewFrustum.getProjectedShadow(boxB); + AABox boxA(glm::vec3(0,0,0), 0.0125); + boxA.scale(TREE_SCALE); + VoxelProjectedShadow shadowA = _viewFrustum.getProjectedShadow(boxA); - bool shadowAoccludesB = shadowA.occludes(shadowB); - bool shadowBoccludesA = shadowB.occludes(shadowA); + AABox boxB(glm::vec3(0.0125,0,0.025), 0.0125); + boxB.scale(TREE_SCALE); + VoxelProjectedShadow shadowB = _viewFrustum.getProjectedShadow(boxB); + + bool shadowAoccludesB = shadowA.occludes(shadowB); + bool shadowBoccludesA = shadowB.occludes(shadowA); - if (shadowA.getVertexCount()) { - if (shadowBoccludesA) { - glColor3f(0,1,1); - } else { - glColor3f(1,0,0); - } - glm::vec2 firstPoint = getScaledScreenPoint(shadowA.getVertex(0)); - glm::vec2 lastPoint(firstPoint); - for (int i = 1; i < shadowA.getVertexCount(); i++) { - glm::vec2 thisPoint = getScaledScreenPoint(shadowA.getVertex(i)); + if (shadowA.getVertexCount()) { + if (shadowBoccludesA) { + glColor3f(1,0,0); + } else { + glColor3f(0,0,1); + } + glm::vec2 firstPoint = getScaledScreenPoint(shadowA.getVertex(0)); + glm::vec2 lastPoint(firstPoint); + for (int i = 1; i < shadowA.getVertexCount(); i++) { + glm::vec2 thisPoint = getScaledScreenPoint(shadowA.getVertex(i)); + glVertex2f(lastPoint.x, lastPoint.y); + glVertex2f(thisPoint.x, thisPoint.y); + lastPoint = thisPoint; + } glVertex2f(lastPoint.x, lastPoint.y); - glVertex2f(thisPoint.x, thisPoint.y); - lastPoint = thisPoint; + glVertex2f(firstPoint.x, firstPoint.y); } - glVertex2f(lastPoint.x, lastPoint.y); - glVertex2f(firstPoint.x, firstPoint.y); - } - if (shadowB.getVertexCount()) { - if (shadowAoccludesB) { - glColor3f(0,1,0); - } else { - glColor3f(1,0,0); - } - glm::vec2 firstPoint = getScaledScreenPoint(shadowB.getVertex(0)); - glm::vec2 lastPoint(firstPoint); - for (int i = 1; i < shadowB.getVertexCount(); i++) { - glm::vec2 thisPoint = getScaledScreenPoint(shadowB.getVertex(i)); + if (shadowB.getVertexCount()) { + if (shadowAoccludesB) { + glColor3f(0,1,0); + } else { + glColor3f(1,0,0); + } + glm::vec2 firstPoint = getScaledScreenPoint(shadowB.getVertex(0)); + glm::vec2 lastPoint(firstPoint); + for (int i = 1; i < shadowB.getVertexCount(); i++) { + glm::vec2 thisPoint = getScaledScreenPoint(shadowB.getVertex(i)); + glVertex2f(lastPoint.x, lastPoint.y); + glVertex2f(thisPoint.x, thisPoint.y); + lastPoint = thisPoint; + } glVertex2f(lastPoint.x, lastPoint.y); - glVertex2f(thisPoint.x, thisPoint.y); - lastPoint = thisPoint; + glVertex2f(firstPoint.x, firstPoint.y); } - glVertex2f(lastPoint.x, lastPoint.y); - glVertex2f(firstPoint.x, firstPoint.y); - } - glEnd(); + glEnd(); + } } void Application::displaySide(Camera& whichCamera) { @@ -2240,7 +2250,7 @@ void Application::displayStats() { } // testing.... - render2DTests(); + renderVirtualOccluders(); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 44ef76b801..276c913fb8 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -102,6 +102,7 @@ private slots: void doFalseRandomizeVoxelColors(); void doFalseRandomizeEveryOtherVoxelColors(); void doFalseColorizeByDistance(); + void doFalseColorizeOccluded(); void doFalseColorizeInView(); void doTrueVoxelColors(); void doTreeStats(); @@ -141,7 +142,7 @@ private: void displayStats(); // Couple of debug routines for use in debuggin/developing Occlusion Culling. Will be removed eventually - void render2DTests(); + void renderVirtualOccluders(); glm::vec2 getScreenPoint(glm::vec3 voxelPoint); glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); @@ -206,6 +207,7 @@ private: QAction* _fullScreenMode; // whether we are in full screen mode QAction* _frustumRenderModeAction; QAction* _settingsAutosave; // Whether settings are saved automatically + QAction* _debugShowVirtualOccluders; SerialInterface _serialHeadSensor; QNetworkAccessManager* _networkAccessManager; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 9cde8906be..cd6a4436ab 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1156,3 +1156,33 @@ void VoxelSystem::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* dest _tree->copyFromTreeIntoSubTree(sourceTree, destinationNode); } +struct FalseColorizeOccludedArgs { + VoxelProjectedShadow occluder; + ViewFrustum* viewFrustum; +}; + +bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraData) { + FalseColorizeOccludedArgs* args = (FalseColorizeOccludedArgs*) extraData; + if (node->isColored()) { + AABox voxelBox = node->getAABox(); + voxelBox.scale(TREE_SCALE); + VoxelProjectedShadow voxelShadow = args->viewFrustum->getProjectedShadow(voxelBox); + if (args->occluder.occludes(voxelShadow)) { + node->setFalseColor(255, 0, 0); + } + } + return true; // keep going! +} + +void VoxelSystem::falseColorizeOccluded() { + FalseColorizeOccludedArgs args; + args.viewFrustum = Application::getInstance()->getViewFrustum(); + + AABox box(glm::vec3(0.0125,0,0.025), 0.0125); + box.scale(TREE_SCALE); + args.occluder = args.viewFrustum->getProjectedShadow(box); + + _tree->recurseTreeWithOperation(falseColorizeOccludedOperation,(void*)&args); + setupNewVoxelsForDrawing(); +} + diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index c4aa33adfc..6a07249454 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -56,6 +56,7 @@ public: void falseColorizeInView(ViewFrustum* viewFrustum); void falseColorizeDistanceFromView(ViewFrustum* viewFrustum); void falseColorizeRandomEveryOther(); + void falseColorizeOccluded(); void killLocalVoxels(); void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; }; @@ -120,6 +121,7 @@ private: static bool removeOutOfViewOperation(VoxelNode* node, void* extraData); static bool falseColorizeRandomEveryOtherOperation(VoxelNode* node, void* extraData); static bool collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData); + static bool falseColorizeOccludedOperation(VoxelNode* node, void* extraData); int updateNodeInArraysAsFullVBO(VoxelNode* node); int updateNodeInArraysAsPartialVBO(VoxelNode* node); From 77dc8d9900aebf9ff465ef54f8902bb337145398 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Jun 2013 14:06:17 -0700 Subject: [PATCH 07/67] moved line intersection to GeometryUtil --- libraries/voxels/src/GeometryUtil.cpp | 27 +++++++++++++++++++ libraries/voxels/src/GeometryUtil.h | 4 +++ libraries/voxels/src/VoxelProjectedShadow.cpp | 27 +------------------ libraries/voxels/src/VoxelProjectedShadow.h | 1 - 4 files changed, 32 insertions(+), 27 deletions(-) diff --git a/libraries/voxels/src/GeometryUtil.cpp b/libraries/voxels/src/GeometryUtil.cpp index aceaa32b37..f311bf2993 100644 --- a/libraries/voxels/src/GeometryUtil.cpp +++ b/libraries/voxels/src/GeometryUtil.cpp @@ -115,3 +115,30 @@ glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& return currentDirection * glm::max(directionalComponent, currentLength) + newPenetration - (currentDirection * directionalComponent); } + +// Do line segments (r1p1.x, r1p1.y)--(r1p2.x, r1p2.y) and (r2p1.x, r2p1.y)--(r2p2.x, r2p2.y) intersect? +bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2) { + int d1 = computeDirection(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p1.x, r1p1.y); + int d2 = computeDirection(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p2.x, r1p2.y); + int d3 = computeDirection(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p1.x, r2p1.y); + int d4 = computeDirection(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p2.x, r2p2.y); + return (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && + ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) || + (d1 == 0 && isOnSegment(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p1.x, r1p1.y)) || + (d2 == 0 && isOnSegment(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p2.x, r1p2.y)) || + (d3 == 0 && isOnSegment(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p1.x, r2p1.y)) || + (d4 == 0 && isOnSegment(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p2.x, r2p2.y)); +} + + +// I want these to be inlined for performance +bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk) { + return (xi <= xk || xj <= xk) && (xk <= xi || xk <= xj) && + (yi <= yk || yj <= yk) && (yk <= yi || yk <= yj); +} + +int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk) { + float a = (xk - xi) * (yj - yi); + float b = (xj - xi) * (yk - yi); + return a < b ? -1 : a > b ? 1 : 0; +} diff --git a/libraries/voxels/src/GeometryUtil.h b/libraries/voxels/src/GeometryUtil.h index 01cd87a4f3..b16ad4e2c0 100644 --- a/libraries/voxels/src/GeometryUtil.h +++ b/libraries/voxels/src/GeometryUtil.h @@ -39,4 +39,8 @@ bool findCapsulePlanePenetration(const glm::vec3& penetratorStart, const glm::ve glm::vec3 addPenetrations(const glm::vec3& currentPenetration, const glm::vec3& newPenetration); +bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2); +bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk); +int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk); + #endif /* defined(__interface__GeometryUtil__) */ diff --git a/libraries/voxels/src/VoxelProjectedShadow.cpp b/libraries/voxels/src/VoxelProjectedShadow.cpp index ba965d2a1b..4d8519ede2 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.cpp +++ b/libraries/voxels/src/VoxelProjectedShadow.cpp @@ -6,7 +6,7 @@ // #include "VoxelProjectedShadow.h" -#include +#include "GeometryUtil.h" void VoxelProjectedShadow::setVertex(int vertex, const glm::vec2& point) { _vertices[vertex] = point; @@ -49,31 +49,6 @@ bool VoxelProjectedShadow::occludes(const VoxelProjectedShadow& occludee) const return true; } -bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk) { - return (xi <= xk || xj <= xk) && (xk <= xi || xk <= xj) && - (yi <= yk || yj <= yk) && (yk <= yi || yk <= yj); -} - -int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk) { - float a = (xk - xi) * (yj - yi); - float b = (xj - xi) * (yk - yi); - return a < b ? -1 : a > b ? 1 : 0; -} - -// Do line segments (r1p1.x, r1p1.y)--(r1p2.x, r1p2.y) and (r2p1.x, r2p1.y)--(r2p2.x, r2p2.y) intersect? -bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2) { - int d1 = computeDirection(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p1.x, r1p1.y); - int d2 = computeDirection(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p2.x, r1p2.y); - int d3 = computeDirection(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p1.x, r2p1.y); - int d4 = computeDirection(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p2.x, r2p2.y); - return (((d1 > 0 && d2 < 0) || (d1 < 0 && d2 > 0)) && - ((d3 > 0 && d4 < 0) || (d3 < 0 && d4 > 0))) || - (d1 == 0 && isOnSegment(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p1.x, r1p1.y)) || - (d2 == 0 && isOnSegment(r2p1.x, r2p1.y, r2p2.x, r2p2.y, r1p2.x, r1p2.y)) || - (d3 == 0 && isOnSegment(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p1.x, r2p1.y)) || - (d4 == 0 && isOnSegment(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p2.x, r2p2.y)); -} - bool VoxelProjectedShadow::pointInside(const glm::vec2& point) const { bool pointInside = false; // assume the worst diff --git a/libraries/voxels/src/VoxelProjectedShadow.h b/libraries/voxels/src/VoxelProjectedShadow.h index 6f1b4b1f79..2be41a02ee 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.h +++ b/libraries/voxels/src/VoxelProjectedShadow.h @@ -47,6 +47,5 @@ private: float _minY; }; -bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm::vec2 r2p2); #endif // _VOXEL_PROJECTED_SHADOW_ From 6d3ec662a1eca98bc4438ca26cb23d5c1d4b1a25 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Jun 2013 18:36:25 -0700 Subject: [PATCH 08/67] CoverageMap class, implments a quad tree that handles coverage map for 2d polygon projections of voxels --- libraries/voxels/src/CoverageMap.cpp | 126 +++++++++++++++++++++++++++ libraries/voxels/src/CoverageMap.h | 72 +++++++++++++++ 2 files changed, 198 insertions(+) create mode 100644 libraries/voxels/src/CoverageMap.cpp create mode 100644 libraries/voxels/src/CoverageMap.h diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp new file mode 100644 index 0000000000..fa3d05101e --- /dev/null +++ b/libraries/voxels/src/CoverageMap.cpp @@ -0,0 +1,126 @@ +// +// CoverageMap.cpp - +// hifi +// +// Added by Brad Hefta-Gaub on 06/11/13. +// + +#include "CoverageMap.h" +#include + +CoverageMap::~CoverageMap() { + if (_polygons) { + delete[] _polygons; + } + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + if (_childMaps[i]) { + delete _childMaps[i]; + } + } +}; + + +void CoverageMap::init() { + _polygonCount = 0; + _polygonArraySize = 0; + _polygons = NULL; + memset(_childMaps,0,sizeof(_childMaps)); +} + +// 0 = bottom, right +// 1 = bottom, left +// 2 = top, right +// 3 = top, left +BoundingBox CoverageMap::getChildBoundingBox(int childIndex) { + const int LEFT_BIT = 1; + const int TOP_BIT = 2; + // initialize to our corner, and half our size + BoundingBox result(_myBoundingBox.corner,_myBoundingBox.size/2.0f); + // if our "left" bit is set, then add size.x to the corner + if ((childIndex & LEFT_BIT) == LEFT_BIT) { + result.corner.x += result.size.x; + } + // if our "top" bit is set, then add size.y to the corner + if ((childIndex & TOP_BIT) == TOP_BIT) { + result.corner.y += result.size.y; + } + return result; +} + + +void CoverageMap::growPolygonArray() { + VoxelProjectedShadow** newPolygons = new VoxelProjectedShadow*[_polygonArraySize + DEFAULT_GROW_SIZE]; + + if (_polygons) { + memcpy(newPolygons, _polygons, sizeof(VoxelProjectedShadow*) * _polygonCount); + delete[] _polygons; + } + _polygons = newPolygons; + _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; +} + +// just handles storage in the array, doesn't test for occlusion or +// determining if this is the correct map to store in! +void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { + if (_polygonArraySize < _polygonCount + 1) { + growPolygonArray(); + } + _polygons[_polygonCount] = polygon; + _polygonCount++; +} + + +// possible results = STORED, OCCLUDED, DOESNT_FIT +// storeInMap(poly) +// if (poly->BB inside myBB) +// -- at this point, we can check polygons at this level +// -- to see if they occlude the polygon being inserted +// -- since the polygons at this level are big relative to +// -- lower levels, there's a higher chance for them to occlude +// -- Note: list should be "depth" sorted +// for each polygon at this level +// if (levelpolygon.occludes(poly)) +// return OCCLUDED +// end +// for each child +// childResult = child->storeInMap(poly) +// if (childResult == STORED || childResult == OCCLUDED) +// return childResult +// end +// end +// -- if we got here, then the polygon didn't fit in any of the children and +// -- wasn't already occluded, so store it here +// insert into local list (poly, poly.depth) +// return STORED +// end +// return DOESNT_FIT +CoverageMap::StorageResult CoverageMap::storeInMap(VoxelProjectedShadow* polygon) { + if (_myBoundingBox.contains(polygon->getBoundingBox())) { + // check to make sure this polygon isn't occluded by something at this level + for (int i = 0; i < _polygonCount; i++) { + VoxelProjectedShadow* polygonAtThisLevel = _polygons[i]; + if (polygonAtThisLevel->occludes(*polygon)) { + return OCCLUDED; + } + } + // if we made it here, then it means the polygon being stored is not occluded + // at this level of the quad tree, so we can continue to insert it into the map. + // First we check to see if it fits in any of our sub maps + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + BoundingBox childMapBoundingBox = getChildBoundingBox(i); + if (childMapBoundingBox.contains(polygon->getBoundingBox())) { + // if no child map exists yet, then create it + if (!_childMaps[i]) { + _childMaps[i] = new CoverageMap(childMapBoundingBox); + } + return _childMaps[i]->storeInMap(polygon); + } + } + // if we got this far, then the polygon is in our bounding box, but doesn't fit in + // any of our child bounding boxes, so we should add it here. + storeInArray(polygon); + return STORED; + } + return DOESNT_FIT; +} + diff --git a/libraries/voxels/src/CoverageMap.h b/libraries/voxels/src/CoverageMap.h new file mode 100644 index 0000000000..3f7dfe343d --- /dev/null +++ b/libraries/voxels/src/CoverageMap.h @@ -0,0 +1,72 @@ +// +// CoverageMap.h - 2D CoverageMap Quad tree for storage of VoxelProjectedShadows +// hifi +// +// Added by Brad Hefta-Gaub on 06/11/13. +// + +#ifndef _COVERAGE_MAP_ +#define _COVERAGE_MAP_ + +#include +#include "VoxelProjectedShadow.h" + + +// +// depth of polygon is distance from camera to closest point on 3d voxel +// this works because voxels are axis aligned and therefore other voxels +// can only be as close as that if they are on the same axis +// +// scanning octree in "closest" order... +// for each node +// polygon = getShadow(node) +// isOccluded = coverageMap->isOccluded(polygon) +// if (!isOccluded) +// coverageMap->add(polygon) +// sendList->add(node) +// else +// don't need to send or remember +// end each + +// adding to coverage map.... +// +// at each level of quadtree +// store a list of polygons whose bounding box fit in the bb of the quad but not a smaller quad +// also store 4 smaller quad trees +// +// is it true, that only polygons from higher in the quad tree can occlude a polygon? +// YES - I believe so, because polygon that occluded all the points of the potential occludee +// would have a bounding box that couldn't fit in a lower level of the quad tree +// +// + + +class CoverageMap { + +public: + static const int NUMBER_OF_CHILDREN = 4; + + CoverageMap(BoundingBox boundingBox) : _myBoundingBox(boundingBox) { init(); }; + ~CoverageMap(); + + typedef enum {STORED, OCCLUDED, DOESNT_FIT} StorageResult; + StorageResult storeInMap(VoxelProjectedShadow* polygon); + + BoundingBox getChildBoundingBox(int childIndex); + +private: + void init(); + void growPolygonArray(); + void storeInArray(VoxelProjectedShadow* polygon); + + BoundingBox _myBoundingBox; + int _polygonCount; // how many polygons at this level + int _polygonArraySize; // how much room is there to store polygons at this level + VoxelProjectedShadow** _polygons; + CoverageMap* _childMaps[NUMBER_OF_CHILDREN]; + + static const int DEFAULT_GROW_SIZE = 500; +}; + + +#endif // _COVERAGE_MAP_ From b3ef9868e3df462a8fc8f57e2bc7d9a210c7a8ae Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 11 Jun 2013 18:37:31 -0700 Subject: [PATCH 09/67] fixed line spacing and added BoundingBox support --- libraries/voxels/src/VoxelProjectedShadow.cpp | 182 +++++++++--------- libraries/voxels/src/VoxelProjectedShadow.h | 113 ++++++----- 2 files changed, 157 insertions(+), 138 deletions(-) diff --git a/libraries/voxels/src/VoxelProjectedShadow.cpp b/libraries/voxels/src/VoxelProjectedShadow.cpp index 4d8519ede2..2c138cdbec 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.cpp +++ b/libraries/voxels/src/VoxelProjectedShadow.cpp @@ -1,87 +1,95 @@ -// -// VoxelProjectedShadow.cpp - The projected shadow (on the 2D view plane) for a voxel -// hifi -// -// Added by Brad Hefta-Gaub on 06/11/13. -// - -#include "VoxelProjectedShadow.h" -#include "GeometryUtil.h" - -void VoxelProjectedShadow::setVertex(int vertex, const glm::vec2& point) { - _vertices[vertex] = point; - - // keep track of our bounding box - if (point.x > _maxX) { - _maxX = point.x; - } - if (point.y > _maxY) { - _maxY = point.y; - } - if (point.x < _minX) { - _minX = point.x; - } - if (point.y < _minY) { - _minY = point.y; - } - -}; - -bool VoxelProjectedShadow::occludes(const VoxelProjectedShadow& occludee) const { - - // first check the bounding boxes, the occludee mush be fully within the boounding box of this shadow - if ((occludee.getMaxX() > getMaxX()) || - (occludee.getMaxY() > getMaxY()) || - (occludee.getMinX() < getMinX()) || - (occludee.getMinY() < getMinY())) { - return false; - } - - // if we got this far, then check each vertex of the occludee, if all those points - // are inside our polygon, then the tested occludee is fully occluded - for(int i = 0; i < occludee.getVertexCount(); i++) { - if (!pointInside(occludee.getVertex(i))) { - return false; - } - } - - // if we got this far, then indeed the occludee is fully occluded by us - return true; -} - -bool VoxelProjectedShadow::pointInside(const glm::vec2& point) const { - bool pointInside = false; // assume the worst - - // first check the bounding boxes, the point mush be fully within the boounding box of this shadow - if ((point.x > getMaxX()) || - (point.y > getMaxY()) || - (point.x < getMinX()) || - (point.y < getMinY())) { - return false; - } - - float e = (getMaxX() - getMinX()) / 100.0f; // some epsilon - - // We need to have one ray that goes from a known outside position to the point in question. We'll pick a - // start point just outside of our min X - glm::vec2 r1p1(getMinX() - e, point.y); - glm::vec2 r1p2(point); - - glm::vec2 r2p1(getVertex(getVertexCount()-1)); // start with last vertex to first vertex - glm::vec2 r2p2; - - // Test the ray against all sides - int intersections = 0; - for (int i = 0; i < getVertexCount(); i++) { - r2p2 = getVertex(i); - if (doLineSegmentsIntersect(r1p1, r1p2, r2p1, r2p2)) { - intersections++; - } - r2p1 = r2p2; // set up for next side - } - - // If odd number of intersections, we're inside - return ((intersections & 1) == 1); -} - - +// +// VoxelProjectedShadow.cpp - The projected shadow (on the 2D view plane) for a voxel +// hifi +// +// Added by Brad Hefta-Gaub on 06/11/13. +// + +#include "VoxelProjectedShadow.h" +#include "GeometryUtil.h" + + +bool BoundingBox::contains(const BoundingBox& box) const { + return ( + (box.corner.x >= corner.x) && + (box.corner.y >= corner.y) && + (box.corner.x + box.size.x <= corner.x + size.x) && + (box.corner.y + box.size.y <= corner.y + size.y) + ); +}; + +void VoxelProjectedShadow::setVertex(int vertex, const glm::vec2& point) { + _vertices[vertex] = point; + + // keep track of our bounding box + if (point.x > _maxX) { + _maxX = point.x; + } + if (point.y > _maxY) { + _maxY = point.y; + } + if (point.x < _minX) { + _minX = point.x; + } + if (point.y < _minY) { + _minY = point.y; + } + +}; + +bool VoxelProjectedShadow::occludes(const VoxelProjectedShadow& occludee) const { + + // first check the bounding boxes, the occludee mush be fully within the boounding box of this shadow + if ((occludee.getMaxX() > getMaxX()) || + (occludee.getMaxY() > getMaxY()) || + (occludee.getMinX() < getMinX()) || + (occludee.getMinY() < getMinY())) { + return false; + } + + // if we got this far, then check each vertex of the occludee, if all those points + // are inside our polygon, then the tested occludee is fully occluded + for(int i = 0; i < occludee.getVertexCount(); i++) { + if (!pointInside(occludee.getVertex(i))) { + return false; + } + } + + // if we got this far, then indeed the occludee is fully occluded by us + return true; +} + +bool VoxelProjectedShadow::pointInside(const glm::vec2& point) const { + // first check the bounding boxes, the point mush be fully within the boounding box of this shadow + if ((point.x > getMaxX()) || + (point.y > getMaxY()) || + (point.x < getMinX()) || + (point.y < getMinY())) { + return false; + } + + float e = (getMaxX() - getMinX()) / 100.0f; // some epsilon + + // We need to have one ray that goes from a known outside position to the point in question. We'll pick a + // start point just outside of our min X + glm::vec2 r1p1(getMinX() - e, point.y); + glm::vec2 r1p2(point); + + glm::vec2 r2p1(getVertex(getVertexCount()-1)); // start with last vertex to first vertex + glm::vec2 r2p2; + + // Test the ray against all sides + int intersections = 0; + for (int i = 0; i < getVertexCount(); i++) { + r2p2 = getVertex(i); + if (doLineSegmentsIntersect(r1p1, r1p2, r2p1, r2p2)) { + intersections++; + } + r2p1 = r2p2; // set up for next side + } + + // If odd number of intersections, we're inside + return ((intersections & 1) == 1); +} + + diff --git a/libraries/voxels/src/VoxelProjectedShadow.h b/libraries/voxels/src/VoxelProjectedShadow.h index 2be41a02ee..90af42d3bc 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.h +++ b/libraries/voxels/src/VoxelProjectedShadow.h @@ -1,51 +1,62 @@ -// -// VoxelProjectedShadow.h - The projected shadow (on the 2D view plane) for a voxel -// hifi -// -// Added by Brad Hefta-Gaub on 06/11/13. -// - -#ifndef _VOXEL_PROJECTED_SHADOW_ -#define _VOXEL_PROJECTED_SHADOW_ - -#include - -const int MAX_SHADOW_VERTEX_COUNT = 6; - -typedef glm::vec2 ShadowVertices[MAX_SHADOW_VERTEX_COUNT]; - -class VoxelProjectedShadow -{ - -public: - - VoxelProjectedShadow() : _vertexCount(0), _maxX(0.0f), _maxY(0.0f), _minX(FLT_MAX), _minY(FLT_MAX) { }; - VoxelProjectedShadow(int vertexCount) : _vertexCount(vertexCount), _maxX(0.0f), _maxY(0.0f), _minX(FLT_MAX), _minY(FLT_MAX) - { }; - - ~VoxelProjectedShadow() { }; - const ShadowVertices& getVerices() const { return _vertices; }; - const glm::vec2& getVertex(int i) const { return _vertices[i]; }; - void setVertex(int vertex, const glm::vec2& point); - int getVertexCount() const { return _vertexCount; }; - void setVertexCount(int vertexCount) { _vertexCount = vertexCount; }; - - bool occludes(const VoxelProjectedShadow& occludee) const; - bool pointInside(const glm::vec2& point) const; - - float getMaxX() const { return _maxX; } - float getMaxY() const { return _maxY; } - float getMinX() const { return _minX; } - float getMinY() const { return _minY; } - -private: - int _vertexCount; - ShadowVertices _vertices; - float _maxX; - float _maxY; - float _minX; - float _minY; -}; - - -#endif // _VOXEL_PROJECTED_SHADOW_ +// +// VoxelProjectedShadow.h - The projected shadow (on the 2D view plane) for a voxel +// hifi +// +// Added by Brad Hefta-Gaub on 06/11/13. +// + +#ifndef _VOXEL_PROJECTED_SHADOW_ +#define _VOXEL_PROJECTED_SHADOW_ + +#include + +const int MAX_SHADOW_VERTEX_COUNT = 6; + +typedef glm::vec2 ShadowVertices[MAX_SHADOW_VERTEX_COUNT]; + +class BoundingBox { +public: + BoundingBox(glm::vec2 corner, glm::vec2 size) : corner(corner), size(size) {}; + glm::vec2 corner; + glm::vec2 size; + bool contains(const BoundingBox& box) const; +}; + +class VoxelProjectedShadow { + +public: + + VoxelProjectedShadow(int vertexCount = 0) : + _vertexCount(vertexCount), _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX) + { }; + + ~VoxelProjectedShadow() { }; + const ShadowVertices& getVerices() const { return _vertices; }; + const glm::vec2& getVertex(int i) const { return _vertices[i]; }; + void setVertex(int vertex, const glm::vec2& point); + int getVertexCount() const { return _vertexCount; }; + void setVertexCount(int vertexCount) { _vertexCount = vertexCount; }; + + bool occludes(const VoxelProjectedShadow& occludee) const; + bool pointInside(const glm::vec2& point) const; + + float getMaxX() const { return _maxX; } + float getMaxY() const { return _maxY; } + float getMinX() const { return _minX; } + float getMinY() const { return _minY; } + + BoundingBox getBoundingBox() const { + return BoundingBox(glm::vec2(_minX,_minY), glm::vec2(_maxX - _minX, _maxY - _minY)); + }; + +private: + int _vertexCount; + ShadowVertices _vertices; + float _maxX; + float _maxY; + float _minX; + float _minY; +}; + + +#endif // _VOXEL_PROJECTED_SHADOW_ From e2d22a8e2144bda8b8bb5eab37abd3c97296e47e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Jun 2013 01:16:46 -0700 Subject: [PATCH 10/67] latest cut at occlusion culling --- interface/src/Application.cpp | 11 ++++- interface/src/VoxelSystem.cpp | 37 ++++++++++++++-- interface/src/VoxelSystem.h | 2 + libraries/voxels/src/CoverageMap.cpp | 7 ++- libraries/voxels/src/CoverageMap.h | 4 +- libraries/voxels/src/VoxelProjectedShadow.cpp | 11 +++++ libraries/voxels/src/VoxelProjectedShadow.h | 3 +- libraries/voxels/src/VoxelTree.cpp | 43 ++++++++++++++++++- libraries/voxels/src/VoxelTree.h | 5 +++ 9 files changed, 115 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d97e488d90..5dd9da7fa2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -60,6 +60,8 @@ #include "renderer/ProgramObject.h" #include "ui/TextRenderer.h" +#include + using namespace std; const bool TESTING_AVATAR_TOUCH = false; @@ -965,7 +967,6 @@ void Application::doFalseColorizeInView() { } void Application::doFalseColorizeOccluded() { - _debugShowVirtualOccluders->setChecked(true); _voxels.falseColorizeOccluded(); } @@ -1912,6 +1913,9 @@ glm::vec2 Application::getScreenPoint(glm::vec3 voxelPoint) { void Application::renderVirtualOccluders() { if (_debugShowVirtualOccluders->isChecked()) { + CoverageMap map(BoundingBox(glm::vec2(-1.f,-1.f), glm::vec2(2.f,2.f))); // screen coverage + + glLineWidth(2.0); glBegin(GL_LINES); glColor3f(0,0,1); @@ -1919,11 +1923,16 @@ void Application::renderVirtualOccluders() { AABox boxA(glm::vec3(0,0,0), 0.0125); boxA.scale(TREE_SCALE); VoxelProjectedShadow shadowA = _viewFrustum.getProjectedShadow(boxA); + AABox boxB(glm::vec3(0.0125,0,0.025), 0.0125); boxB.scale(TREE_SCALE); VoxelProjectedShadow shadowB = _viewFrustum.getProjectedShadow(boxB); + //CoverageMap::StorageResult result; + //result = map.storeInMap(&shadowB); // test this first since it's closer in Z-buffer + //result = map.storeInMap(&shadowA); + bool shadowAoccludesB = shadowA.occludes(shadowB); bool shadowBoccludesA = shadowB.occludes(shadowA); diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index cd6a4436ab..1c924a1a36 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -22,6 +22,7 @@ #include "Application.h" #include "Log.h" #include "VoxelConstants.h" +#include "CoverageMap.h" #include "InterfaceConfig.h" #include "renderer/ProgramObject.h" @@ -1159,9 +1160,10 @@ void VoxelSystem::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* dest struct FalseColorizeOccludedArgs { VoxelProjectedShadow occluder; ViewFrustum* viewFrustum; + CoverageMap* map; }; -bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraData) { +bool VoxelSystem::falseColorizeTestOccludedOperation(VoxelNode* node, void* extraData) { FalseColorizeOccludedArgs* args = (FalseColorizeOccludedArgs*) extraData; if (node->isColored()) { AABox voxelBox = node->getAABox(); @@ -1174,7 +1176,7 @@ bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraDat return true; // keep going! } -void VoxelSystem::falseColorizeOccluded() { +void VoxelSystem::falseColorizeTestOccluded() { FalseColorizeOccludedArgs args; args.viewFrustum = Application::getInstance()->getViewFrustum(); @@ -1182,7 +1184,36 @@ void VoxelSystem::falseColorizeOccluded() { box.scale(TREE_SCALE); args.occluder = args.viewFrustum->getProjectedShadow(box); - _tree->recurseTreeWithOperation(falseColorizeOccludedOperation,(void*)&args); + _tree->recurseTreeWithOperation(falseColorizeTestOccludedOperation,(void*)&args); + setupNewVoxelsForDrawing(); +} + +bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraData) { + FalseColorizeOccludedArgs* args = (FalseColorizeOccludedArgs*) extraData; + if (node->isColored() && node->isLeaf()) { + AABox voxelBox = node->getAABox(); + voxelBox.scale(TREE_SCALE); + VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(args->viewFrustum->getProjectedShadow(voxelBox)); + CoverageMap::StorageResult result = args->map->storeInMap(voxelShadow); + if (result == CoverageMap::OCCLUDED) { + node->setFalseColor(255, 0, 0); + } + } + return true; // keep going! +} + +void VoxelSystem::falseColorizeOccluded() { + CoverageMap map(BoundingBox(glm::vec2(-1.f,-1.f), glm::vec2(2.f,2.f)), true); + FalseColorizeOccludedArgs args; + args.viewFrustum = Application::getInstance()->getViewFrustum(); + args.map = ↦ + + AABox box(glm::vec3(0.0125,0,0.025), 0.0125); + box.scale(TREE_SCALE); + args.occluder = args.viewFrustum->getProjectedShadow(box); + + _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedOperation, + args.viewFrustum->getPosition(), (void*)&args); setupNewVoxelsForDrawing(); } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 6a07249454..f67960748a 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -57,6 +57,7 @@ public: void falseColorizeDistanceFromView(ViewFrustum* viewFrustum); void falseColorizeRandomEveryOther(); void falseColorizeOccluded(); + void falseColorizeTestOccluded(); void killLocalVoxels(); void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; }; @@ -122,6 +123,7 @@ private: static bool falseColorizeRandomEveryOtherOperation(VoxelNode* node, void* extraData); static bool collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData); static bool falseColorizeOccludedOperation(VoxelNode* node, void* extraData); + static bool falseColorizeTestOccludedOperation(VoxelNode* node, void* extraData); int updateNodeInArraysAsFullVBO(VoxelNode* node); int updateNodeInArraysAsPartialVBO(VoxelNode* node); diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp index fa3d05101e..80b8776d8c 100644 --- a/libraries/voxels/src/CoverageMap.cpp +++ b/libraries/voxels/src/CoverageMap.cpp @@ -9,6 +9,11 @@ #include CoverageMap::~CoverageMap() { + if (_managePolygons) { + for (int i = 0; i < _polygonCount; i++) { + delete _polygons[i]; + } + } if (_polygons) { delete[] _polygons; } @@ -111,7 +116,7 @@ CoverageMap::StorageResult CoverageMap::storeInMap(VoxelProjectedShadow* polygon if (childMapBoundingBox.contains(polygon->getBoundingBox())) { // if no child map exists yet, then create it if (!_childMaps[i]) { - _childMaps[i] = new CoverageMap(childMapBoundingBox); + _childMaps[i] = new CoverageMap(childMapBoundingBox, _managePolygons); } return _childMaps[i]->storeInMap(polygon); } diff --git a/libraries/voxels/src/CoverageMap.h b/libraries/voxels/src/CoverageMap.h index 3f7dfe343d..c505b1e223 100644 --- a/libraries/voxels/src/CoverageMap.h +++ b/libraries/voxels/src/CoverageMap.h @@ -46,7 +46,8 @@ class CoverageMap { public: static const int NUMBER_OF_CHILDREN = 4; - CoverageMap(BoundingBox boundingBox) : _myBoundingBox(boundingBox) { init(); }; + CoverageMap(BoundingBox boundingBox, bool managePolygons = false) : + _myBoundingBox(boundingBox), _managePolygons(managePolygons) { init(); }; ~CoverageMap(); typedef enum {STORED, OCCLUDED, DOESNT_FIT} StorageResult; @@ -60,6 +61,7 @@ private: void storeInArray(VoxelProjectedShadow* polygon); BoundingBox _myBoundingBox; + bool _managePolygons; // will the coverage map delete the polygons on destruct int _polygonCount; // how many polygons at this level int _polygonArraySize; // how much room is there to store polygons at this level VoxelProjectedShadow** _polygons; diff --git a/libraries/voxels/src/VoxelProjectedShadow.cpp b/libraries/voxels/src/VoxelProjectedShadow.cpp index 2c138cdbec..0568c8b3c9 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.cpp +++ b/libraries/voxels/src/VoxelProjectedShadow.cpp @@ -18,6 +18,7 @@ bool BoundingBox::contains(const BoundingBox& box) const { ); }; + void VoxelProjectedShadow::setVertex(int vertex, const glm::vec2& point) { _vertices[vertex] = point; @@ -92,4 +93,14 @@ bool VoxelProjectedShadow::pointInside(const glm::vec2& point) const { return ((intersections & 1) == 1); } +void VoxelProjectedShadow::printDebugDetails() const { + printf("VoxelProjectedShadow..."); + printf(" minX=%f maxX=%f minY=%f maxY=%f\n", getMinX(), getMaxX(), getMinY(), getMaxY()); + printf(" vertex count=%d \n", getVertexCount()); + for (int i = 0; i < getVertexCount(); i++) { + glm::vec2 point = getVertex(i); + printf(" vertex[%d] = %f, %f \n", i, point.x, point.y); + } +} + diff --git a/libraries/voxels/src/VoxelProjectedShadow.h b/libraries/voxels/src/VoxelProjectedShadow.h index 90af42d3bc..1d5e7cf022 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.h +++ b/libraries/voxels/src/VoxelProjectedShadow.h @@ -25,7 +25,6 @@ public: class VoxelProjectedShadow { public: - VoxelProjectedShadow(int vertexCount = 0) : _vertexCount(vertexCount), _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX) { }; @@ -49,6 +48,8 @@ public: return BoundingBox(glm::vec2(_minX,_minY), glm::vec2(_maxX - _minX, _maxY - _minY)); }; + void printDebugDetails() const; + private: int _vertexCount; ShadowVertices _vertices; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index b67e87597a..aea4a8778b 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -68,7 +68,48 @@ void VoxelTree::recurseNodeWithOperation(VoxelNode* node,RecurseVoxelTreeOperati } } -VoxelNode * VoxelTree::nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const { +// Recurses voxel tree calling the RecurseVoxelTreeOperation function for each node. +// stops recursion if operation function returns false. +void VoxelTree::recurseTreeWithOperationDistanceSorted(RecurseVoxelTreeOperation operation, + const glm::vec3& point, void* extraData) { + recurseNodeWithOperationDistanceSorted(rootNode, operation, point, extraData); +} + +// Recurses voxel node with an operation function +void VoxelTree::recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseVoxelTreeOperation operation, + const glm::vec3& point, void* extraData) { + if (operation(node, extraData)) { + // determine the distance sorted order of our children + + VoxelNode* sortedChildren[NUMBER_OF_CHILDREN]; + float distancesToChildren[NUMBER_OF_CHILDREN]; + int indexOfChildren[NUMBER_OF_CHILDREN]; // not really needed + int currentCount = 0; + + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { + VoxelNode* childNode = node->getChildAtIndex(i); + if (childNode) { + float distance = glm::distance(point, childNode->getCenter()); + currentCount = insertIntoSortedArrays((void*)childNode, distance, i, + (void**)&sortedChildren, (float*)&distancesToChildren, + (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); + } + + + } + + for (int i = 0; i < currentCount; i++) { + VoxelNode* childNode = sortedChildren[i]; + if (childNode) { + recurseNodeWithOperationDistanceSorted(childNode, operation, point, extraData); + } + } + } +} + + +VoxelNode* VoxelTree::nodeForOctalCode(VoxelNode* ancestorNode, + unsigned char* needleCode, VoxelNode** parentOfFoundNode) const { // find the appropriate branch index based on this ancestorNode if (*needleCode > 0) { int branchForNeedle = branchIndexWithDescendant(ancestorNode->getOctalCode(), needleCode); diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index a238cb603a..ad644f8dc6 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -67,6 +67,8 @@ public: creationMode mode, bool destructive = false, bool debug = false); void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); + void recurseTreeWithOperationDistanceSorted(RecurseVoxelTreeOperation operation, + const glm::vec3& point, void* extraData=NULL); int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, @@ -117,6 +119,9 @@ private: static bool countVoxelsOperation(VoxelNode* node, void* extraData); void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); + void recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseVoxelTreeOperation operation, + const glm::vec3& point, void* extraData); + VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, From 2e58a77180b992f756a3722bc66fe7867885f515 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Jun 2013 12:35:02 -0700 Subject: [PATCH 11/67] make originalIndexArray optional in insertIntoSortedArrays() --- libraries/shared/src/SharedUtil.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 697719b36d..efa474e8a1 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -400,6 +400,7 @@ void printVoxelCode(unsigned char* voxelCode) { // the second array is a sorted key for the value, the third array is the index for the value in it original // non-sorted array // returns -1 if size exceeded +// originalIndexArray is optional int insertIntoSortedArrays(void* value, float key, int originalIndex, void** valueArray, float* keyArray, int* originalIndexArray, int currentCount, int maxCount) { @@ -415,13 +416,17 @@ int insertIntoSortedArrays(void* value, float key, int originalIndex, if (i < currentCount && i+1 < maxCount) { memcpy(&valueArray[i + 1], &valueArray[i], sizeof(void*) * (currentCount - i)); memcpy(&keyArray[i + 1], &keyArray[i], sizeof(float) * (currentCount - i)); - memcpy(&originalIndexArray[i + 1], &originalIndexArray[i], sizeof(int) * (currentCount - i)); + if (originalIndexArray) { + memcpy(&originalIndexArray[i + 1], &originalIndexArray[i], sizeof(int) * (currentCount - i)); + } } } // place new element at i valueArray[i] = value; keyArray[i] = key; - originalIndexArray[i] = originalIndex; + if (originalIndexArray) { + originalIndexArray[i] = originalIndex; + } return currentCount + 1; } return -1; // error case From 627f61badbeae0e9de532c09523126674a2295c1 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Jun 2013 12:36:28 -0700 Subject: [PATCH 12/67] some debug changes for testing occlusion culling --- interface/src/Application.cpp | 18 ++++++++++++++---- interface/src/VoxelSystem.cpp | 12 ++++++++++-- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b793123d1b..75cda7be85 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1899,6 +1899,20 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { // -1,-1 is 0,windowHeight // 1,1 is windowWidth,0 + + // -1,1 1,1 + // +-----------------------+ + // | | | + // | | | + // | -1,0 | | + // |-----------+-----------| + // | 0,0 | + // | | | + // | | | + // | | | + // +-----------------------+ + // -1,-1 1,-1 + glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale, ((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->height()); @@ -1929,10 +1943,6 @@ void Application::renderVirtualOccluders() { boxB.scale(TREE_SCALE); VoxelProjectedShadow shadowB = _viewFrustum.getProjectedShadow(boxB); - //CoverageMap::StorageResult result; - //result = map.storeInMap(&shadowB); // test this first since it's closer in Z-buffer - //result = map.storeInMap(&shadowA); - bool shadowAoccludesB = shadowA.occludes(shadowB); bool shadowBoccludesA = shadowB.occludes(shadowA); diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 1c924a1a36..2e5995e140 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1189,21 +1189,29 @@ void VoxelSystem::falseColorizeTestOccluded() { } bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraData) { +//node->printDebugDetails(">>>>>>>>>>>>>>> falseColorizeOccludedOperation() BEGIN >>>>>>>>>>>>>>"); FalseColorizeOccludedArgs* args = (FalseColorizeOccludedArgs*) extraData; - if (node->isColored() && node->isLeaf()) { + if (node->isColored() && node->isLeaf() && !node->isStagedForDeletion() && node->getShouldRender()) { +//printLog("***** falseColorizeOccludedOperation() NODE is colored, etc, so consider it *****\n"); AABox voxelBox = node->getAABox(); voxelBox.scale(TREE_SCALE); VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(args->viewFrustum->getProjectedShadow(voxelBox)); CoverageMap::StorageResult result = args->map->storeInMap(voxelShadow); if (result == CoverageMap::OCCLUDED) { +//printLog("***** falseColorizeOccludedOperation() NODE is OCCLUDED *****\n"); node->setFalseColor(255, 0, 0); + } else if (result == CoverageMap::STORED) { +//printLog("***** falseColorizeOccludedOperation() NODE is STORED *****\n"); + } else if (result == CoverageMap::DOESNT_FIT) { +//printLog("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n"); } } +//printLog("<<<<<<<<<<<<<<<<< falseColorizeOccludedOperation() END <<<<<<<<<<<<<<<<<\n"); return true; // keep going! } void VoxelSystem::falseColorizeOccluded() { - CoverageMap map(BoundingBox(glm::vec2(-1.f,-1.f), glm::vec2(2.f,2.f)), true); + CoverageMap map(BoundingBox(glm::vec2(-2.f,-2.f), glm::vec2(4.f,4.f)), true); FalseColorizeOccludedArgs args; args.viewFrustum = Application::getInstance()->getViewFrustum(); args.map = ↦ From 91aea82418400e39192246c06a70ae454c5182a8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Jun 2013 12:37:21 -0700 Subject: [PATCH 13/67] latest work on occlusion culling --- libraries/voxels/src/CoverageMap.cpp | 80 +++++++++++++++++-- libraries/voxels/src/CoverageMap.h | 13 ++- libraries/voxels/src/ViewFrustum.cpp | 3 + libraries/voxels/src/VoxelProjectedShadow.cpp | 12 ++- libraries/voxels/src/VoxelProjectedShadow.h | 10 ++- 5 files changed, 108 insertions(+), 10 deletions(-) diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp index 80b8776d8c..35913a3777 100644 --- a/libraries/voxels/src/CoverageMap.cpp +++ b/libraries/voxels/src/CoverageMap.cpp @@ -6,7 +6,18 @@ // #include "CoverageMap.h" +#include #include +#include "Log.h" + +int CoverageMap::_mapCount = 0; + +CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygons) : + _isRoot(isRoot), _myBoundingBox(boundingBox), _managePolygons(managePolygons) { + _mapCount++; + init(); + printLog("CoverageMap created... _mapCount=%d\n",_mapCount); +}; CoverageMap::~CoverageMap() { if (_managePolygons) { @@ -54,24 +65,49 @@ BoundingBox CoverageMap::getChildBoundingBox(int childIndex) { void CoverageMap::growPolygonArray() { - VoxelProjectedShadow** newPolygons = new VoxelProjectedShadow*[_polygonArraySize + DEFAULT_GROW_SIZE]; + VoxelProjectedShadow** newPolygons = new VoxelProjectedShadow*[_polygonArraySize + DEFAULT_GROW_SIZE]; + float* newDistances = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; + if (_polygons) { memcpy(newPolygons, _polygons, sizeof(VoxelProjectedShadow*) * _polygonCount); delete[] _polygons; + memcpy(newDistances, _polygonDistances, sizeof(float) * _polygonCount); + delete[] _polygonDistances; } _polygons = newPolygons; + _polygonDistances = newDistances; _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; +printLog("CoverageMap::growPolygonArray() _polygonArraySize=%d...\n",_polygonArraySize); } +int CoverageMap::_maxPolygonsUsed = 0; + + // just handles storage in the array, doesn't test for occlusion or // determining if this is the correct map to store in! void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { + +//printLog("CoverageMap::storeInArray()..."); +//polygon->printDebugDetails(); + if (_polygonArraySize < _polygonCount + 1) { growPolygonArray(); } - _polygons[_polygonCount] = polygon; - _polygonCount++; + + // 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 + const int IGNORED = NULL; + _polygonCount = insertIntoSortedArrays((void*)polygon, polygon->getDistance(), IGNORED, + (void**)_polygons, _polygonDistances, IGNORED, + _polygonCount, _polygonArraySize); + + if (_polygonCount > _maxPolygonsUsed) { + _maxPolygonsUsed = _polygonCount; + printLog("CoverageMap new _maxPolygonsUsed reached=%d\n",_maxPolygonsUsed); + _myBoundingBox.printDebugDetails("map._myBoundingBox"); + } } @@ -100,11 +136,45 @@ void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { // end // return DOESNT_FIT CoverageMap::StorageResult CoverageMap::storeInMap(VoxelProjectedShadow* polygon) { - if (_myBoundingBox.contains(polygon->getBoundingBox())) { + +//printLog("CoverageMap::storeInMap()..."); +//polygon->printDebugDetails(); + + if (_isRoot || _myBoundingBox.contains(polygon->getBoundingBox())) { + +/* +if (_isRoot) { + printLog("CoverageMap::storeInMap()... this map _isRoot, so all polygons are contained....\n"); +} else { + printLog("CoverageMap::storeInMap()... _myBoundingBox.contains(polygon)....\n"); + _myBoundingBox.printDebugDetails("_myBoundingBox"); + polygon->getBoundingBox().printDebugDetails("polygon->getBoundingBox()"); +} +*/ + // check to make sure this polygon isn't occluded by something at this level for (int i = 0; i < _polygonCount; i++) { VoxelProjectedShadow* polygonAtThisLevel = _polygons[i]; + +//printLog("CoverageMap::storeInMap()... polygonAtThisLevel = _polygons[%d] =",i); +//polygonAtThisLevel->printDebugDetails(); + + // Check to make sure that the polygon in question is "behind" the polygon in the list + // otherwise, we don't need to test it's occlusion (although, it means we've potentially + // added an item previously that may be occluded??? Is that possible? Maybe not, because two + // voxels can't have the exact same outline. So one occludes the other, they can't both occlude + // each other. if (polygonAtThisLevel->occludes(*polygon)) { + +//printLog("CoverageMap::storeInMap()... polygonAtThisLevel->occludes(*polygon)...\n",i); + + // if the polygonAtThisLevel is actually behind the one we're inserting, then we don't + // want to report our inserted one as occluded, but we do want to add our inserted one. + if (polygonAtThisLevel->getDistance() >= polygon->getDistance()) { + storeInArray(polygon); + return STORED; + } + // this polygon is occluded by a closer polygon, so don't store it, and let the caller know return OCCLUDED; } } @@ -116,7 +186,7 @@ CoverageMap::StorageResult CoverageMap::storeInMap(VoxelProjectedShadow* polygon if (childMapBoundingBox.contains(polygon->getBoundingBox())) { // if no child map exists yet, then create it if (!_childMaps[i]) { - _childMaps[i] = new CoverageMap(childMapBoundingBox, _managePolygons); + _childMaps[i] = new CoverageMap(childMapBoundingBox, NOT_ROOT, _managePolygons); } return _childMaps[i]->storeInMap(polygon); } diff --git a/libraries/voxels/src/CoverageMap.h b/libraries/voxels/src/CoverageMap.h index c505b1e223..57db884593 100644 --- a/libraries/voxels/src/CoverageMap.h +++ b/libraries/voxels/src/CoverageMap.h @@ -41,13 +41,15 @@ // + class CoverageMap { public: static const int NUMBER_OF_CHILDREN = 4; + static const bool NOT_ROOT=false; + static const bool IS_ROOT=true; - CoverageMap(BoundingBox boundingBox, bool managePolygons = false) : - _myBoundingBox(boundingBox), _managePolygons(managePolygons) { init(); }; + CoverageMap(BoundingBox boundingBox, bool isRoot = IS_ROOT, bool managePolygons = false); ~CoverageMap(); typedef enum {STORED, OCCLUDED, DOESNT_FIT} StorageResult; @@ -60,14 +62,19 @@ private: void growPolygonArray(); void storeInArray(VoxelProjectedShadow* polygon); + bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT BoundingBox _myBoundingBox; bool _managePolygons; // will the coverage map delete the polygons on destruct int _polygonCount; // how many polygons at this level int _polygonArraySize; // how much room is there to store polygons at this level VoxelProjectedShadow** _polygons; + float* _polygonDistances; CoverageMap* _childMaps[NUMBER_OF_CHILDREN]; - static const int DEFAULT_GROW_SIZE = 500; + static const int DEFAULT_GROW_SIZE = 100; + static int _mapCount; + static int _maxPolygonsUsed; + }; diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 6926a6190d..491a355040 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -513,5 +513,8 @@ VoxelProjectedShadow ViewFrustum::getProjectedShadow(const AABox& box) const { shadow.setVertex(i, projectedPoint); } } + // set the distance from our camera position, to the closest vertex + float distance = glm::distance(getPosition(), box.getCenter()); + shadow.setDistance(distance); return shadow; } diff --git a/libraries/voxels/src/VoxelProjectedShadow.cpp b/libraries/voxels/src/VoxelProjectedShadow.cpp index 0568c8b3c9..1ddb6370a9 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.cpp +++ b/libraries/voxels/src/VoxelProjectedShadow.cpp @@ -7,6 +7,7 @@ #include "VoxelProjectedShadow.h" #include "GeometryUtil.h" +#include "Log.h" bool BoundingBox::contains(const BoundingBox& box) const { @@ -18,6 +19,15 @@ bool BoundingBox::contains(const BoundingBox& box) const { ); }; +void BoundingBox::printDebugDetails(const char* label) const { + if (label) { + printLog(label); + } else { + printLog("BoundingBox"); + } + printLog("\n corner=%f,%f size=%f,%f\n", corner.x, corner.y, size.x, size.y); +} + void VoxelProjectedShadow::setVertex(int vertex, const glm::vec2& point) { _vertices[vertex] = point; @@ -96,7 +106,7 @@ bool VoxelProjectedShadow::pointInside(const glm::vec2& point) const { void VoxelProjectedShadow::printDebugDetails() const { printf("VoxelProjectedShadow..."); printf(" minX=%f maxX=%f minY=%f maxY=%f\n", getMinX(), getMaxX(), getMinY(), getMaxY()); - printf(" vertex count=%d \n", getVertexCount()); + printf(" vertex count=%d distance=%f\n", getVertexCount(), getDistance()); for (int i = 0; i < getVertexCount(); i++) { glm::vec2 point = getVertex(i); printf(" vertex[%d] = %f, %f \n", i, point.x, point.y); diff --git a/libraries/voxels/src/VoxelProjectedShadow.h b/libraries/voxels/src/VoxelProjectedShadow.h index 1d5e7cf022..ffe13bb9b6 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.h +++ b/libraries/voxels/src/VoxelProjectedShadow.h @@ -20,13 +20,17 @@ public: glm::vec2 corner; glm::vec2 size; bool contains(const BoundingBox& box) const; + + void printDebugDetails(const char* label=NULL) const; }; class VoxelProjectedShadow { public: VoxelProjectedShadow(int vertexCount = 0) : - _vertexCount(vertexCount), _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX) + _vertexCount(vertexCount), + _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX), + _distance(0) { }; ~VoxelProjectedShadow() { }; @@ -36,6 +40,9 @@ public: int getVertexCount() const { return _vertexCount; }; void setVertexCount(int vertexCount) { _vertexCount = vertexCount; }; + float getDistance() const { return _distance; } + void setDistance(float distance) { _distance = distance; } + bool occludes(const VoxelProjectedShadow& occludee) const; bool pointInside(const glm::vec2& point) const; @@ -57,6 +64,7 @@ private: float _maxY; float _minX; float _minY; + float _distance; }; From 0f234d739e691cad11201d8047525438116417fd Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Jun 2013 21:44:49 -0700 Subject: [PATCH 14/67] remove Camera menu from frustum debugging, because its obsolete and only causes problems --- interface/src/Application.cpp | 13 +------------ interface/src/Application.h | 1 - 2 files changed, 1 insertion(+), 13 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 75cda7be85..0db20f3526 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1304,9 +1304,6 @@ void Application::initMenu() { _frustumOn->setShortcut(Qt::SHIFT | Qt::Key_F); (_viewFrustumFromOffset = frustumMenu->addAction( "Use Offset Camera", this, SLOT(setFrustumOffset(bool)), Qt::SHIFT | Qt::Key_O))->setCheckable(true); - (_cameraFrustum = frustumMenu->addAction("Switch Camera"))->setCheckable(true); - _cameraFrustum->setChecked(true); - _cameraFrustum->setShortcut(Qt::SHIFT | Qt::Key_C); _frustumRenderModeAction = frustumMenu->addAction( "Render Mode", this, SLOT(cycleFrustumRenderMode()), Qt::SHIFT | Qt::Key_R); updateFrustumRenderModeAction(); @@ -1717,15 +1714,7 @@ void Application::updateAvatar(float deltaTime) { // void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { // We will use these below, from either the camera or head vectors calculated above - glm::vec3 position; - - // Camera or Head? - if (_cameraFrustum->isChecked()) { - position = camera.getPosition(); - } else { - position = _myAvatar.getHeadJointPosition(); - } - + glm::vec3 position(camera.getPosition()); float fov = camera.getFieldOfView(); float nearClip = camera.getNearClip(); float farClip = camera.getFarClip(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 276c913fb8..4d99d73001 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -203,7 +203,6 @@ private: QAction* _destructiveAddVoxel; // when doing voxel editing do we want them to be destructive QAction* _frustumOn; // Whether or not to display the debug view frustum QAction* _viewFrustumFromOffset; // Whether or not to offset the view of the frustum - QAction* _cameraFrustum; // which frustum to look at QAction* _fullScreenMode; // whether we are in full screen mode QAction* _frustumRenderModeAction; QAction* _settingsAutosave; // Whether settings are saved automatically From b8e51943ab0d686eeecf6ffcbdb41772a750f0a7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Jun 2013 21:45:45 -0700 Subject: [PATCH 15/67] make sure position is in voxel units NOT TREE_SCALE --- interface/src/VoxelSystem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 2e5995e140..2261559f74 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1219,9 +1219,9 @@ void VoxelSystem::falseColorizeOccluded() { AABox box(glm::vec3(0.0125,0,0.025), 0.0125); box.scale(TREE_SCALE); args.occluder = args.viewFrustum->getProjectedShadow(box); + glm::vec3 position = args.viewFrustum->getPosition() * (1.0f/TREE_SCALE); - _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedOperation, - args.viewFrustum->getPosition(), (void*)&args); + _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedOperation, position, (void*)&args); setupNewVoxelsForDrawing(); } From 3a33d871e86e2accb6ec37e0a71d2cecf70f6d49 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 12 Jun 2013 21:46:22 -0700 Subject: [PATCH 16/67] some debug code --- libraries/voxels/src/CoverageMap.cpp | 21 +++++++++++++++++---- libraries/voxels/src/CoverageMap.h | 1 + libraries/voxels/src/VoxelTree.cpp | 9 +++++++-- 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp index 35913a3777..fff6345a5a 100644 --- a/libraries/voxels/src/CoverageMap.cpp +++ b/libraries/voxels/src/CoverageMap.cpp @@ -33,6 +33,17 @@ CoverageMap::~CoverageMap() { delete _childMaps[i]; } } + + if (_isRoot) { + printLog("CoverageMap last to be deleted...\n"); + printLog("_mapCount=%d\n",_mapCount); + printLog("_maxPolygonsUsed=%d\n",_maxPolygonsUsed); + printLog("_totalPolygons=%d\n",_totalPolygons); + + _maxPolygonsUsed = 0; + _totalPolygons = 0; + _mapCount = 0; + } }; @@ -78,16 +89,18 @@ void CoverageMap::growPolygonArray() { _polygons = newPolygons; _polygonDistances = newDistances; _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; -printLog("CoverageMap::growPolygonArray() _polygonArraySize=%d...\n",_polygonArraySize); +//printLog("CoverageMap::growPolygonArray() _polygonArraySize=%d...\n",_polygonArraySize); } int CoverageMap::_maxPolygonsUsed = 0; - +int CoverageMap::_totalPolygons = 0; // just handles storage in the array, doesn't test for occlusion or // determining if this is the correct map to store in! void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { + _totalPolygons++; + //printLog("CoverageMap::storeInArray()..."); //polygon->printDebugDetails(); @@ -142,7 +155,7 @@ CoverageMap::StorageResult CoverageMap::storeInMap(VoxelProjectedShadow* polygon if (_isRoot || _myBoundingBox.contains(polygon->getBoundingBox())) { -/* +/** if (_isRoot) { printLog("CoverageMap::storeInMap()... this map _isRoot, so all polygons are contained....\n"); } else { @@ -150,7 +163,7 @@ if (_isRoot) { _myBoundingBox.printDebugDetails("_myBoundingBox"); polygon->getBoundingBox().printDebugDetails("polygon->getBoundingBox()"); } -*/ +**/ // check to make sure this polygon isn't occluded by something at this level for (int i = 0; i < _polygonCount; i++) { diff --git a/libraries/voxels/src/CoverageMap.h b/libraries/voxels/src/CoverageMap.h index 57db884593..09474e9333 100644 --- a/libraries/voxels/src/CoverageMap.h +++ b/libraries/voxels/src/CoverageMap.h @@ -74,6 +74,7 @@ private: static const int DEFAULT_GROW_SIZE = 100; static int _mapCount; static int _maxPolygonsUsed; + static int _totalPolygons; }; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index aea4a8778b..6379e0c903 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -89,8 +89,11 @@ void VoxelTree::recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseV for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); if (childNode) { - float distance = glm::distance(point, childNode->getCenter()); - currentCount = insertIntoSortedArrays((void*)childNode, distance, i, + // 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); +//childNode->printDebugDetails(""); + currentCount = insertIntoSortedArrays((void*)childNode, distanceSquared, i, (void**)&sortedChildren, (float*)&distancesToChildren, (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); } @@ -101,6 +104,8 @@ 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]); +//childNode->printDebugDetails(""); recurseNodeWithOperationDistanceSorted(childNode, operation, point, extraData); } } From abb08e24821258ec9418816f371fd6a5d0caec44 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Jun 2013 13:30:04 -0700 Subject: [PATCH 17/67] handle out of view points --- libraries/voxels/src/ViewFrustum.cpp | 26 ++++++++++++++++--- libraries/voxels/src/ViewFrustum.h | 2 +- libraries/voxels/src/VoxelProjectedShadow.cpp | 10 +++++++ libraries/voxels/src/VoxelProjectedShadow.h | 7 +++++ 4 files changed, 41 insertions(+), 4 deletions(-) diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 491a355040..0a492d2d6e 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -426,7 +426,7 @@ void ViewFrustum::printDebugDetails() const { } -glm::vec2 ViewFrustum::projectPoint(glm::vec3 point) const { +glm::vec2 ViewFrustum::projectPoint(glm::vec3 point, bool& pointInView) const { // Projection matrix : Field of View, ratio, display range : near to far glm::mat4 projection = glm::perspective(_fieldOfView, _aspectRatio, _nearClip, _farClip); @@ -437,7 +437,19 @@ glm::vec2 ViewFrustum::projectPoint(glm::vec3 point) const { glm::vec4 pointVec4 = glm::vec4(point,1); glm::vec4 projectedPointVec4 = VP * pointVec4; - glm::vec2 projectedPoint(projectedPointVec4.x / projectedPointVec4.w, projectedPointVec4.y / projectedPointVec4.w); + pointInView = (projectedPointVec4.w > 0); // math! If the w result is negative then the point is behind the viewer + + // what happens with w is 0??? + float x = projectedPointVec4.x / projectedPointVec4.w; + float y = projectedPointVec4.y / projectedPointVec4.w; + glm::vec2 projectedPoint(x,y); + + // if the point is out of view we also need to flip the signs of x and y + if (!pointInView) { + projectedPoint.x = -x; + projectedPoint.y = -y; + } + return projectedPoint; } @@ -505,16 +517,24 @@ VoxelProjectedShadow ViewFrustum::getProjectedShadow(const AABox& box) const { VoxelProjectedShadow shadow(vertexCount); + bool pointInView = true; + bool allPointsInView = false; // assume the best, but wait till we know we have a vertex + bool anyPointsInView = false; // assume the worst! if (vertexCount) { + allPointsInView = true; // assume the best! for(int i = 0; i < vertexCount; i++) { int vertexNum = hullVertexLookup[lookUp][i+1]; glm::vec3 point = box.getVertex((BoxVertex)vertexNum); - glm::vec2 projectedPoint = projectPoint(point); + glm::vec2 projectedPoint = projectPoint(point, pointInView); + allPointsInView = allPointsInView && pointInView; + anyPointsInView = anyPointsInView || pointInView; shadow.setVertex(i, projectedPoint); } } // set the distance from our camera position, to the closest vertex float distance = glm::distance(getPosition(), box.getCenter()); shadow.setDistance(distance); + shadow.setAnyInView(anyPointsInView); + shadow.setAllInView(allPointsInView); return shadow; } diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 04ef0dc7a9..bf30aa4818 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -88,7 +88,7 @@ public: void printDebugDetails() const; - glm::vec2 projectPoint(glm::vec3 point) const; + glm::vec2 projectPoint(glm::vec3 point, bool& pointInView) const; VoxelProjectedShadow getProjectedShadow(const AABox& box) const; private: diff --git a/libraries/voxels/src/VoxelProjectedShadow.cpp b/libraries/voxels/src/VoxelProjectedShadow.cpp index 1ddb6370a9..19e0fe5e7d 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.cpp +++ b/libraries/voxels/src/VoxelProjectedShadow.cpp @@ -50,6 +50,16 @@ void VoxelProjectedShadow::setVertex(int vertex, const glm::vec2& point) { bool VoxelProjectedShadow::occludes(const VoxelProjectedShadow& occludee) const { + // if we are completely out of view, then we definitely don't occlude! + // if the occludee is completely out of view, then we also don't occlude it + // + // this is true, but unfortunately, we're not quite handling projects in the + // case when SOME points are in view and others are not. So, we will not consider + // occlusion for any shadows that are partially in view. + if (!getAllInView() || !occludee.getAllInView() ) { + return false; + } + // first check the bounding boxes, the occludee mush be fully within the boounding box of this shadow if ((occludee.getMaxX() > getMaxX()) || (occludee.getMaxY() > getMaxY()) || diff --git a/libraries/voxels/src/VoxelProjectedShadow.h b/libraries/voxels/src/VoxelProjectedShadow.h index ffe13bb9b6..30bf80b630 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.h +++ b/libraries/voxels/src/VoxelProjectedShadow.h @@ -43,6 +43,11 @@ public: float getDistance() const { return _distance; } void setDistance(float distance) { _distance = distance; } + bool getAnyInView() const { return _anyInView; }; + void setAnyInView(bool anyInView) { _anyInView = anyInView; }; + bool getAllInView() const { return _allInView; }; + void setAllInView(bool allInView) { _allInView = allInView; }; + bool occludes(const VoxelProjectedShadow& occludee) const; bool pointInside(const glm::vec2& point) const; @@ -65,6 +70,8 @@ private: float _minX; float _minY; float _distance; + bool _anyInView; // if any points are in view + bool _allInView; // if all points are in view }; From 40c2cf2d446d06ee10d186b32cfff8acaca1a5cf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Jun 2013 13:31:26 -0700 Subject: [PATCH 18/67] removed some dead code --- interface/src/Application.cpp | 5 ----- interface/src/Application.h | 1 - 2 files changed, 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d4250c6b51..252a314e81 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1943,11 +1943,6 @@ glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { return screenPoint; } -glm::vec2 Application::getScreenPoint(glm::vec3 voxelPoint) { - glm::vec2 projectedPoint = _viewFrustum.projectPoint(voxelPoint * (float)TREE_SCALE); - return getScaledScreenPoint(projectedPoint); -} - void Application::renderVirtualOccluders() { if (_debugShowVirtualOccluders->isChecked()) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 3617883e13..8742a58c8f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -148,7 +148,6 @@ private: // Couple of debug routines for use in debuggin/developing Occlusion Culling. Will be removed eventually void renderVirtualOccluders(); - glm::vec2 getScreenPoint(glm::vec3 voxelPoint); glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); void renderViewFrustum(ViewFrustum& viewFrustum); From 7fb4ed276fd444ff49d29db007991efbef64d1b5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Jun 2013 14:10:53 -0700 Subject: [PATCH 19/67] removed some debugging code --- libraries/voxels/src/CoverageMap.cpp | 42 ++++++---------------------- 1 file changed, 8 insertions(+), 34 deletions(-) diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp index fff6345a5a..643f73e163 100644 --- a/libraries/voxels/src/CoverageMap.cpp +++ b/libraries/voxels/src/CoverageMap.cpp @@ -16,7 +16,7 @@ CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygo _isRoot(isRoot), _myBoundingBox(boundingBox), _managePolygons(managePolygons) { _mapCount++; init(); - printLog("CoverageMap created... _mapCount=%d\n",_mapCount); + //printLog("CoverageMap created... _mapCount=%d\n",_mapCount); }; CoverageMap::~CoverageMap() { @@ -33,12 +33,12 @@ CoverageMap::~CoverageMap() { delete _childMaps[i]; } } - + if (_isRoot) { printLog("CoverageMap last to be deleted...\n"); - printLog("_mapCount=%d\n",_mapCount); - printLog("_maxPolygonsUsed=%d\n",_maxPolygonsUsed); - printLog("_totalPolygons=%d\n",_totalPolygons); + printLog("_mapCount=%d\n",_mapCount); + printLog("_maxPolygonsUsed=%d\n",_maxPolygonsUsed); + printLog("_totalPolygons=%d\n",_totalPolygons); _maxPolygonsUsed = 0; _totalPolygons = 0; @@ -89,7 +89,7 @@ void CoverageMap::growPolygonArray() { _polygons = newPolygons; _polygonDistances = newDistances; _polygonArraySize = _polygonArraySize + DEFAULT_GROW_SIZE; -//printLog("CoverageMap::growPolygonArray() _polygonArraySize=%d...\n",_polygonArraySize); + //printLog("CoverageMap::growPolygonArray() _polygonArraySize=%d...\n",_polygonArraySize); } int CoverageMap::_maxPolygonsUsed = 0; @@ -101,9 +101,6 @@ void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { _totalPolygons++; -//printLog("CoverageMap::storeInArray()..."); -//polygon->printDebugDetails(); - if (_polygonArraySize < _polygonCount + 1) { growPolygonArray(); } @@ -118,8 +115,8 @@ void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { if (_polygonCount > _maxPolygonsUsed) { _maxPolygonsUsed = _polygonCount; - printLog("CoverageMap new _maxPolygonsUsed reached=%d\n",_maxPolygonsUsed); - _myBoundingBox.printDebugDetails("map._myBoundingBox"); + //printLog("CoverageMap new _maxPolygonsUsed reached=%d\n",_maxPolygonsUsed); + //_myBoundingBox.printDebugDetails("map._myBoundingBox"); } } @@ -149,38 +146,16 @@ void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { // end // return DOESNT_FIT CoverageMap::StorageResult CoverageMap::storeInMap(VoxelProjectedShadow* polygon) { - -//printLog("CoverageMap::storeInMap()..."); -//polygon->printDebugDetails(); - if (_isRoot || _myBoundingBox.contains(polygon->getBoundingBox())) { - -/** -if (_isRoot) { - printLog("CoverageMap::storeInMap()... this map _isRoot, so all polygons are contained....\n"); -} else { - printLog("CoverageMap::storeInMap()... _myBoundingBox.contains(polygon)....\n"); - _myBoundingBox.printDebugDetails("_myBoundingBox"); - polygon->getBoundingBox().printDebugDetails("polygon->getBoundingBox()"); -} -**/ - // check to make sure this polygon isn't occluded by something at this level for (int i = 0; i < _polygonCount; i++) { VoxelProjectedShadow* polygonAtThisLevel = _polygons[i]; - -//printLog("CoverageMap::storeInMap()... polygonAtThisLevel = _polygons[%d] =",i); -//polygonAtThisLevel->printDebugDetails(); - // Check to make sure that the polygon in question is "behind" the polygon in the list // otherwise, we don't need to test it's occlusion (although, it means we've potentially // added an item previously that may be occluded??? Is that possible? Maybe not, because two // voxels can't have the exact same outline. So one occludes the other, they can't both occlude // each other. if (polygonAtThisLevel->occludes(*polygon)) { - -//printLog("CoverageMap::storeInMap()... polygonAtThisLevel->occludes(*polygon)...\n",i); - // if the polygonAtThisLevel is actually behind the one we're inserting, then we don't // want to report our inserted one as occluded, but we do want to add our inserted one. if (polygonAtThisLevel->getDistance() >= polygon->getDistance()) { @@ -211,4 +186,3 @@ if (_isRoot) { } return DOESNT_FIT; } - From 620a4a8ad60afda791f44070e63a88e052567997 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 13 Jun 2013 16:37:14 -0700 Subject: [PATCH 20/67] latest occlusion culling with support for checking map without adding to coverage map for checking parent nodes --- interface/src/VoxelSystem.cpp | 138 ++++++++++++++++++++------- interface/src/VoxelSystem.h | 3 +- libraries/voxels/src/CoverageMap.cpp | 20 ++-- libraries/voxels/src/CoverageMap.h | 4 +- libraries/voxels/src/VoxelTree.h | 8 +- 5 files changed, 124 insertions(+), 49 deletions(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 0f919914f4..95e6b382b9 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1158,70 +1158,138 @@ void VoxelSystem::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* dest } struct FalseColorizeOccludedArgs { - VoxelProjectedShadow occluder; ViewFrustum* viewFrustum; CoverageMap* map; + VoxelTree* tree; + long totalVoxels; + long coloredVoxels; + long occludedVoxels; + long notOccludedVoxels; + long outOfView; + long subtreeVoxelsSkipped; + long nonLeaves; + long nonLeavesOutOfView; + long nonLeavesOccluded; + long stagedForDeletion; }; -bool VoxelSystem::falseColorizeTestOccludedOperation(VoxelNode* node, void* extraData) { - FalseColorizeOccludedArgs* args = (FalseColorizeOccludedArgs*) extraData; - if (node->isColored()) { - AABox voxelBox = node->getAABox(); - voxelBox.scale(TREE_SCALE); - VoxelProjectedShadow voxelShadow = args->viewFrustum->getProjectedShadow(voxelBox); - if (args->occluder.occludes(voxelShadow)) { - node->setFalseColor(255, 0, 0); - } - } - return true; // keep going! -} +struct FalseColorizeSubTreeOperationArgs { + unsigned char color[NUMBER_OF_COLORS]; + long voxelsTouched; +}; -void VoxelSystem::falseColorizeTestOccluded() { - FalseColorizeOccludedArgs args; - args.viewFrustum = Application::getInstance()->getViewFrustum(); - - AABox box(glm::vec3(0.0125,0,0.025), 0.0125); - box.scale(TREE_SCALE); - args.occluder = args.viewFrustum->getProjectedShadow(box); - - _tree->recurseTreeWithOperation(falseColorizeTestOccludedOperation,(void*)&args); - setupNewVoxelsForDrawing(); +bool VoxelSystem::falseColorizeSubTreeOperation(VoxelNode* node, void* extraData) { + FalseColorizeSubTreeOperationArgs* args = (FalseColorizeSubTreeOperationArgs*) extraData; + node->setFalseColor(args->color[0], args->color[1], args->color[2]); + args->voxelsTouched++; + return true; } bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraData) { -//node->printDebugDetails(">>>>>>>>>>>>>>> falseColorizeOccludedOperation() BEGIN >>>>>>>>>>>>>>"); + FalseColorizeOccludedArgs* args = (FalseColorizeOccludedArgs*) extraData; - if (node->isColored() && node->isLeaf() && !node->isStagedForDeletion() && node->getShouldRender()) { -//printLog("***** falseColorizeOccludedOperation() NODE is colored, etc, so consider it *****\n"); + args->totalVoxels++; + + // if this node is staged for deletion, then just return + if (node->isStagedForDeletion()) { + args->stagedForDeletion++; + return true; + } + + // If we are a parent, let's see if we're completely occluded. + if (!node->isLeaf()) { + args->nonLeaves++; + AABox voxelBox = node->getAABox(); voxelBox.scale(TREE_SCALE); VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(args->viewFrustum->getProjectedShadow(voxelBox)); - CoverageMap::StorageResult result = args->map->storeInMap(voxelShadow); + + // If we're not all in view, then ignore it, and just return. But keep searching... + if (!voxelShadow->getAllInView()) { + args->nonLeavesOutOfView++; + delete voxelShadow; + return true; + } + + CoverageMap::StorageResult result = args->map->checkMap(voxelShadow, false); + if (result == CoverageMap::OCCLUDED) { + args->nonLeavesOccluded++; + delete voxelShadow; + + FalseColorizeSubTreeOperationArgs subArgs; + subArgs.color[0] = 0; + subArgs.color[1] = 255; + subArgs.color[2] = 0; + subArgs.voxelsTouched = 0; + + args->tree->recurseNodeWithOperation(node, falseColorizeSubTreeOperation, &subArgs ); + + args->subtreeVoxelsSkipped += (subArgs.voxelsTouched - 1); + args->totalVoxels += (subArgs.voxelsTouched - 1); + + return false; + } + + delete voxelShadow; + return true; // keep looking... + } + + if (node->isLeaf() && node->isColored() && node->getShouldRender()) { + args->coloredVoxels++; + + AABox voxelBox = node->getAABox(); + voxelBox.scale(TREE_SCALE); + VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(args->viewFrustum->getProjectedShadow(voxelBox)); + + // If we're not all in view, then ignore it, and just return. But keep searching... + if (!voxelShadow->getAllInView()) { + args->outOfView++; + delete voxelShadow; + return true; + } + + CoverageMap::StorageResult result = args->map->checkMap(voxelShadow, true); if (result == CoverageMap::OCCLUDED) { -//printLog("***** falseColorizeOccludedOperation() NODE is OCCLUDED *****\n"); node->setFalseColor(255, 0, 0); + args->occludedVoxels++; } else if (result == CoverageMap::STORED) { -//printLog("***** falseColorizeOccludedOperation() NODE is STORED *****\n"); + args->notOccludedVoxels++; + //printLog("***** falseColorizeOccludedOperation() NODE is STORED *****\n"); } else if (result == CoverageMap::DOESNT_FIT) { -//printLog("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n"); + //printLog("***** falseColorizeOccludedOperation() NODE DOESNT_FIT???? *****\n"); } } -//printLog("<<<<<<<<<<<<<<<<< falseColorizeOccludedOperation() END <<<<<<<<<<<<<<<<<\n"); return true; // keep going! } - void VoxelSystem::falseColorizeOccluded() { + PerformanceWarning warn(true, "falseColorizeOccluded()",true); CoverageMap map(BoundingBox(glm::vec2(-2.f,-2.f), glm::vec2(4.f,4.f)), true); FalseColorizeOccludedArgs args; args.viewFrustum = Application::getInstance()->getViewFrustum(); args.map = ↦ + args.totalVoxels = 0; + args.coloredVoxels = 0; + args.occludedVoxels = 0; + args.notOccludedVoxels = 0; + args.outOfView = 0; + args.subtreeVoxelsSkipped = 0; + args.nonLeaves = 0; + args.stagedForDeletion = 0; + args.nonLeavesOutOfView = 0; + args.nonLeavesOccluded = 0; + args.tree = _tree; - AABox box(glm::vec3(0.0125,0,0.025), 0.0125); - box.scale(TREE_SCALE); - args.occluder = args.viewFrustum->getProjectedShadow(box); glm::vec3 position = args.viewFrustum->getPosition() * (1.0f/TREE_SCALE); _tree->recurseTreeWithOperationDistanceSorted(falseColorizeOccludedOperation, position, (void*)&args); + + printLog("falseColorizeOccluded()\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", + args.totalVoxels, args.coloredVoxels, args.occludedVoxels, + args.notOccludedVoxels, args.outOfView, args.subtreeVoxelsSkipped, + args.stagedForDeletion, + args.nonLeaves, args.nonLeavesOutOfView, args.nonLeavesOccluded); + + setupNewVoxelsForDrawing(); } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index f67960748a..5087308392 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -57,7 +57,6 @@ public: void falseColorizeDistanceFromView(ViewFrustum* viewFrustum); void falseColorizeRandomEveryOther(); void falseColorizeOccluded(); - void falseColorizeTestOccluded(); void killLocalVoxels(); void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; }; @@ -123,7 +122,7 @@ private: static bool falseColorizeRandomEveryOtherOperation(VoxelNode* node, void* extraData); static bool collectStatsForTreesAndVBOsOperation(VoxelNode* node, void* extraData); static bool falseColorizeOccludedOperation(VoxelNode* node, void* extraData); - static bool falseColorizeTestOccludedOperation(VoxelNode* node, void* extraData); + static bool falseColorizeSubTreeOperation(VoxelNode* node, void* extraData); int updateNodeInArraysAsFullVBO(VoxelNode* node); int updateNodeInArraysAsPartialVBO(VoxelNode* node); diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp index 643f73e163..413360a330 100644 --- a/libraries/voxels/src/CoverageMap.cpp +++ b/libraries/voxels/src/CoverageMap.cpp @@ -145,7 +145,7 @@ void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { // return STORED // end // return DOESNT_FIT -CoverageMap::StorageResult CoverageMap::storeInMap(VoxelProjectedShadow* polygon) { +CoverageMap::StorageResult CoverageMap::checkMap(VoxelProjectedShadow* polygon, bool storeIt) { if (_isRoot || _myBoundingBox.contains(polygon->getBoundingBox())) { // check to make sure this polygon isn't occluded by something at this level for (int i = 0; i < _polygonCount; i++) { @@ -159,8 +159,12 @@ CoverageMap::StorageResult CoverageMap::storeInMap(VoxelProjectedShadow* polygon // if the polygonAtThisLevel is actually behind the one we're inserting, then we don't // want to report our inserted one as occluded, but we do want to add our inserted one. if (polygonAtThisLevel->getDistance() >= polygon->getDistance()) { - storeInArray(polygon); - return STORED; + if (storeIt) { + storeInArray(polygon); + return STORED; + } else { + return NOT_STORED; + } } // this polygon is occluded by a closer polygon, so don't store it, and let the caller know return OCCLUDED; @@ -176,13 +180,17 @@ CoverageMap::StorageResult CoverageMap::storeInMap(VoxelProjectedShadow* polygon if (!_childMaps[i]) { _childMaps[i] = new CoverageMap(childMapBoundingBox, NOT_ROOT, _managePolygons); } - return _childMaps[i]->storeInMap(polygon); + return _childMaps[i]->checkMap(polygon, storeIt); } } // if we got this far, then the polygon is in our bounding box, but doesn't fit in // any of our child bounding boxes, so we should add it here. - storeInArray(polygon); - return STORED; + if (storeIt) { + storeInArray(polygon); + return STORED; + } else { + return NOT_STORED; + } } return DOESNT_FIT; } diff --git a/libraries/voxels/src/CoverageMap.h b/libraries/voxels/src/CoverageMap.h index 09474e9333..4c3f10d17b 100644 --- a/libraries/voxels/src/CoverageMap.h +++ b/libraries/voxels/src/CoverageMap.h @@ -52,8 +52,8 @@ public: CoverageMap(BoundingBox boundingBox, bool isRoot = IS_ROOT, bool managePolygons = false); ~CoverageMap(); - typedef enum {STORED, OCCLUDED, DOESNT_FIT} StorageResult; - StorageResult storeInMap(VoxelProjectedShadow* polygon); + typedef enum {STORED, OCCLUDED, DOESNT_FIT, NOT_STORED} StorageResult; + StorageResult checkMap(VoxelProjectedShadow* polygon, bool storeIt = true); BoundingBox getChildBoundingBox(int childIndex); diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index ad644f8dc6..474c9a4063 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -102,6 +102,10 @@ public: void copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode); bool getShouldReaverage() const { return _shouldReaverage; } + + void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); + void recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseVoxelTreeOperation operation, + const glm::vec3& point, void* extraData); private: void deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraData); @@ -118,10 +122,6 @@ private: static bool countVoxelsOperation(VoxelNode* node, void* extraData); - void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); - void recurseNodeWithOperationDistanceSorted(VoxelNode* node, RecurseVoxelTreeOperation operation, - const glm::vec3& point, void* extraData); - VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; VoxelNode* createMissingNode(VoxelNode* lastParentNode, unsigned char* deepestCodeToCreate); int readNodeData(VoxelNode *destinationNode, unsigned char* nodeData, int bufferSizeBytes, From 593730682dad4d09ecf43cca2fe0b64c245b9a68 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 14 Jun 2013 12:04:25 -0600 Subject: [PATCH 21/67] add timing for TwoPole calls --- audio-mixer/src/main.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 362be4506e..09d74e6ccf 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -116,6 +116,8 @@ int main(int argc, const char* argv[]) { float sumFrameTimePercentages = 0.0f; int numStatCollections = 0; + timeval twoPoleStart, twoPoleEnd; + // if we'll be sending stats, call the Logstash::socket() method to make it load the logstash IP outside the loop if (Logstash::shouldSendStats()) { Logstash::socket(); @@ -257,6 +259,8 @@ int main(int argc, const char* argv[]) { numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); + gettimeofday(&twoPoleStart, NULL); + // grab the TwoPole object for this source, add it if it doesn't exist TwoPoleAgentMap& agentTwoPoles = agentRingBuffer->getTwoPoles(); TwoPoleAgentMap::iterator twoPoleIterator = agentTwoPoles.find(otherAgent->getAgentID()); @@ -276,6 +280,10 @@ int main(int argc, const char* argv[]) { TWO_POLE_MAX_FILTER_STRENGTH * fabsf(bearingRelativeAngleToSource) / 180.0f, true); + + gettimeofday(&twoPoleEnd, NULL); + + printf("TPP: %lld\n", usecTimestamp(&twoPoleEnd) - usecTimestamp(&twoPoleStart)); } } @@ -302,7 +310,14 @@ int main(int argc, const char* argv[]) { } if (otherAgentTwoPole) { + + gettimeofday(&twoPoleStart, NULL); + otherAgentBuffer->getNextOutput()[s] = otherAgentTwoPole->tick(otherAgentBuffer->getNextOutput()[s]); + + gettimeofday(&twoPoleEnd, NULL); + + printf("TPC: %lld\n", usecTimestamp(&twoPoleEnd) - usecTimestamp(&twoPoleStart)); } int16_t currentSample = otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient; From 892167510a007147e8a05eab98ce60f2d1fd6d4b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Fri, 14 Jun 2013 12:15:12 -0600 Subject: [PATCH 22/67] time TwoPole call for 256 samples --- audio-mixer/src/main.cpp | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 09d74e6ccf..39ae1b8637 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -259,8 +259,6 @@ int main(int argc, const char* argv[]) { numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); - gettimeofday(&twoPoleStart, NULL); - // grab the TwoPole object for this source, add it if it doesn't exist TwoPoleAgentMap& agentTwoPoles = agentRingBuffer->getTwoPoles(); TwoPoleAgentMap::iterator twoPoleIterator = agentTwoPoles.find(otherAgent->getAgentID()); @@ -280,10 +278,6 @@ int main(int argc, const char* argv[]) { TWO_POLE_MAX_FILTER_STRENGTH * fabsf(bearingRelativeAngleToSource) / 180.0f, true); - - gettimeofday(&twoPoleEnd, NULL); - - printf("TPP: %lld\n", usecTimestamp(&twoPoleEnd) - usecTimestamp(&twoPoleStart)); } } @@ -298,6 +292,17 @@ int main(int argc, const char* argv[]) { ? otherAgentBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay : otherAgentBuffer->getNextOutput() - numSamplesDelay; + gettimeofday(&twoPoleStart, NULL); + + for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { + if (otherAgentTwoPole) { + otherAgentBuffer->getNextOutput()[s] = otherAgentTwoPole->tick(otherAgentBuffer->getNextOutput()[s]); + } + } + + gettimeofday(&twoPoleEnd, NULL); + + printf("TPC: %lld\n", usecTimestamp(&twoPoleEnd) - usecTimestamp(&twoPoleStart)); for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { if (s < numSamplesDelay) { @@ -309,16 +314,9 @@ int main(int argc, const char* argv[]) { plateauAdditionOfSamples(delayedChannel[s], earlierSample); } - if (otherAgentTwoPole) { - - gettimeofday(&twoPoleStart, NULL); - - otherAgentBuffer->getNextOutput()[s] = otherAgentTwoPole->tick(otherAgentBuffer->getNextOutput()[s]); - - gettimeofday(&twoPoleEnd, NULL); - - printf("TPC: %lld\n", usecTimestamp(&twoPoleEnd) - usecTimestamp(&twoPoleStart)); - } +// if (otherAgentTwoPole) { +// otherAgentBuffer->getNextOutput()[s] = otherAgentTwoPole->tick(otherAgentBuffer->getNextOutput()[s]); +// } int16_t currentSample = otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient; From edc13776926204732fde0c34e85dd80601c8ddd3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 09:19:35 -0700 Subject: [PATCH 23/67] perform the two-pole effect across 256 samples, not one per call --- audio-mixer/src/main.cpp | 38 +++++++++++++++++++++----------------- 1 file changed, 21 insertions(+), 17 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 39ae1b8637..e74191ea60 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -116,6 +116,8 @@ int main(int argc, const char* argv[]) { float sumFrameTimePercentages = 0.0f; int numStatCollections = 0; + stk::StkFrames stkFrameBuffer(BUFFER_LENGTH_SAMPLES_PER_CHANNEL, 1); + timeval twoPoleStart, twoPoleEnd; // if we'll be sending stats, call the Logstash::socket() method to make it load the logstash IP outside the loop @@ -163,6 +165,9 @@ int main(int argc, const char* argv[]) { } for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { + + const int PHASE_DELAY_AT_90 = 20; + if (agent->getType() == AGENT_TYPE_AVATAR) { AvatarAudioRingBuffer* agentRingBuffer = (AvatarAudioRingBuffer*) agent->getLinkedData(); @@ -250,7 +255,6 @@ int main(int argc, const char* argv[]) { glm::normalize(rotatedSourcePosition), glm::vec3(0.0f, 1.0f, 0.0f)); - const int PHASE_DELAY_AT_90 = 20; const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5; // figure out the number of samples of delay and the ratio of the amplitude @@ -281,6 +285,8 @@ int main(int argc, const char* argv[]) { } } + int16_t* sourceBuffer = otherAgentBuffer->getNextOutput(); + int16_t* goodChannel = (bearingRelativeAngleToSource > 0.0f) ? clientSamples : clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL; @@ -292,33 +298,25 @@ int main(int argc, const char* argv[]) { ? otherAgentBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay : otherAgentBuffer->getNextOutput() - numSamplesDelay; - gettimeofday(&twoPoleStart, NULL); - for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { - if (otherAgentTwoPole) { - otherAgentBuffer->getNextOutput()[s] = otherAgentTwoPole->tick(otherAgentBuffer->getNextOutput()[s]); - } + // load up the stkFrameBuffer with this source's samples + stkFrameBuffer[s] = (stk::StkFloat) sourceBuffer[s]; } - gettimeofday(&twoPoleEnd, NULL); - - printf("TPC: %lld\n", usecTimestamp(&twoPoleEnd) - usecTimestamp(&twoPoleStart)); + // perform the TwoPole effect on the stkFrameBuffer + if (otherAgentTwoPole) { + otherAgentTwoPole->tick(stkFrameBuffer); + } for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { if (s < numSamplesDelay) { // pull the earlier sample for the delayed channel - int earlierSample = delaySamplePointer[s] - * attenuationCoefficient - * weakChannelAmplitudeRatio; + int earlierSample = delaySamplePointer[s] * attenuationCoefficient * weakChannelAmplitudeRatio; plateauAdditionOfSamples(delayedChannel[s], earlierSample); } -// if (otherAgentTwoPole) { -// otherAgentBuffer->getNextOutput()[s] = otherAgentTwoPole->tick(otherAgentBuffer->getNextOutput()[s]); -// } - - int16_t currentSample = otherAgentBuffer->getNextOutput()[s] * attenuationCoefficient; + int16_t currentSample = stkFrameBuffer[s] * attenuationCoefficient; plateauAdditionOfSamples(goodChannel[s], currentSample); @@ -326,6 +324,12 @@ int main(int argc, const char* argv[]) { plateauAdditionOfSamples(delayedChannel[s + numSamplesDelay], currentSample * weakChannelAmplitudeRatio); } + + if (s >= BUFFER_LENGTH_SAMPLES_PER_CHANNEL - PHASE_DELAY_AT_90) { + // this could be a delayed sample on the next pass + // so store the affected back in the ARB + otherAgentBuffer->getNextOutput()[s] = (int16_t) stkFrameBuffer[s]; + } } } } From 5acb0bd1a300faabec6a54d6ffe1872573465a7e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 09:22:43 -0700 Subject: [PATCH 24/67] add timing for two pole effect --- audio-mixer/src/main.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index e74191ea60..b1494d3c61 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -298,6 +298,8 @@ int main(int argc, const char* argv[]) { ? otherAgentBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay : otherAgentBuffer->getNextOutput() - numSamplesDelay; + gettimeofday(&twoPoleStart, NULL); + for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { // load up the stkFrameBuffer with this source's samples stkFrameBuffer[s] = (stk::StkFloat) sourceBuffer[s]; @@ -308,6 +310,10 @@ int main(int argc, const char* argv[]) { otherAgentTwoPole->tick(stkFrameBuffer); } + gettimeofday(&twoPoleEnd, NULL); + + printf("Time taken for TP: %lld\n", usecTimestamp(&twoPoleEnd) - usecTimestamp(&twoPoleStart)); + for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { if (s < numSamplesDelay) { // pull the earlier sample for the delayed channel From 7fe6c0e3b311d6b4787e49989acdfc9eb82a495e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 09:34:12 -0700 Subject: [PATCH 25/67] added occlusion culling menu option --- interface/src/Application.cpp | 5 +++++ interface/src/Application.h | 1 + libraries/avatars/src/AvatarData.cpp | 15 +++++++++------ libraries/avatars/src/AvatarData.h | 4 ++++ 4 files changed, 19 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ef9fc2ae11..9a108f66c4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1005,6 +1005,10 @@ void Application::setWantsDelta(bool wantsDelta) { _myAvatar.setWantDelta(wantsDelta); } +void Application::setWantsOcclusionCulling(bool wantsOcclusionCulling) { + _myAvatar.setWantOcclusionCulling(wantsOcclusionCulling); +} + void Application::updateVoxelModeActions() { // only the sender can be checked foreach (QAction* action, _voxelModeActions->actions()) { @@ -1346,6 +1350,7 @@ void Application::initMenu() { debugMenu->addAction("Wants Res-In", this, SLOT(setWantsResIn(bool)))->setCheckable(true); debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true); debugMenu->addAction("Wants View Delta Sending", this, SLOT(setWantsDelta(bool)))->setCheckable(true); + debugMenu->addAction("Wants Occlusion Culling", this, SLOT(setWantsOcclusionCulling(bool)))->setCheckable(true); QMenu* settingsMenu = menuBar->addMenu("Settings"); (_settingsAutosave = settingsMenu->addAction("Autosave"))->setCheckable(true); diff --git a/interface/src/Application.h b/interface/src/Application.h index 8742a58c8f..c910787463 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -114,6 +114,7 @@ private slots: void setWantsMonochrome(bool wantsMonochrome); void setWantsResIn(bool wantsResIn); void setWantsDelta(bool wantsDelta); + void setWantsOcclusionCulling(bool wantsOcclusionCulling); void updateVoxelModeActions(); void decreaseVoxelSize(); void increaseVoxelSize(); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index d24754b28f..8fb9fa05d1 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -35,6 +35,7 @@ AvatarData::AvatarData(Agent* owningAgent) : _wantResIn(false), _wantColor(true), _wantDelta(false), + _wantOcclusionCulling(false), _headData(NULL) { @@ -106,9 +107,10 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { // bitMask of less than byte wide items unsigned char bitItems = 0; - if (_wantResIn) { setAtBit(bitItems,WANT_RESIN_AT_BIT); } - if (_wantColor) { setAtBit(bitItems,WANT_COLOR_AT_BIT); } - if (_wantDelta) { setAtBit(bitItems,WANT_DELTA_AT_BIT); } + if (_wantResIn) { setAtBit(bitItems, WANT_RESIN_AT_BIT); } + if (_wantColor) { setAtBit(bitItems, WANT_COLOR_AT_BIT); } + if (_wantDelta) { setAtBit(bitItems, WANT_DELTA_AT_BIT); } + if (_wantOcclusionCulling) { setAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); } // key state setSemiNibbleAt(bitItems,KEY_STATE_START_BIT,_keyState); @@ -192,9 +194,10 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { // voxel sending features... unsigned char bitItems = 0; bitItems = (unsigned char)*sourceBuffer++; - _wantResIn = oneAtBit(bitItems,WANT_RESIN_AT_BIT); - _wantColor = oneAtBit(bitItems,WANT_COLOR_AT_BIT); - _wantDelta = oneAtBit(bitItems,WANT_DELTA_AT_BIT); + _wantResIn = oneAtBit(bitItems, WANT_RESIN_AT_BIT); + _wantColor = oneAtBit(bitItems, WANT_COLOR_AT_BIT); + _wantDelta = oneAtBit(bitItems, WANT_DELTA_AT_BIT); + _wantOcclusionCulling = oneAtBit(bitItems, WANT_OCCLUSION_CULLING_BIT); // key state, stored as a semi-nibble in the bitItems _keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT); diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index cf9845ab4c..4a94db133b 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -23,6 +23,7 @@ const int WANT_COLOR_AT_BIT = 1; const int WANT_DELTA_AT_BIT = 2; const int KEY_STATE_START_BIT = 3; // 4th and 5th bits const int HAND_STATE_START_BIT = 5; // 6th and 7th bits +const int WANT_OCCLUSION_CULLING_BIT = 7; // 8th bit const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation @@ -89,9 +90,11 @@ public: bool getWantResIn() const { return _wantResIn; } bool getWantColor() const { return _wantColor; } bool getWantDelta() const { return _wantDelta; } + bool getWantOcclusionCulling() const { return _wantOcclusionCulling; } void setWantResIn(bool wantResIn) { _wantResIn = wantResIn; } void setWantColor(bool wantColor) { _wantColor = wantColor; } void setWantDelta(bool wantDelta) { _wantDelta = wantDelta; } + void setWantOcclusionCulling(bool wantOcclusionCulling) { _wantOcclusionCulling = wantOcclusionCulling; } void setHeadData(HeadData* headData) { _headData = headData; } @@ -125,6 +128,7 @@ protected: bool _wantResIn; bool _wantColor; bool _wantDelta; + bool _wantOcclusionCulling; HeadData* _headData; private: From c8d4b2ebed9413a85006cf6cab6068e569559ba4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 09:35:13 -0700 Subject: [PATCH 26/67] added erase() and some other tweaks to CoverageMap --- libraries/voxels/src/CoverageMap.cpp | 22 +++++++++++++++++++++- libraries/voxels/src/CoverageMap.h | 5 ++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp index 413360a330..f83076ee13 100644 --- a/libraries/voxels/src/CoverageMap.cpp +++ b/libraries/voxels/src/CoverageMap.cpp @@ -11,6 +11,7 @@ #include "Log.h" int CoverageMap::_mapCount = 0; +const BoundingBox CoverageMap::ROOT_BOUNDING_BOX = BoundingBox(glm::vec2(-2.f,-2.f), glm::vec2(4.f,4.f)); CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygons) : _isRoot(isRoot), _myBoundingBox(boundingBox), _managePolygons(managePolygons) { @@ -20,20 +21,37 @@ CoverageMap::CoverageMap(BoundingBox boundingBox, bool isRoot, bool managePolygo }; CoverageMap::~CoverageMap() { + erase(); +}; + +void CoverageMap::erase() { + // If we're in charge of managing the polygons, then clean them up first if (_managePolygons) { for (int i = 0; i < _polygonCount; i++) { delete _polygons[i]; + _polygons[i] = NULL; // do we need to do this? } } + + // Now, clean up our local storage + _polygonCount = 0; + _polygonArraySize = 0; if (_polygons) { delete[] _polygons; + _polygons = NULL; + } + if (_polygonDistances) { + delete[] _polygonDistances; + _polygonDistances = NULL; } for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (_childMaps[i]) { delete _childMaps[i]; + _childMaps[i] = NULL; } } +/** if (_isRoot) { printLog("CoverageMap last to be deleted...\n"); printLog("_mapCount=%d\n",_mapCount); @@ -44,13 +62,15 @@ CoverageMap::~CoverageMap() { _totalPolygons = 0; _mapCount = 0; } -}; +**/ +} void CoverageMap::init() { _polygonCount = 0; _polygonArraySize = 0; _polygons = NULL; + _polygonDistances = NULL; memset(_childMaps,0,sizeof(_childMaps)); } diff --git a/libraries/voxels/src/CoverageMap.h b/libraries/voxels/src/CoverageMap.h index 4c3f10d17b..dc46695dba 100644 --- a/libraries/voxels/src/CoverageMap.h +++ b/libraries/voxels/src/CoverageMap.h @@ -48,14 +48,17 @@ public: static const int NUMBER_OF_CHILDREN = 4; static const bool NOT_ROOT=false; static const bool IS_ROOT=true; + static const BoundingBox ROOT_BOUNDING_BOX; - CoverageMap(BoundingBox boundingBox, bool isRoot = IS_ROOT, bool managePolygons = false); + CoverageMap(BoundingBox boundingBox = ROOT_BOUNDING_BOX, bool isRoot = IS_ROOT, bool managePolygons = true); ~CoverageMap(); typedef enum {STORED, OCCLUDED, DOESNT_FIT, NOT_STORED} StorageResult; StorageResult checkMap(VoxelProjectedShadow* polygon, bool storeIt = true); BoundingBox getChildBoundingBox(int childIndex); + + void erase(); // erase the coverage map private: void init(); From 58c4010185f4ad0e557e029718487b9f92f74b92 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 09:36:43 -0700 Subject: [PATCH 27/67] added CoverageMap and occlusion culling to server --- libraries/voxels/src/VoxelTree.cpp | 208 +++++++++++++++++++++++++---- libraries/voxels/src/VoxelTree.h | 33 +++-- voxel-server/src/VoxelAgentData.h | 2 + voxel-server/src/main.cpp | 7 +- 4 files changed, 211 insertions(+), 39 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 6853df3e9b..6e90b06b9c 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -22,6 +22,7 @@ #include "ViewFrustum.h" #include // to load voxels from file #include "VoxelConstants.h" +#include "CoverageMap.h" #include @@ -91,21 +92,19 @@ 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); -//childNode->printDebugDetails(""); + //printLog("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, (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); } - - } for (int i = 0; i < currentCount; i++) { VoxelNode* childNode = sortedChildren[i]; if (childNode) { -//printLog("recurseNodeWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]); -//childNode->printDebugDetails(""); + //printLog("recurseNodeWithOperationDistanceSorted() PROCESSING child[%d] distance=%f...\n", i, distancesToChildren[i]); + //childNode->printDebugDetails(""); recurseNodeWithOperationDistanceSorted(childNode, operation, point, extraData); } } @@ -1118,6 +1117,39 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp if (!node->isInView(*params.viewFrustum)) { 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 + if (params.wantOcclusionCulling && !node->isLeaf()) { + //node->printDebugDetails("upper section, params.wantOcclusionCulling... node="); + AABox voxelBox = node->getAABox(); + voxelBox.scale(TREE_SCALE); + VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(params.viewFrustum->getProjectedShadow(voxelBox)); + + // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion + // culling and proceed as normal + if (voxelShadow->getAllInView()) { + //node->printDebugDetails("upper section, voxelShadow->getAllInView() node="); + + CoverageMap::StorageResult result = params.map->checkMap(voxelShadow, false); + delete voxelShadow; // cleanup + if (result == CoverageMap::OCCLUDED) { + //node->printDebugDetails("upper section, non-Leaf is occluded!! node="); + //args->nonLeavesOccluded++; + + //args->subtreeVoxelsSkipped += (subArgs.voxelsTouched - 1); + //args->totalVoxels += (subArgs.voxelsTouched - 1); + + return bytesAtThisLevel; + } + } else { + //node->printDebugDetails("upper section, shadow Not in view node="); + // If this shadow wasn't "all in view" then we ignored it for occlusion culling, but + // we do need to clean up memory and proceed as normal... + delete voxelShadow; + } + } } bool keepDiggingDeeper = true; // Assuming we're in view we have a great work ethic, we're always ready for more! @@ -1126,37 +1158,68 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // is 1 byte for child colors + 3*NUMBER_OF_CHILDREN bytes for the actual colors + 1 byte for child trees. There could be sub trees // below this point, which might take many more bytes, but that's ok, because we can always mark our subtrees as // not existing and stop the packet at this point, then start up with a new packet for the remaining sub trees. - const int CHILD_COLOR_MASK_BYTES = 1; + unsigned char childrenExistInTreeBits = 0; + unsigned char childrenExistInPacketBits = 0; + unsigned char childrenColoredBits = 0; + + const int CHILD_COLOR_MASK_BYTES = sizeof(childrenColoredBits); const int BYTES_PER_COLOR = 3; - const int CHILD_TREE_EXISTS_BYTES = 1; + const int CHILD_TREE_EXISTS_BYTES = sizeof(childrenExistInTreeBits) + sizeof(childrenExistInPacketBits); const int MAX_LEVEL_BYTES = CHILD_COLOR_MASK_BYTES + NUMBER_OF_CHILDREN * BYTES_PER_COLOR + CHILD_TREE_EXISTS_BYTES; // Make our local buffer large enough to handle writing at this level in case we need to. unsigned char thisLevelBuffer[MAX_LEVEL_BYTES]; unsigned char* writeToThisLevelBuffer = &thisLevelBuffer[0]; - unsigned char childrenExistInTreeBits = 0; - unsigned char childrenExistInPacketBits = 0; - unsigned char childrenColoredBits = 0; int inViewCount = 0; int inViewNotLeafCount = 0; int inViewWithColorCount = 0; - // for each child node, check to see if they exist, are colored, and in view, and if so - // add them to our distance ordered array of children + VoxelNode* sortedChildren[NUMBER_OF_CHILDREN]; + float distancesToChildren[NUMBER_OF_CHILDREN]; + int indexOfChildren[NUMBER_OF_CHILDREN]; // not really needed + int currentCount = 0; + for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); - + // if the caller wants to include childExistsBits, then include them even if not in view if (params.includeExistsBits && childNode) { childrenExistInTreeBits += (1 << (7 - i)); } - + + if (params.wantOcclusionCulling) { + 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); + //childNode->printDebugDetails(""); + + float distance = params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; + + currentCount = insertIntoSortedArrays((void*)childNode, distance, i, + (void**)&sortedChildren, (float*)&distancesToChildren, + (int*)&indexOfChildren, currentCount, NUMBER_OF_CHILDREN); + } + } else { + sortedChildren[i] = childNode; + indexOfChildren[i] = i; + distancesToChildren[i] = 0.0f; + currentCount++; + } + } + + // for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so + // add them to our distance ordered array of children + for (int i = 0; i < currentCount; i++) { + VoxelNode* childNode = sortedChildren[i]; + int originalIndex = indexOfChildren[i]; + bool childIsInView = (childNode && (!params.viewFrustum || childNode->isInView(*params.viewFrustum))); if (childIsInView) { // Before we determine consider this further, let's see if it's in our LOD scope... - float distance = params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; + float distance = distancesToChildren[i]; // params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; float boundaryDistance = params.viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1; if (distance < boundaryDistance) { @@ -1166,16 +1229,62 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // we don't care about recursing deeper on them, and we don't consider their // subtree to exist if (!(childNode && childNode->isLeaf())) { - childrenExistInPacketBits += (1 << (7 - i)); + childrenExistInPacketBits += (1 << (7 - originalIndex)); inViewNotLeafCount++; } + bool childIsOccluded = false; // assume it's not occluded + + // If the user also asked for occlusion culling, check if this node is occluded + if (params.wantOcclusionCulling && childNode->isLeaf()) { +//printLog("params.wantOcclusionCulling... in childNode section...\n"); + // Don't check occlusion here, just add them to our distance ordered array... + + AABox voxelBox = childNode->getAABox(); + voxelBox.scale(TREE_SCALE); + VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(params.viewFrustum->getProjectedShadow(voxelBox)); + + // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion + // culling and proceed as normal + if (voxelShadow->getAllInView()) { +//childNode->printDebugDetails("voxelShadow->getAllInView() childNode="); + + CoverageMap::StorageResult result = params.map->checkMap(voxelShadow, true); + + // In all cases where the shadow wasn't stored, we need to free our own memory. + // In the case where it is stored, the CoverageMap will free memory for us later. + if (result != CoverageMap::STORED) { + delete voxelShadow; + } + + if (result == CoverageMap::STORED) { +//childNode->printDebugDetails("Leaf is stored!! childNode="); + } + + if (result == CoverageMap::DOESNT_FIT) { +//printLog(">>>> Leaf DOESNT_FIT!! That's not expected!!! \n"); + } + + + // If while attempting to add this voxel's shadow, we determined it was occluded, then + // we don't need to process it further and we can exit early. + if (result == CoverageMap::OCCLUDED) { +//childNode->printDebugDetails("Leaf is occluded!! childNode="); + childIsOccluded = true; + } + } else { +//childNode->printDebugDetails("Not all in view, cleanup... childNode="); + delete voxelShadow; + } + } // wants occlusion culling & isLeaf() + + bool childWasInView = (childNode && params.deltaViewFrustum && (params.lastViewFrustum && ViewFrustum::INSIDE == childNode->inFrustum(*params.lastViewFrustum))); // track children with actual color, only if the child wasn't previously in view! - if (childNode && childNode->isColored() && !childWasInView) { - childrenColoredBits += (1 << (7 - i)); + if (childNode && childNode->isColored() && !childWasInView && !childIsOccluded) { + childrenColoredBits += (1 << (7 - originalIndex)); inViewWithColorCount++; } } @@ -1235,15 +1344,35 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // // we know the last thing we wrote to the outputBuffer was our childrenExistInPacketBits. Let's remember where that was! unsigned char* childExistsPlaceHolder = outputBuffer-sizeof(childrenExistInPacketBits); - - for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { - if (oneAtBit(childrenExistInPacketBits, i)) { - VoxelNode* childNode = node->getChildAtIndex(i); - + // we are also going to recurse these child trees in "distance" sorted order, but we need to pack them in the + // final packet in standard order. So what we're going to do is keep track of how big each subtree was in bytes, + // and then later reshuffle these sections of our output buffer back into normal order. This allows us to make + // a single recursive pass in distance sorted order, but retain standard order in our encoded packet + int recursiveSliceSizes[NUMBER_OF_CHILDREN]; + unsigned char* recursiveSliceStarts[NUMBER_OF_CHILDREN]; + unsigned char* firstRecursiveSlice = outputBuffer; + int allSlicesSize = 0; + + // for each child node in Distance sorted order..., check to see if they exist, are colored, and in view, and if so + // add them to our distance ordered array of children + for (int indexByDistance = 0; indexByDistance < currentCount; indexByDistance++) { + VoxelNode* childNode = sortedChildren[indexByDistance]; + int originalIndex = indexOfChildren[indexByDistance]; + + if (oneAtBit(childrenExistInPacketBits, originalIndex)) { + int thisLevel = currentEncodeLevel; + + // remember this for reshuffling + recursiveSliceStarts[originalIndex] = outputBuffer; + int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, outputBuffer, availableBytes, bag, params, thisLevel); + + // remember this for reshuffling + recursiveSliceSizes[originalIndex] = childTreeBytesOut; + allSlicesSize += childTreeBytesOut; // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, // basically, the children below don't contain any info. @@ -1273,15 +1402,40 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // then we want to remove their bit from the childExistsPlaceHolder bitmask if (childTreeBytesOut == 0) { // remove this child's bit... - childrenExistInPacketBits -= (1 << (7 - i)); + childrenExistInPacketBits -= (1 << (7 - originalIndex)); // repair the child exists mask *childExistsPlaceHolder = childrenExistInPacketBits; // Note: no need to move the pointer, cause we already stored this } // end if (childTreeBytesOut == 0) - } // end if (oneAtBit(childrenExistInPacketBits, i)) + } // end if (oneAtBit(childrenExistInPacketBits, originalIndex)) } // end for - } // end keepDiggingDeeper + // reshuffle here... + if (params.wantOcclusionCulling) { + unsigned char tempReshuffleBuffer[MAX_VOXEL_PACKET_SIZE]; + + unsigned char* tempBufferTo = &tempReshuffleBuffer[0]; // this is our temporary destination + + // iterate through our childrenExistInPacketBits, these will be the sections of the packet that we copied subTree + // details into. Unfortunately, they're in distance sorted order, not original index order. we need to put them + // back into original distance order + for (int originalIndex = 0; originalIndex < NUMBER_OF_CHILDREN; originalIndex++) { + if (oneAtBit(childrenExistInPacketBits, originalIndex)) { + int thisSliceSize = recursiveSliceSizes[originalIndex]; + unsigned char* thisSliceStarts = recursiveSliceStarts[originalIndex]; + + memcpy(tempBufferTo, thisSliceStarts, thisSliceSize); + tempBufferTo += thisSliceSize; + } + } + + // now that all slices are back in the correct order, copy them to the correct output buffer + memcpy(firstRecursiveSlice, &tempReshuffleBuffer[0], allSlicesSize); + } + + + } // end keepDiggingDeeper + return bytesAtThisLevel; } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 650e662a3b..df721d0ba5 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -13,20 +13,25 @@ #include "ViewFrustum.h" #include "VoxelNode.h" #include "VoxelNodeBag.h" +#include "CoverageMap.h" // Callback function, for recuseTreeWithOperation typedef bool (*RecurseVoxelTreeOperation)(VoxelNode* node, void* extraData); typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; -#define NO_EXISTS_BITS false -#define WANT_EXISTS_BITS true -#define NO_COLOR false -#define WANT_COLOR true -#define IGNORE_VIEW_FRUSTUM NULL -#define JUST_STAGE_DELETION true -#define ACTUALLY_DELETE false -#define COLLAPSE_EMPTY_TREE true -#define DONT_COLLAPSE false +#define NO_EXISTS_BITS false +#define WANT_EXISTS_BITS true +#define NO_COLOR false +#define WANT_COLOR true +#define IGNORE_VIEW_FRUSTUM NULL +#define JUST_STAGE_DELETION true +#define ACTUALLY_DELETE false +#define COLLAPSE_EMPTY_TREE true +#define DONT_COLLAPSE false +#define NO_OCCLUSION_CULLING false +#define WANT_OCCLUSION_CULLING true +#define IGNORE_COVERAGE_MAP NULL +#define DONT_CHOP 0 class EncodeBitstreamParams { public: @@ -37,6 +42,8 @@ public: int chopLevels; bool deltaViewFrustum; const ViewFrustum* lastViewFrustum; + bool wantOcclusionCulling; + CoverageMap* map; EncodeBitstreamParams( int maxEncodeLevel = INT_MAX, @@ -45,7 +52,9 @@ public: bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, bool deltaViewFrustum = false, - const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM) : + const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM, + bool wantOcclusionCulling= NO_OCCLUSION_CULLING, + CoverageMap* map = IGNORE_COVERAGE_MAP) : maxEncodeLevel (maxEncodeLevel), viewFrustum (viewFrustum), @@ -53,7 +62,9 @@ public: includeExistsBits (includeExistsBits), chopLevels (chopLevels), deltaViewFrustum (deltaViewFrustum), - lastViewFrustum (lastViewFrustum) + lastViewFrustum (lastViewFrustum), + wantOcclusionCulling(wantOcclusionCulling), + map (map) {} }; diff --git a/voxel-server/src/VoxelAgentData.h b/voxel-server/src/VoxelAgentData.h index 2afc64a6c8..6606530b94 100644 --- a/voxel-server/src/VoxelAgentData.h +++ b/voxel-server/src/VoxelAgentData.h @@ -14,6 +14,7 @@ #include #include "VoxelNodeBag.h" #include "VoxelConstants.h" +#include "CoverageMap.h" class VoxelAgentData : public AvatarData { public: @@ -36,6 +37,7 @@ public: void setMaxLevelReached(int maxLevelReached) { _maxLevelReachedInLastSearch = maxLevelReached; } VoxelNodeBag nodeBag; + CoverageMap map; ViewFrustum& getCurrentViewFrustum() { return _currentViewFrustum; }; ViewFrustum& getLastKnownViewFrustum() { return _lastKnownViewFrustum; }; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 5853e3f245..f8b8c2f36e 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -312,9 +312,13 @@ void deepestLevelVoxelDistributor(AgentList* agentList, while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) { if (!agentData->nodeBag.isEmpty()) { VoxelNode* subTree = agentData->nodeBag.extract(); + + bool wantOcclusionCulling = agentData->getWantOcclusionCulling(); + CoverageMap* coverageMap = wantOcclusionCulling ? &agentData->map : IGNORE_COVERAGE_MAP; EncodeBitstreamParams params(INT_MAX, &agentData->getCurrentViewFrustum(), agentData->getWantColor(), - WANT_EXISTS_BITS, wantDelta, lastViewFrustum); + WANT_EXISTS_BITS, DONT_CHOP, wantDelta, lastViewFrustum, + wantOcclusionCulling, coverageMap); bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, agentData->nodeBag, params); @@ -375,6 +379,7 @@ void deepestLevelVoxelDistributor(AgentList* agentList, if (agentData->nodeBag.isEmpty()) { agentData->updateLastKnownViewFrustum(); agentData->setViewSent(true); + agentData->map.erase(); } From 8cef77bbda2c86dc18ea9be7b917331c2de5d053 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 09:53:30 -0700 Subject: [PATCH 28/67] remove the timing for twopole testing --- audio-mixer/src/main.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index b1494d3c61..e74191ea60 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -298,8 +298,6 @@ int main(int argc, const char* argv[]) { ? otherAgentBuffer->getBuffer() + RING_BUFFER_LENGTH_SAMPLES - numSamplesDelay : otherAgentBuffer->getNextOutput() - numSamplesDelay; - gettimeofday(&twoPoleStart, NULL); - for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { // load up the stkFrameBuffer with this source's samples stkFrameBuffer[s] = (stk::StkFloat) sourceBuffer[s]; @@ -310,10 +308,6 @@ int main(int argc, const char* argv[]) { otherAgentTwoPole->tick(stkFrameBuffer); } - gettimeofday(&twoPoleEnd, NULL); - - printf("Time taken for TP: %lld\n", usecTimestamp(&twoPoleEnd) - usecTimestamp(&twoPoleStart)); - for (int s = 0; s < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; s++) { if (s < numSamplesDelay) { // pull the earlier sample for the delayed channel From 2ba7fe0031d52ff544af93562fda948c9874beb2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 09:55:04 -0700 Subject: [PATCH 29/67] remove the unused timevals --- audio-mixer/src/main.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index e74191ea60..6606e97c9c 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -118,8 +118,6 @@ int main(int argc, const char* argv[]) { stk::StkFrames stkFrameBuffer(BUFFER_LENGTH_SAMPLES_PER_CHANNEL, 1); - timeval twoPoleStart, twoPoleEnd; - // if we'll be sending stats, call the Logstash::socket() method to make it load the logstash IP outside the loop if (Logstash::shouldSendStats()) { Logstash::socket(); From 8331fc1acb5524ea4bc92725c1900a105ac65f62 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 10:19:49 -0700 Subject: [PATCH 30/67] removed some old debug code --- interface/src/Application.cpp | 93 ----------------------------------- interface/src/Application.h | 6 --- 2 files changed, 99 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9a108f66c4..04c69bd043 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1345,7 +1345,6 @@ void Application::initMenu() { renderDebugMenu->addAction("FALSE Color Voxel Out of View", this, SLOT(doFalseColorizeInView())); renderDebugMenu->addAction("FALSE Color Occluded Voxels", this, SLOT(doFalseColorizeOccluded()), Qt::CTRL | Qt::Key_O); renderDebugMenu->addAction("Show TRUE Colors", this, SLOT(doTrueVoxelColors()), Qt::CTRL | Qt::Key_T); - (_debugShowVirtualOccluders = renderDebugMenu->addAction("Show Virtual Occluders"))->setCheckable(true); debugMenu->addAction("Wants Res-In", this, SLOT(setWantsResIn(bool)))->setCheckable(true); debugMenu->addAction("Wants Monochrome", this, SLOT(setWantsMonochrome(bool)))->setCheckable(true); @@ -1928,94 +1927,6 @@ void Application::displayOculus(Camera& whichCamera) { glPopMatrix(); } -glm::vec2 Application::getScaledScreenPoint(glm::vec2 projectedPoint) { - float horizontalScale = _glWidget->width() / 2.0f; - float verticalScale = _glWidget->height() / 2.0f; - - // -1,-1 is 0,windowHeight - // 1,1 is windowWidth,0 - - // -1,1 1,1 - // +-----------------------+ - // | | | - // | | | - // | -1,0 | | - // |-----------+-----------| - // | 0,0 | - // | | | - // | | | - // | | | - // +-----------------------+ - // -1,-1 1,-1 - - glm::vec2 screenPoint((projectedPoint.x + 1.0) * horizontalScale, - ((projectedPoint.y + 1.0) * -verticalScale) + _glWidget->height()); - - return screenPoint; -} - -void Application::renderVirtualOccluders() { - - if (_debugShowVirtualOccluders->isChecked()) { - CoverageMap map(BoundingBox(glm::vec2(-1.f,-1.f), glm::vec2(2.f,2.f))); // screen coverage - - - glLineWidth(2.0); - glBegin(GL_LINES); - glColor3f(0,0,1); - - AABox boxA(glm::vec3(0,0,0), 0.0125); - boxA.scale(TREE_SCALE); - VoxelProjectedShadow shadowA = _viewFrustum.getProjectedShadow(boxA); - - - AABox boxB(glm::vec3(0.0125,0,0.025), 0.0125); - boxB.scale(TREE_SCALE); - VoxelProjectedShadow shadowB = _viewFrustum.getProjectedShadow(boxB); - - bool shadowAoccludesB = shadowA.occludes(shadowB); - bool shadowBoccludesA = shadowB.occludes(shadowA); - - if (shadowA.getVertexCount()) { - if (shadowBoccludesA) { - glColor3f(1,0,0); - } else { - glColor3f(0,0,1); - } - glm::vec2 firstPoint = getScaledScreenPoint(shadowA.getVertex(0)); - glm::vec2 lastPoint(firstPoint); - for (int i = 1; i < shadowA.getVertexCount(); i++) { - glm::vec2 thisPoint = getScaledScreenPoint(shadowA.getVertex(i)); - glVertex2f(lastPoint.x, lastPoint.y); - glVertex2f(thisPoint.x, thisPoint.y); - lastPoint = thisPoint; - } - glVertex2f(lastPoint.x, lastPoint.y); - glVertex2f(firstPoint.x, firstPoint.y); - } - - if (shadowB.getVertexCount()) { - if (shadowAoccludesB) { - glColor3f(0,1,0); - } else { - glColor3f(1,0,0); - } - glm::vec2 firstPoint = getScaledScreenPoint(shadowB.getVertex(0)); - glm::vec2 lastPoint(firstPoint); - for (int i = 1; i < shadowB.getVertexCount(); i++) { - glm::vec2 thisPoint = getScaledScreenPoint(shadowB.getVertex(i)); - glVertex2f(lastPoint.x, lastPoint.y); - glVertex2f(thisPoint.x, thisPoint.y); - lastPoint = thisPoint; - } - glVertex2f(lastPoint.x, lastPoint.y); - glVertex2f(firstPoint.x, firstPoint.y); - } - - glEnd(); - } -} - void Application::displaySide(Camera& whichCamera) { // transform by eye offset @@ -2304,10 +2215,6 @@ void Application::displayStats() { } delete []perfStatLinesArray; // we're responsible for cleanup } - - // testing.... - renderVirtualOccluders(); - } void Application::renderThrustAtVoxel(const glm::vec3& thrust) { diff --git a/interface/src/Application.h b/interface/src/Application.h index c910787463..c84cc025a6 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -146,11 +146,6 @@ private: void displaySide(Camera& whichCamera); void displayOverlay(); void displayStats(); - - // Couple of debug routines for use in debuggin/developing Occlusion Culling. Will be removed eventually - void renderVirtualOccluders(); - glm::vec2 getScaledScreenPoint(glm::vec2 projectedPoint); - void renderViewFrustum(ViewFrustum& viewFrustum); void setupPaintingVoxel(); @@ -212,7 +207,6 @@ private: QAction* _fullScreenMode; // whether we are in full screen mode QAction* _frustumRenderModeAction; QAction* _settingsAutosave; // Whether settings are saved automatically - QAction* _debugShowVirtualOccluders; SerialInterface _serialHeadSensor; QNetworkAccessManager* _networkAccessManager; From 46d7ada7531a32b3f86663ce8a32914e4e80dc58 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 10:21:47 -0700 Subject: [PATCH 31/67] code cleanup --- interface/src/Application.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 04c69bd043..a7d5b63d98 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -60,8 +60,6 @@ #include "renderer/ProgramObject.h" #include "ui/TextRenderer.h" -#include - using namespace std; // Starfield information @@ -2063,7 +2061,6 @@ void Application::displaySide(Camera& whichCamera) { // brad's frustum for debugging if (_frustumOn->isChecked()) renderViewFrustum(_viewFrustum); - } void Application::displayOverlay() { From a6b4bdba53760f1eeea173b6dac6ac0ae01dde03 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 10:25:58 -0700 Subject: [PATCH 32/67] code cleanup --- libraries/voxels/src/CoverageMap.cpp | 25 +------------------------ 1 file changed, 1 insertion(+), 24 deletions(-) diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp index f83076ee13..183438462e 100644 --- a/libraries/voxels/src/CoverageMap.cpp +++ b/libraries/voxels/src/CoverageMap.cpp @@ -141,30 +141,7 @@ void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { } -// possible results = STORED, OCCLUDED, DOESNT_FIT -// storeInMap(poly) -// if (poly->BB inside myBB) -// -- at this point, we can check polygons at this level -// -- to see if they occlude the polygon being inserted -// -- since the polygons at this level are big relative to -// -- lower levels, there's a higher chance for them to occlude -// -- Note: list should be "depth" sorted -// for each polygon at this level -// if (levelpolygon.occludes(poly)) -// return OCCLUDED -// end -// for each child -// childResult = child->storeInMap(poly) -// if (childResult == STORED || childResult == OCCLUDED) -// return childResult -// end -// end -// -- if we got here, then the polygon didn't fit in any of the children and -// -- wasn't already occluded, so store it here -// insert into local list (poly, poly.depth) -// return STORED -// end -// return DOESNT_FIT +// possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT CoverageMap::StorageResult CoverageMap::checkMap(VoxelProjectedShadow* polygon, bool storeIt) { if (_isRoot || _myBoundingBox.contains(polygon->getBoundingBox())) { // check to make sure this polygon isn't occluded by something at this level From 00438f9d9939e9b92c3d9857cd72c5cc430c7959 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 10:28:14 -0700 Subject: [PATCH 33/67] code cleanup --- libraries/voxels/src/CoverageMap.h | 31 --------------------------- libraries/voxels/src/GeometryUtil.cpp | 2 -- 2 files changed, 33 deletions(-) diff --git a/libraries/voxels/src/CoverageMap.h b/libraries/voxels/src/CoverageMap.h index dc46695dba..536b3a6adc 100644 --- a/libraries/voxels/src/CoverageMap.h +++ b/libraries/voxels/src/CoverageMap.h @@ -11,37 +11,6 @@ #include #include "VoxelProjectedShadow.h" - -// -// depth of polygon is distance from camera to closest point on 3d voxel -// this works because voxels are axis aligned and therefore other voxels -// can only be as close as that if they are on the same axis -// -// scanning octree in "closest" order... -// for each node -// polygon = getShadow(node) -// isOccluded = coverageMap->isOccluded(polygon) -// if (!isOccluded) -// coverageMap->add(polygon) -// sendList->add(node) -// else -// don't need to send or remember -// end each - -// adding to coverage map.... -// -// at each level of quadtree -// store a list of polygons whose bounding box fit in the bb of the quad but not a smaller quad -// also store 4 smaller quad trees -// -// is it true, that only polygons from higher in the quad tree can occlude a polygon? -// YES - I believe so, because polygon that occluded all the points of the potential occludee -// would have a bounding box that couldn't fit in a lower level of the quad tree -// -// - - - class CoverageMap { public: diff --git a/libraries/voxels/src/GeometryUtil.cpp b/libraries/voxels/src/GeometryUtil.cpp index f311bf2993..1fc4e57013 100644 --- a/libraries/voxels/src/GeometryUtil.cpp +++ b/libraries/voxels/src/GeometryUtil.cpp @@ -130,8 +130,6 @@ bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm (d4 == 0 && isOnSegment(r1p1.x, r1p1.y, r1p2.x, r1p2.y, r2p2.x, r2p2.y)); } - -// I want these to be inlined for performance bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk) { return (xi <= xk || xj <= xk) && (xk <= xi || xk <= xj) && (yi <= yk || yj <= yk) && (yk <= yi || yk <= yj); From 9a22db28a34cc2e0ecf2f701312712eb811bec5f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 10:35:32 -0700 Subject: [PATCH 34/67] code cleanup --- libraries/voxels/src/VoxelTree.cpp | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 6e90b06b9c..5077a4274c 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1237,7 +1237,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // If the user also asked for occlusion culling, check if this node is occluded if (params.wantOcclusionCulling && childNode->isLeaf()) { -//printLog("params.wantOcclusionCulling... in childNode section...\n"); // Don't check occlusion here, just add them to our distance ordered array... AABox voxelBox = childNode->getAABox(); @@ -1247,8 +1246,6 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion // culling and proceed as normal if (voxelShadow->getAllInView()) { -//childNode->printDebugDetails("voxelShadow->getAllInView() childNode="); - CoverageMap::StorageResult result = params.map->checkMap(voxelShadow, true); // In all cases where the shadow wasn't stored, we need to free our own memory. @@ -1257,23 +1254,12 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp delete voxelShadow; } - if (result == CoverageMap::STORED) { -//childNode->printDebugDetails("Leaf is stored!! childNode="); - } - - if (result == CoverageMap::DOESNT_FIT) { -//printLog(">>>> Leaf DOESNT_FIT!! That's not expected!!! \n"); - } - - // If while attempting to add this voxel's shadow, we determined it was occluded, then // we don't need to process it further and we can exit early. if (result == CoverageMap::OCCLUDED) { -//childNode->printDebugDetails("Leaf is occluded!! childNode="); childIsOccluded = true; } } else { -//childNode->printDebugDetails("Not all in view, cleanup... childNode="); delete voxelShadow; } } // wants occlusion culling & isLeaf() From 5918c492cc923956e2091a29199b232646a2b3c2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 10:46:45 -0700 Subject: [PATCH 35/67] correct stat collection for mixer frame time usage --- audio-mixer/src/main.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 6606e97c9c..2ad86f6970 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -412,6 +412,9 @@ int main(int argc, const char* argv[]) { if (percentageOfMaxElapsed > 0) { sumFrameTimePercentages += percentageOfMaxElapsed; + } else { + // a negative value suggests that we've taken 100% of the allowable time + sumFrameTimePercentages += 100; } numStatCollections++; From b51d3e88d3acfbabf3b8f9a9aebe18366a2b55d4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 10:49:15 -0700 Subject: [PATCH 36/67] impossible for percentageOfMaxElapsed to be zero --- audio-mixer/src/main.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 2ad86f6970..c19aba0a9c 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -410,12 +410,7 @@ int main(int argc, const char* argv[]) { float percentageOfMaxElapsed = ((float) (usecTimestamp(&endSendTime) - usecTimestamp(&beginSendTime)) / BUFFER_SEND_INTERVAL_USECS) * 100.0f; - if (percentageOfMaxElapsed > 0) { - sumFrameTimePercentages += percentageOfMaxElapsed; - } else { - // a negative value suggests that we've taken 100% of the allowable time - sumFrameTimePercentages += 100; - } + sumFrameTimePercentages += percentageOfMaxElapsed; numStatCollections++; } From 8b18ee6844cc10a315d9089a453037ae3967a2e9 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 12:01:01 -0700 Subject: [PATCH 37/67] renamed VoxelProjectedShadow class --- interface/src/VoxelSystem.cpp | 4 ++-- libraries/voxels/src/CoverageMap.cpp | 10 +++++----- libraries/voxels/src/CoverageMap.h | 10 +++++----- libraries/voxels/src/ViewFrustum.cpp | 4 ++-- libraries/voxels/src/ViewFrustum.h | 4 ++-- ...ojectedShadow.cpp => VoxelProjectedPolygon.cpp} | 14 +++++++------- ...elProjectedShadow.h => VoxelProjectedPolygon.h} | 10 +++++----- libraries/voxels/src/VoxelTree.cpp | 4 ++-- 8 files changed, 30 insertions(+), 30 deletions(-) rename libraries/voxels/src/{VoxelProjectedShadow.cpp => VoxelProjectedPolygon.cpp} (88%) rename libraries/voxels/src/{VoxelProjectedShadow.h => VoxelProjectedPolygon.h} (88%) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 95e6b382b9..12d466961d 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1202,7 +1202,7 @@ bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraDat AABox voxelBox = node->getAABox(); voxelBox.scale(TREE_SCALE); - VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(args->viewFrustum->getProjectedShadow(voxelBox)); + VoxelProjectedPolygon* voxelShadow = new VoxelProjectedPolygon(args->viewFrustum->getProjectedShadow(voxelBox)); // If we're not all in view, then ignore it, and just return. But keep searching... if (!voxelShadow->getAllInView()) { @@ -1239,7 +1239,7 @@ bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraDat AABox voxelBox = node->getAABox(); voxelBox.scale(TREE_SCALE); - VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(args->viewFrustum->getProjectedShadow(voxelBox)); + VoxelProjectedPolygon* voxelShadow = new VoxelProjectedPolygon(args->viewFrustum->getProjectedShadow(voxelBox)); // If we're not all in view, then ignore it, and just return. But keep searching... if (!voxelShadow->getAllInView()) { diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp index 183438462e..e9a1fb6231 100644 --- a/libraries/voxels/src/CoverageMap.cpp +++ b/libraries/voxels/src/CoverageMap.cpp @@ -96,12 +96,12 @@ BoundingBox CoverageMap::getChildBoundingBox(int childIndex) { void CoverageMap::growPolygonArray() { - VoxelProjectedShadow** newPolygons = new VoxelProjectedShadow*[_polygonArraySize + DEFAULT_GROW_SIZE]; + VoxelProjectedPolygon** newPolygons = new VoxelProjectedPolygon*[_polygonArraySize + DEFAULT_GROW_SIZE]; float* newDistances = new float[_polygonArraySize + DEFAULT_GROW_SIZE]; if (_polygons) { - memcpy(newPolygons, _polygons, sizeof(VoxelProjectedShadow*) * _polygonCount); + memcpy(newPolygons, _polygons, sizeof(VoxelProjectedPolygon*) * _polygonCount); delete[] _polygons; memcpy(newDistances, _polygonDistances, sizeof(float) * _polygonCount); delete[] _polygonDistances; @@ -117,7 +117,7 @@ int CoverageMap::_totalPolygons = 0; // just handles storage in the array, doesn't test for occlusion or // determining if this is the correct map to store in! -void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { +void CoverageMap::storeInArray(VoxelProjectedPolygon* polygon) { _totalPolygons++; @@ -142,11 +142,11 @@ void CoverageMap::storeInArray(VoxelProjectedShadow* polygon) { // possible results = STORED/NOT_STORED, OCCLUDED, DOESNT_FIT -CoverageMap::StorageResult CoverageMap::checkMap(VoxelProjectedShadow* polygon, bool storeIt) { +CoverageMap::StorageResult CoverageMap::checkMap(VoxelProjectedPolygon* polygon, bool storeIt) { if (_isRoot || _myBoundingBox.contains(polygon->getBoundingBox())) { // check to make sure this polygon isn't occluded by something at this level for (int i = 0; i < _polygonCount; i++) { - VoxelProjectedShadow* polygonAtThisLevel = _polygons[i]; + VoxelProjectedPolygon* polygonAtThisLevel = _polygons[i]; // Check to make sure that the polygon in question is "behind" the polygon in the list // otherwise, we don't need to test it's occlusion (although, it means we've potentially // added an item previously that may be occluded??? Is that possible? Maybe not, because two diff --git a/libraries/voxels/src/CoverageMap.h b/libraries/voxels/src/CoverageMap.h index 536b3a6adc..38c7dc6145 100644 --- a/libraries/voxels/src/CoverageMap.h +++ b/libraries/voxels/src/CoverageMap.h @@ -1,5 +1,5 @@ // -// CoverageMap.h - 2D CoverageMap Quad tree for storage of VoxelProjectedShadows +// CoverageMap.h - 2D CoverageMap Quad tree for storage of VoxelProjectedPolygons // hifi // // Added by Brad Hefta-Gaub on 06/11/13. @@ -9,7 +9,7 @@ #define _COVERAGE_MAP_ #include -#include "VoxelProjectedShadow.h" +#include "VoxelProjectedPolygon.h" class CoverageMap { @@ -23,7 +23,7 @@ public: ~CoverageMap(); typedef enum {STORED, OCCLUDED, DOESNT_FIT, NOT_STORED} StorageResult; - StorageResult checkMap(VoxelProjectedShadow* polygon, bool storeIt = true); + StorageResult checkMap(VoxelProjectedPolygon* polygon, bool storeIt = true); BoundingBox getChildBoundingBox(int childIndex); @@ -32,14 +32,14 @@ public: private: void init(); void growPolygonArray(); - void storeInArray(VoxelProjectedShadow* polygon); + void storeInArray(VoxelProjectedPolygon* polygon); bool _isRoot; // is this map the root, if so, it never returns DOESNT_FIT BoundingBox _myBoundingBox; bool _managePolygons; // will the coverage map delete the polygons on destruct int _polygonCount; // how many polygons at this level int _polygonArraySize; // how much room is there to store polygons at this level - VoxelProjectedShadow** _polygons; + VoxelProjectedPolygon** _polygons; float* _polygonDistances; CoverageMap* _childMaps[NUMBER_OF_CHILDREN]; diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 0a492d2d6e..786e5a1af0 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -503,7 +503,7 @@ const int hullVertexLookup[MAX_POSSIBLE_COMBINATIONS][MAX_SHADOW_VERTEX_COUNT+1] {6, TOP_RIGHT_NEAR, TOP_RIGHT_FAR, BOTTOM_RIGHT_FAR, BOTTOM_LEFT_FAR, BOTTOM_LEFT_NEAR, TOP_LEFT_NEAR}, // back, top, left }; -VoxelProjectedShadow ViewFrustum::getProjectedShadow(const AABox& box) const { +VoxelProjectedPolygon ViewFrustum::getProjectedShadow(const AABox& box) const { glm::vec3 bottomNearRight = box.getCorner(); glm::vec3 topFarLeft = box.getCorner() + box.getSize(); int lookUp = ((_position.x < bottomNearRight.x) ) // 1 = right | compute 6-bit @@ -515,7 +515,7 @@ VoxelProjectedShadow ViewFrustum::getProjectedShadow(const AABox& box) const { int vertexCount = hullVertexLookup[lookUp][0]; //look up number of vertices - VoxelProjectedShadow shadow(vertexCount); + VoxelProjectedPolygon shadow(vertexCount); bool pointInView = true; bool allPointsInView = false; // assume the best, but wait till we know we have a vertex diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index bf30aa4818..f2b329ee30 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -15,7 +15,7 @@ #include #include "Plane.h" #include "AABox.h" -#include "VoxelProjectedShadow.h" +#include "VoxelProjectedPolygon.h" const float DEFAULT_KEYHOLE_RADIUS = 2.0f; @@ -89,7 +89,7 @@ public: void printDebugDetails() const; glm::vec2 projectPoint(glm::vec3 point, bool& pointInView) const; - VoxelProjectedShadow getProjectedShadow(const AABox& box) const; + VoxelProjectedPolygon getProjectedShadow(const AABox& box) const; private: diff --git a/libraries/voxels/src/VoxelProjectedShadow.cpp b/libraries/voxels/src/VoxelProjectedPolygon.cpp similarity index 88% rename from libraries/voxels/src/VoxelProjectedShadow.cpp rename to libraries/voxels/src/VoxelProjectedPolygon.cpp index 19e0fe5e7d..cee5399240 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.cpp +++ b/libraries/voxels/src/VoxelProjectedPolygon.cpp @@ -1,11 +1,11 @@ // -// VoxelProjectedShadow.cpp - The projected shadow (on the 2D view plane) for a voxel +// VoxelProjectedPolygon.cpp - The projected shadow (on the 2D view plane) for a voxel // hifi // // Added by Brad Hefta-Gaub on 06/11/13. // -#include "VoxelProjectedShadow.h" +#include "VoxelProjectedPolygon.h" #include "GeometryUtil.h" #include "Log.h" @@ -29,7 +29,7 @@ void BoundingBox::printDebugDetails(const char* label) const { } -void VoxelProjectedShadow::setVertex(int vertex, const glm::vec2& point) { +void VoxelProjectedPolygon::setVertex(int vertex, const glm::vec2& point) { _vertices[vertex] = point; // keep track of our bounding box @@ -48,7 +48,7 @@ void VoxelProjectedShadow::setVertex(int vertex, const glm::vec2& point) { }; -bool VoxelProjectedShadow::occludes(const VoxelProjectedShadow& occludee) const { +bool VoxelProjectedPolygon::occludes(const VoxelProjectedPolygon& occludee) const { // if we are completely out of view, then we definitely don't occlude! // if the occludee is completely out of view, then we also don't occlude it @@ -80,7 +80,7 @@ bool VoxelProjectedShadow::occludes(const VoxelProjectedShadow& occludee) const return true; } -bool VoxelProjectedShadow::pointInside(const glm::vec2& point) const { +bool VoxelProjectedPolygon::pointInside(const glm::vec2& point) const { // first check the bounding boxes, the point mush be fully within the boounding box of this shadow if ((point.x > getMaxX()) || (point.y > getMaxY()) || @@ -113,8 +113,8 @@ bool VoxelProjectedShadow::pointInside(const glm::vec2& point) const { return ((intersections & 1) == 1); } -void VoxelProjectedShadow::printDebugDetails() const { - printf("VoxelProjectedShadow..."); +void VoxelProjectedPolygon::printDebugDetails() const { + printf("VoxelProjectedPolygon..."); printf(" minX=%f maxX=%f minY=%f maxY=%f\n", getMinX(), getMaxX(), getMinY(), getMaxY()); printf(" vertex count=%d distance=%f\n", getVertexCount(), getDistance()); for (int i = 0; i < getVertexCount(); i++) { diff --git a/libraries/voxels/src/VoxelProjectedShadow.h b/libraries/voxels/src/VoxelProjectedPolygon.h similarity index 88% rename from libraries/voxels/src/VoxelProjectedShadow.h rename to libraries/voxels/src/VoxelProjectedPolygon.h index 30bf80b630..c6e4b665fa 100644 --- a/libraries/voxels/src/VoxelProjectedShadow.h +++ b/libraries/voxels/src/VoxelProjectedPolygon.h @@ -1,5 +1,5 @@ // -// VoxelProjectedShadow.h - The projected shadow (on the 2D view plane) for a voxel +// VoxelProjectedPolygon.h - The projected shadow (on the 2D view plane) for a voxel // hifi // // Added by Brad Hefta-Gaub on 06/11/13. @@ -24,16 +24,16 @@ public: void printDebugDetails(const char* label=NULL) const; }; -class VoxelProjectedShadow { +class VoxelProjectedPolygon { public: - VoxelProjectedShadow(int vertexCount = 0) : + VoxelProjectedPolygon(int vertexCount = 0) : _vertexCount(vertexCount), _maxX(-FLT_MAX), _maxY(-FLT_MAX), _minX(FLT_MAX), _minY(FLT_MAX), _distance(0) { }; - ~VoxelProjectedShadow() { }; + ~VoxelProjectedPolygon() { }; const ShadowVertices& getVerices() const { return _vertices; }; const glm::vec2& getVertex(int i) const { return _vertices[i]; }; void setVertex(int vertex, const glm::vec2& point); @@ -48,7 +48,7 @@ public: bool getAllInView() const { return _allInView; }; void setAllInView(bool allInView) { _allInView = allInView; }; - bool occludes(const VoxelProjectedShadow& occludee) const; + bool occludes(const VoxelProjectedPolygon& occludee) const; bool pointInside(const glm::vec2& point) const; float getMaxX() const { return _maxX; } diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 5077a4274c..4329b94177 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1125,7 +1125,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp //node->printDebugDetails("upper section, params.wantOcclusionCulling... node="); AABox voxelBox = node->getAABox(); voxelBox.scale(TREE_SCALE); - VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(params.viewFrustum->getProjectedShadow(voxelBox)); + VoxelProjectedPolygon* voxelShadow = new VoxelProjectedPolygon(params.viewFrustum->getProjectedShadow(voxelBox)); // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion // culling and proceed as normal @@ -1241,7 +1241,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outp AABox voxelBox = childNode->getAABox(); voxelBox.scale(TREE_SCALE); - VoxelProjectedShadow* voxelShadow = new VoxelProjectedShadow(params.viewFrustum->getProjectedShadow(voxelBox)); + VoxelProjectedPolygon* voxelShadow = new VoxelProjectedPolygon(params.viewFrustum->getProjectedShadow(voxelBox)); // In order to check occlusion culling, the shadow has to be "all in view" otherwise, we will ignore occlusion // culling and proceed as normal From 7922c3b625c2cf1c9c8cf8a4035ac79731ce12f5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 12:02:17 -0700 Subject: [PATCH 38/67] fixed typo --- libraries/voxels/src/VoxelProjectedPolygon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/voxels/src/VoxelProjectedPolygon.cpp b/libraries/voxels/src/VoxelProjectedPolygon.cpp index cee5399240..baef436d08 100644 --- a/libraries/voxels/src/VoxelProjectedPolygon.cpp +++ b/libraries/voxels/src/VoxelProjectedPolygon.cpp @@ -60,7 +60,7 @@ bool VoxelProjectedPolygon::occludes(const VoxelProjectedPolygon& occludee) cons return false; } - // first check the bounding boxes, the occludee mush be fully within the boounding box of this shadow + // first check the bounding boxes, the occludee must be fully within the boounding box of this shadow if ((occludee.getMaxX() > getMaxX()) || (occludee.getMaxY() > getMaxY()) || (occludee.getMinX() < getMinX()) || @@ -81,7 +81,7 @@ bool VoxelProjectedPolygon::occludes(const VoxelProjectedPolygon& occludee) cons } bool VoxelProjectedPolygon::pointInside(const glm::vec2& point) const { - // first check the bounding boxes, the point mush be fully within the boounding box of this shadow + // first check the bounding boxes, the point must be fully within the boounding box of this shadow if ((point.x > getMaxX()) || (point.y > getMaxY()) || (point.x < getMinX()) || From 1fc3ad80112be854815ca05fde77e701c46e1b81 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 12:03:58 -0700 Subject: [PATCH 39/67] CR feedback --- interface/src/VoxelSystem.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 12d466961d..4a81d3ec2d 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1263,7 +1263,7 @@ bool VoxelSystem::falseColorizeOccludedOperation(VoxelNode* node, void* extraDat } void VoxelSystem::falseColorizeOccluded() { PerformanceWarning warn(true, "falseColorizeOccluded()",true); - CoverageMap map(BoundingBox(glm::vec2(-2.f,-2.f), glm::vec2(4.f,4.f)), true); + CoverageMap map; FalseColorizeOccludedArgs args; args.viewFrustum = Application::getInstance()->getViewFrustum(); args.map = ↦ From 8c44ad19a1c697f5b5f14c7309137b1c452b2746 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 12:10:59 -0700 Subject: [PATCH 40/67] fixed build buster --- libraries/voxels/src/CoverageMap.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/CoverageMap.cpp b/libraries/voxels/src/CoverageMap.cpp index e9a1fb6231..76a04b2468 100644 --- a/libraries/voxels/src/CoverageMap.cpp +++ b/libraries/voxels/src/CoverageMap.cpp @@ -7,7 +7,7 @@ #include "CoverageMap.h" #include -#include +#include #include "Log.h" int CoverageMap::_mapCount = 0; From 9466e815903d586a56b630f0d11aef10cb304a82 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 12:25:16 -0700 Subject: [PATCH 41/67] fixed crash --- libraries/voxels/src/VoxelTree.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 4329b94177..ec9ae008e6 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1057,7 +1057,7 @@ int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, *outputBuffer = 0; // root } } else { - codeLength = bytesRequiredForCodeLength(*node->getOctalCode()); + codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(node->getOctalCode())); memcpy(outputBuffer, node->getOctalCode(), codeLength); } From 38d894db379efacf61896ed90ae3fe96ccfd775d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 12:32:04 -0700 Subject: [PATCH 42/67] remove random sleep mode, simplify injector while --- injector/src/main.cpp | 158 +++++++++++++++--------------------------- 1 file changed, 56 insertions(+), 102 deletions(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index a0c07179f7..169c04d104 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -35,7 +35,8 @@ enum { }; // Command line parameter defaults -bool loopAudio = true; +bool shouldLoopAudio = true; +bool hasInjectedAudioOnce = false; float sleepIntervalMin = 1.00; float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; @@ -47,9 +48,7 @@ float radius = 0.0f; void usage(void) { std::cout << "High Fidelity - Interface audio injector" << std::endl; - std::cout << " -s Random sleep mode. If not specified will default to constant loop." << std::endl; - std::cout << " -b FLOAT Min. number of seconds to sleep. Only valid in random sleep mode. Default 1.0" << std::endl; - std::cout << " -t FLOAT Max. number of seconds to sleep. Only valid in random sleep mode. Default 2.0" << std::endl; + std::cout << " -s Single play mode. If not specified will default to constant loop." << std::endl; std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl; std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl; std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl; @@ -62,16 +61,8 @@ bool processParameters(int parameterCount, char* parameterData[]) { while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) { switch (p) { case 's': - ::loopAudio = false; - std::cout << "[DEBUG] Random sleep mode enabled" << std::endl; - break; - case 'b': - ::sleepIntervalMin = atof(optarg); - std::cout << "[DEBUG] Min delay between plays " << sleepIntervalMin << "sec" << std::endl; - break; - case 't': - ::sleepIntervalMax = atof(optarg); - std::cout << "[DEBUG] Max delay between plays " << sleepIntervalMax << "sec" << std::endl; + ::shouldLoopAudio = false; + std::cout << "[DEBUG] Single play mode enabled" << std::endl; break; case 'f': ::sourceAudioFile = optarg; @@ -113,35 +104,6 @@ bool processParameters(int parameterCount, char* parameterData[]) { return true; }; -bool stopReceiveAgentDataThread; - -void *receiveAgentData(void *args) { - sockaddr senderAddress; - ssize_t bytesReceived; - unsigned char incomingPacket[MAX_PACKET_SIZE]; - - AgentList* agentList = AgentList::getInstance(); - - while (!::stopReceiveAgentDataThread) { - if (agentList->getAgentSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) { - switch (incomingPacket[0]) { - case PACKET_HEADER_BULK_AVATAR_DATA: - // this is the positional data for other agents - // pass that off to the agentList processBulkAgentData method - agentList->processBulkAgentData(&senderAddress, incomingPacket, bytesReceived); - break; - default: - // have the agentList handle list of agents from DS, replies from other agents, etc. - agentList->processAgentData(&senderAddress, incomingPacket, bytesReceived); - break; - } - } - } - - pthread_exit(0); - return NULL; -} - void createAvatarDataForAgent(Agent* agent) { if (!agent->getLinkedData()) { agent->setLinkedData(new AvatarData(agent)); @@ -164,9 +126,6 @@ int main(int argc, char* argv[]) { // create an AgentList instance to handle communication with other agents AgentList* agentList = AgentList::createInstance(AGENT_TYPE_AUDIO_INJECTOR, AUDIO_UDP_SEND_PORT); - pthread_t receiveAgentDataThread; - pthread_create(&receiveAgentDataThread, NULL, receiveAgentData, NULL); - // start the agent list thread that will kill off agents when they stop talking agentList->startSilentAgentRemovalThread(); @@ -183,42 +142,47 @@ int main(int argc, char* argv[]) { // register the callback for agent data creation agentList->linkedDataCreateCallback = createAvatarDataForAgent; - - unsigned char broadcastPacket = PACKET_HEADER_INJECT_AUDIO; - - timeval thisSend; - long long numMicrosecondsSleep = 0; + + timeval lastSend = {}; + unsigned char broadcastPacket = PACKET_HEADER_INJECT_AUDIO; timeval lastDomainServerCheckIn = {}; - // the audio injector needs to know about the avatar mixer and the audio mixer - const char INJECTOR_AGENTS_OF_INTEREST[] = {AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_AUDIO_MIXER}; - AgentList::getInstance()->setAgentTypesOfInterest(INJECTOR_AGENTS_OF_INTEREST, sizeof(INJECTOR_AGENTS_OF_INTEREST)); + sockaddr senderAddress; + ssize_t bytesReceived; + unsigned char incomingPacket[MAX_PACKET_SIZE]; - while (true) { - + // the audio injector needs to know about the avatar mixer and the audio mixer + const char INJECTOR_AGENTS_OF_INTEREST[] = {AGENT_TYPE_AUDIO_MIXER, AGENT_TYPE_AVATAR_MIXER}; + + int bytesAgentsOfInterest = (::triggerDistance > 0) + ? sizeof(INJECTOR_AGENTS_OF_INTEREST) + : sizeof(INJECTOR_AGENTS_OF_INTEREST) - 1; + + AgentList::getInstance()->setAgentTypesOfInterest(INJECTOR_AGENTS_OF_INTEREST, bytesAgentsOfInterest); + + while (true) { // send a check in packet to the domain server if DOMAIN_SERVER_CHECK_IN_USECS has elapsed if (usecTimestampNow() - usecTimestamp(&lastDomainServerCheckIn) >= DOMAIN_SERVER_CHECK_IN_USECS) { gettimeofday(&lastDomainServerCheckIn, NULL); AgentList::getInstance()->sendDomainServerCheckIn(); } - if (::triggerDistance) { - - // update the thisSend timeval to the current time - gettimeofday(&thisSend, NULL); - - // find the current avatar mixer - Agent* avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); - - // make sure we actually have an avatar mixer with an active socket - if (avatarMixer && avatarMixer->getActiveSocket() != NULL) { - // use the UDPSocket instance attached to our agent list to ask avatar mixer for a list of avatars - agentList->getAgentSocket()->send(avatarMixer->getActiveSocket(), - &broadcastPacket, - sizeof(broadcastPacket)); + while (agentList->getAgentSocket()->receive(&senderAddress, incomingPacket, &bytesReceived)) { + switch (incomingPacket[0]) { + case PACKET_HEADER_BULK_AVATAR_DATA: + // this is the positional data for other agents + // pass that off to the agentList processBulkAgentData method + agentList->processBulkAgentData(&senderAddress, incomingPacket, bytesReceived); + break; + default: + // have the agentList handle list of agents from DS, replies from other agents, etc. + agentList->processAgentData(&senderAddress, incomingPacket, bytesReceived); + break; } - + } + + if (::triggerDistance) { if (!injector.isInjectingAudio()) { // enumerate the other agents to decide if one is close enough that we should inject for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { @@ -226,49 +190,39 @@ int main(int argc, char* argv[]) { if (avatarData) { glm::vec3 tempVector = injector.getPosition() - avatarData->getPosition(); - float squareDistance = glm::dot(tempVector, tempVector); - if (squareDistance <= ::triggerDistance) { - // look for an audio mixer in our agent list - Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); - - if (audioMixer) { - // we have an active audio mixer we can send data to - AudioInjectionManager::threadInjector(&injector); - } + if (glm::dot(tempVector, tempVector) <= ::triggerDistance) { + // use the AudioInjectionManager to thread this injector + AudioInjectionManager::threadInjector(&injector); } } } } - // sleep for the correct amount of time to have data send be consistently timed - if ((numMicrosecondsSleep = (AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS * 1000) - - (usecTimestampNow() - usecTimestamp(&thisSend))) > 0) { - usleep(numMicrosecondsSleep); + // find the current avatar mixer + Agent* avatarMixer = agentList->soloAgentOfType(AGENT_TYPE_AVATAR_MIXER); + + // make sure we actually have an avatar mixer with an active socket + if (avatarMixer && avatarMixer->getActiveSocket() != NULL + && (usecTimestampNow() - usecTimestamp(&lastSend) > AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS)) { + + // update the lastSend timeval to the current time + gettimeofday(&lastSend, NULL); + + // use the UDPSocket instance attached to our agent list to ask avatar mixer for a list of avatars + agentList->getAgentSocket()->send(avatarMixer->getActiveSocket(), + &broadcastPacket, + sizeof(broadcastPacket)); } } else { - // look for an audio mixer in our agent list - Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); - - if (audioMixer) { - injector.injectAudio(agentList->getAgentSocket(), audioMixer->getActiveSocket()); + if (!injector.isInjectingAudio() && (::shouldLoopAudio || !::hasInjectedAudioOnce)) { + // use the AudioInjectionManager to thread this injector + AudioInjectionManager::threadInjector(&injector); + ::hasInjectedAudioOnce = true; } - - float delay = 0; - int usecDelay = 0; - - if (!::loopAudio) { - delay = randFloatInRange(::sleepIntervalMin, ::sleepIntervalMax); - usecDelay = delay * 1000 * 1000; - usleep(usecDelay); - } } } - // stop the receive agent data thread - stopReceiveAgentDataThread = true; - pthread_join(receiveAgentDataThread, NULL); - // stop the agent list's threads agentList->stopSilentAgentRemovalThread(); } From 5204a9634b3e8477065e807318098c3606d37f88 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 12:33:41 -0700 Subject: [PATCH 43/67] change the trigger argument from d to t --- injector/src/main.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 169c04d104..5b19ada6db 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -40,7 +40,7 @@ bool hasInjectedAudioOnce = false; float sleepIntervalMin = 1.00; float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; -const char *allowedParameters = ":sb::t::c::a::f::d::r:"; +const char *allowedParameters = ":sc::a::f::t::r:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; unsigned char volume = DEFAULT_INJECTOR_VOLUME; float triggerDistance = 0.0f; @@ -52,7 +52,7 @@ void usage(void) { std::cout << " -c FLOAT,FLOAT,FLOAT,FLOAT X,Y,Z,YAW position in universe where audio will be originating from and direction. Defaults to 0,0,0,0" << std::endl; std::cout << " -a 0-255 Attenuation curve modifier, defaults to 255" << std::endl; std::cout << " -f FILENAME Name of audio source file. Required - RAW format, 22050hz 16bit signed mono" << std::endl; - std::cout << " -d FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl; + std::cout << " -t FLOAT Trigger distance for injection. If not specified will loop constantly" << std::endl; std::cout << " -r FLOAT Radius for spherical source. If not specified injected audio is point source" << std::endl; } @@ -88,7 +88,7 @@ bool processParameters(int parameterCount, char* parameterData[]) { ::volume = atoi(optarg); std::cout << "[DEBUG] Attenuation modifier: " << optarg << std::endl; break; - case 'd': + case 't': ::triggerDistance = atof(optarg); std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl; break; From 46de07cd7e272138388d46c3598e066853855a57 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 12:57:05 -0700 Subject: [PATCH 44/67] add debugging for DS public socket activation --- libraries/shared/src/AgentList.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 7a4803586e..2406dee618 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -292,7 +292,10 @@ Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket if (socketMatch(publicSocket, localSocket)) { // likely debugging scenario with two agents on local network // set the agent active right away + printf("Activating the public socket for agent with type %c\n", agentType); newAgent->activatePublicSocket(); + } else { + printf("No match for agent with type %c\n", agentType); } if (newAgent->getType() == AGENT_TYPE_VOXEL_SERVER || From 02eadd904618b630776c7294854199e9d6101474 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 13:02:51 -0700 Subject: [PATCH 45/67] more debugging for DS socket match --- libraries/shared/src/AgentList.cpp | 2 +- libraries/shared/src/UDPSocket.cpp | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 2406dee618..b7a6a97469 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -295,7 +295,7 @@ Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket printf("Activating the public socket for agent with type %c\n", agentType); newAgent->activatePublicSocket(); } else { - printf("No match for agent with type %c\n", agentType); + printf("No match for agent with type %c\n", agentType); } if (newAgent->getType() == AGENT_TYPE_VOXEL_SERVER || diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index 69cf0cfebe..901f6fc7b0 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -39,6 +39,9 @@ bool socketMatch(const sockaddr* first, const sockaddr* second) { const sockaddr_in *firstIn = (const sockaddr_in *) first; const sockaddr_in *secondIn = (const sockaddr_in *) second; + printf("First - %s, %d\n", inet_ntoa(firstIn->sin_addr), ntohs(firstIn->sin_port)); + printf("Second - %s, %d\n", inet_ntoa(secondIn->sin_addr), ntohs(secondIn->sin_port)); + return firstIn->sin_addr.s_addr == secondIn->sin_addr.s_addr && firstIn->sin_port == secondIn->sin_port; } else { From 49b9471d0c6158f12e97f36f6f3ccdb723befc37 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 13:08:14 -0700 Subject: [PATCH 46/67] remove debugging for DS and injector communication --- libraries/shared/src/AgentList.cpp | 3 --- libraries/shared/src/UDPSocket.cpp | 3 --- 2 files changed, 6 deletions(-) diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index b7a6a97469..7a4803586e 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -292,10 +292,7 @@ Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket if (socketMatch(publicSocket, localSocket)) { // likely debugging scenario with two agents on local network // set the agent active right away - printf("Activating the public socket for agent with type %c\n", agentType); newAgent->activatePublicSocket(); - } else { - printf("No match for agent with type %c\n", agentType); } if (newAgent->getType() == AGENT_TYPE_VOXEL_SERVER || diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index 901f6fc7b0..69cf0cfebe 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -39,9 +39,6 @@ bool socketMatch(const sockaddr* first, const sockaddr* second) { const sockaddr_in *firstIn = (const sockaddr_in *) first; const sockaddr_in *secondIn = (const sockaddr_in *) second; - printf("First - %s, %d\n", inet_ntoa(firstIn->sin_addr), ntohs(firstIn->sin_port)); - printf("Second - %s, %d\n", inet_ntoa(secondIn->sin_addr), ntohs(secondIn->sin_port)); - return firstIn->sin_addr.s_addr == secondIn->sin_addr.s_addr && firstIn->sin_port == secondIn->sin_port; } else { From 5e8e50e53bced13906859ae9a1b23315c907f353 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 13:11:31 -0700 Subject: [PATCH 47/67] the EC2 domain server should send to the Agent's local socket --- domain-server/src/main.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 67c1123205..028f4cb508 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -65,8 +65,8 @@ int main(int argc, const char * argv[]) // with the EC2 IP. Otherwise, we will replace the IP like we used to // this allows developers to run a local domain without recompiling the // domain server - bool useLocal = cmdOptionExists(argc, argv, "--local"); - if (useLocal) { + bool isLocalMode = cmdOptionExists(argc, argv, "--local"); + if (isLocalMode) { printf("NOTE: Running in Local Mode!\n"); } else { printf("--------------------------------------------------\n"); @@ -109,7 +109,7 @@ int main(int argc, const char * argv[]) if (agentPublicAddress.sin_addr.s_addr == serverLocalAddress) { // If we're not running "local" then we do replace the IP // with the EC2 IP. Otherwise, we use our normal public IP - if (!useLocal) { + if (!isLocalMode) { agentPublicAddress.sin_addr.s_addr = 895283510; // local IP in this format... } } @@ -177,10 +177,12 @@ int main(int argc, const char * argv[]) // add the agent ID to the end of the pointer currentBufferPos += packAgentId(currentBufferPos, newAgent->getAgentID()); + sockaddr* destinationSocket = (sockaddr*) (isLocalMode ? &agentPublicAddress : &agentLocalAddress); + // send the constructed list back to this agent - agentList->getAgentSocket()->send((sockaddr*) &agentPublicAddress, - broadcastPacket, - (currentBufferPos - startPointer) + 1); + agentList->getAgentSocket()->send(destinationSocket, + broadcastPacket, + (currentBufferPos - startPointer) + 1); } } From 350ebfb80ffd2c6dc5b960397c1ff3df3f16f9aa Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 13:32:17 -0700 Subject: [PATCH 48/67] clients not on EC2 box should be talked to at public address --- domain-server/src/main.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/domain-server/src/main.cpp b/domain-server/src/main.cpp index 028f4cb508..2ea7ecf9f6 100644 --- a/domain-server/src/main.cpp +++ b/domain-server/src/main.cpp @@ -103,6 +103,8 @@ int main(int argc, const char * argv[]) int numBytesSocket = unpackSocket(packetData + sizeof(PACKET_HEADER) + sizeof(AGENT_TYPE), (sockaddr*) &agentLocalAddress); + sockaddr* destinationSocket = (sockaddr*) &agentPublicAddress; + // check the agent public address // if it matches our local address we're on the same box // so hardcode the EC2 public address for now @@ -111,6 +113,7 @@ int main(int argc, const char * argv[]) // with the EC2 IP. Otherwise, we use our normal public IP if (!isLocalMode) { agentPublicAddress.sin_addr.s_addr = 895283510; // local IP in this format... + destinationSocket = (sockaddr*) &agentLocalAddress; } } @@ -177,8 +180,6 @@ int main(int argc, const char * argv[]) // add the agent ID to the end of the pointer currentBufferPos += packAgentId(currentBufferPos, newAgent->getAgentID()); - sockaddr* destinationSocket = (sockaddr*) (isLocalMode ? &agentPublicAddress : &agentLocalAddress); - // send the constructed list back to this agent agentList->getAgentSocket()->send(destinationSocket, broadcastPacket, From f978d748fa5405eca680877713d84c1742aad64b Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 18 Jun 2013 13:42:26 -0700 Subject: [PATCH 49/67] memmove instead of memcpy --- libraries/shared/src/SharedUtil.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 449ce36529..e218006dae 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -423,10 +423,10 @@ int insertIntoSortedArrays(void* value, float key, int originalIndex, // i is our desired location // shift array elements to the right if (i < currentCount && i+1 < maxCount) { - memcpy(&valueArray[i + 1], &valueArray[i], sizeof(void*) * (currentCount - i)); - memcpy(&keyArray[i + 1], &keyArray[i], sizeof(float) * (currentCount - i)); + memmove(&valueArray[i + 1], &valueArray[i], sizeof(void*) * (currentCount - i)); + memmove(&keyArray[i + 1], &keyArray[i], sizeof(float) * (currentCount - i)); if (originalIndexArray) { - memcpy(&originalIndexArray[i + 1], &originalIndexArray[i], sizeof(int) * (currentCount - i)); + memmove(&originalIndexArray[i + 1], &originalIndexArray[i], sizeof(int) * (currentCount - i)); } } } From 5945fbc32d756739d981a53e5607c150c25d225e Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 14:52:13 -0700 Subject: [PATCH 50/67] initial version of jenkins groovy DSL --- jenkins/jobs.groovy | 84 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 jenkins/jobs.groovy diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy new file mode 100644 index 0000000000..f00a86295e --- /dev/null +++ b/jenkins/jobs.groovy @@ -0,0 +1,84 @@ +/*def targets = [ + 'animation-server', + 'audio-mixer', + 'avatar-mixer', + 'domain-server', + 'eve', + 'interface', + 'pairing-server', + 'space-server', + 'voxel-server' +]*/ + +def targets = ['space-server'] + +def JENKINS_URL = 'https://jenkins.below92.com/' +def GITHUB_HOOK_URL = 'https://github.com/worklist/hifi/' +def GIT_REPO_URL = 'git@github.com:worklist/hifi.git' +def HIPCHAT_AUTH_TOKEN = '4ad6553471db605629852ff3265408' +def HIPCHAT_ROOM = 'High Fidelity' +def ARTIFACT_DESTINATION = 'a-tower.below92.com' + +targets.each { + def targetName = it + + job { + name "hifi-${targetName}" + logRotator(7, -1, -1, -1) + + scm { + git(GIT_REPO_URL) + } + + configure { project -> + project / 'properties' << { + 'com.coravy.hudson.plugins.github.GithubProjectProperty' { + projectUrl GITHUB_HOOK_URL + } + + 'jenkins.plugins.hipchat.HipChatNotifier_-HipChatJobProperty' { + room HIPCHAT_ROOM + } + } + + project / 'scm' << { + includedRegions "${targetName}/.*\nlibraries/.*" + } + + project / 'triggers' << 'com.cloudbees.jenkins.GitHubPushTrigger' { + spec '' + } + + project / 'publishers' << { + 'jenkins.plugins.hipchat.HipChatNotifier' { + jenkinsUrl JENKINS_URL + authToken HIPCHAT_AUTH_TOKEN + room HIPCHAT_ROOM + } + + 'jenkins.plugins.publish__over__ssh.BapSshPublisherPlugin' { + consolePrefix 'SSH: ' + + } + } + + project / 'builders' << 'hudson.plugins.cmake.CmakeBuilder' { + sourceDir targetName + buildDir 'build' + buildType 'Release' + generator 'Unix Makefiles' + makeCommand 'make' + installCommand 'make install' + projectCmakePath '/usr/bin/cmake' + cleanBuild 'false' + cleanInstallDir 'false' + } + } + + publishers { + publishScp(ARTIFACT_DESTINATION) { + entry('**/build/$TARGET', '/deploy/$TARGET') + } + } + } +} \ No newline at end of file From 8e94da3cc00ccc5d030b0c9f1466d60d8b5e3945 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 15:43:51 -0700 Subject: [PATCH 51/67] fixes to order of publish steps, deploy --- jenkins/jobs.groovy | 69 +++++++++++++++++++++++++++++---------------- 1 file changed, 45 insertions(+), 24 deletions(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index f00a86295e..37e5a24348 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -38,7 +38,11 @@ targets.each { 'jenkins.plugins.hipchat.HipChatNotifier_-HipChatJobProperty' { room HIPCHAT_ROOM - } + } + 'hudson.plugins.buildblocker.BuildBlockerProperty' { + useBuildBlocker true + blockingJobs 'hifi-dsl-seed' + } } project / 'scm' << { @@ -49,35 +53,52 @@ targets.each { spec '' } + project / 'builders' << 'hudson.plugins.cmake.CmakeBuilder' { + sourceDir targetName + buildDir 'build' + installDir '' + buildType 'RelWithDebInfo' + generator 'Unix Makefiles' + makeCommand 'make' + installCommand 'make install' + preloadScript '' + cmakeArgs '' + projectCmakePath '/usr/bin/cmake' + cleanBuild 'false' + cleanInstallDir 'false' + builderImpl '' + } + } + + publishers { + publishScp(ARTIFACT_DESTINATION) { + entry("**/build/${targetName}", "deploy/${targetName}") + } + } + + configure { project -> project / 'publishers' << { + 'hudson.plugins.postbuildtask.PostbuildTask' { + 'tasks' { + 'hudson.plugins.postbuildtask.TaskProperties' { + logTexts { + 'hudson.plugins.postbuildtask.LogProperties' { + logText '.' + operator 'AND' + } + } + EscalateStatus true + RunIfJobSuccessful true + script "curl -d 'action=deploy&role=highfidelity-live&revision=${targetName}' https://a-tower.below92.com" + } + } + } + 'jenkins.plugins.hipchat.HipChatNotifier' { jenkinsUrl JENKINS_URL authToken HIPCHAT_AUTH_TOKEN room HIPCHAT_ROOM } - - 'jenkins.plugins.publish__over__ssh.BapSshPublisherPlugin' { - consolePrefix 'SSH: ' - - } - } - - project / 'builders' << 'hudson.plugins.cmake.CmakeBuilder' { - sourceDir targetName - buildDir 'build' - buildType 'Release' - generator 'Unix Makefiles' - makeCommand 'make' - installCommand 'make install' - projectCmakePath '/usr/bin/cmake' - cleanBuild 'false' - cleanInstallDir 'false' - } - } - - publishers { - publishScp(ARTIFACT_DESTINATION) { - entry('**/build/$TARGET', '/deploy/$TARGET') } } } From df28dc3165a041baeca66c6de1b26434cc59f69f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 15:46:58 -0700 Subject: [PATCH 52/67] enable creation of jobs for all targets --- jenkins/jobs.groovy | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index 37e5a24348..cc327b1d08 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -1,4 +1,4 @@ -/*def targets = [ +def targets = [ 'animation-server', 'audio-mixer', 'avatar-mixer', @@ -8,9 +8,7 @@ 'pairing-server', 'space-server', 'voxel-server' -]*/ - -def targets = ['space-server'] +] def JENKINS_URL = 'https://jenkins.below92.com/' def GITHUB_HOOK_URL = 'https://github.com/worklist/hifi/' From 3ae44b7614860217fb097fe3023142e803898a22 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 15:55:29 -0700 Subject: [PATCH 53/67] match shorter seed name for DSL job --- jenkins/jobs.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index cc327b1d08..91da60b78e 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -39,7 +39,7 @@ targets.each { } 'hudson.plugins.buildblocker.BuildBlockerProperty' { useBuildBlocker true - blockingJobs 'hifi-dsl-seed' + blockingJobs 'hifi-seed' } } From f6fa95614481170164e64c02a66c8f4e8779910a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 16:02:02 -0700 Subject: [PATCH 54/67] remove a blank line --- libraries/shared/src/SharedUtil.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index e218006dae..85a51422c7 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -404,7 +404,6 @@ void printVoxelCode(unsigned char* voxelCode) { } #endif - // Inserts the value and key into three arrays sorted by the key array, the first array is the value, // the second array is a sorted key for the value, the third array is the index for the value in it original // non-sorted array From 53d3eea0b1fcabc8bf1d7132b9df644b4befd77f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 16:20:24 -0700 Subject: [PATCH 55/67] add conditional deploy of target --- jenkins/jobs.groovy | 78 +++++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 35 deletions(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index 91da60b78e..28e58fc676 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -1,24 +1,10 @@ -def targets = [ - 'animation-server', - 'audio-mixer', - 'avatar-mixer', - 'domain-server', - 'eve', - 'interface', - 'pairing-server', - 'space-server', - 'voxel-server' -] - -def JENKINS_URL = 'https://jenkins.below92.com/' -def GITHUB_HOOK_URL = 'https://github.com/worklist/hifi/' -def GIT_REPO_URL = 'git@github.com:worklist/hifi.git' -def HIPCHAT_AUTH_TOKEN = '4ad6553471db605629852ff3265408' -def HIPCHAT_ROOM = 'High Fidelity' -def ARTIFACT_DESTINATION = 'a-tower.below92.com' - -targets.each { - def targetName = it +def hifiJob(String targetName, Boolean deploy) { + def JENKINS_URL = 'https://jenkins.below92.com/' + def GITHUB_HOOK_URL = 'https://github.com/worklist/hifi/' + def GIT_REPO_URL = 'git@github.com:worklist/hifi.git' + def HIPCHAT_AUTH_TOKEN = '4ad6553471db605629852ff3265408' + def HIPCHAT_ROOM = 'High Fidelity' + def ARTIFACT_DESTINATION = 'a-tower.below92.com' job { name "hifi-${targetName}" @@ -68,26 +54,31 @@ targets.each { } } - publishers { - publishScp(ARTIFACT_DESTINATION) { - entry("**/build/${targetName}", "deploy/${targetName}") + if (deploy) { + publishers { + publishScp(ARTIFACT_DESTINATION) { + entry("**/build/${targetName}", "deploy/${targetName}") + } } } configure { project -> + project / 'publishers' << { - 'hudson.plugins.postbuildtask.PostbuildTask' { - 'tasks' { - 'hudson.plugins.postbuildtask.TaskProperties' { - logTexts { - 'hudson.plugins.postbuildtask.LogProperties' { - logText '.' - operator 'AND' + if (deploy) { + 'hudson.plugins.postbuildtask.PostbuildTask' { + 'tasks' { + 'hudson.plugins.postbuildtask.TaskProperties' { + logTexts { + 'hudson.plugins.postbuildtask.LogProperties' { + logText '.' + operator 'AND' + } } + EscalateStatus true + RunIfJobSuccessful true + script "curl -d 'action=deploy&role=highfidelity-live&revision=${targetName}' https://a-tower.below92.com" } - EscalateStatus true - RunIfJobSuccessful true - script "curl -d 'action=deploy&role=highfidelity-live&revision=${targetName}' https://a-tower.below92.com" } } } @@ -100,4 +91,21 @@ targets.each { } } } -} \ No newline at end of file +} + +def deployTargets = [ + 'animation-server', + 'audio-mixer', + 'avatar-mixer', + 'domain-server', + 'eve', + 'pairing-server', + 'space-server', + 'voxel-server' +] + +deployTargets.each { + hifiJob(it, true) +} + +hifiJob('interface', false) \ No newline at end of file From ee7246cef477eb29ba674e83c3b2c0838f3cc0b4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 17:13:06 -0700 Subject: [PATCH 56/67] have the DSL setup the branch deploy job --- jenkins/jobs.groovy | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index 28e58fc676..4c3ffd5d73 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -11,7 +11,9 @@ def hifiJob(String targetName, Boolean deploy) { logRotator(7, -1, -1, -1) scm { - git(GIT_REPO_URL) + git(GIT_REPO_URL, 'master') { node -> + node / includedRegions << "${targetName}/.*\nlibraries/.*" + } } configure { project -> @@ -29,10 +31,6 @@ def hifiJob(String targetName, Boolean deploy) { } } - project / 'scm' << { - includedRegions "${targetName}/.*\nlibraries/.*" - } - project / 'triggers' << 'com.cloudbees.jenkins.GitHubPushTrigger' { spec '' } @@ -104,8 +102,30 @@ def deployTargets = [ 'voxel-server' ] +/* setup all of the deploys jobs that use the above template */ + deployTargets.each { hifiJob(it, true) } -hifiJob('interface', false) \ No newline at end of file +/* setup the interface job, doesn't deploy */ + +hifiJob('interface', false) + +/* setup the parametrized-build job for builds from jenkins */ + +parametrizedJob = hifiJob('$TARGET', true) +parametrizedJob.with { + name 'hifi-branch-deploy' + parameters { + stringParam('GITHUB_USER', '', "Specifies the name of the GitHub user that we're building from.") + stringParam('GIT_BRANCH', '', "Specifies the specific branch to build and deploy.") + stringParam('HOSTNAME', 'devel.highfidelity.io', "Specifies the hostname to deploy against.") + stringParam('TARGET', '', "What server to build specifically") + } + scm { + git('git@github.com:/$GITHUB_USER/hifi.git', '$GIT_BRANCH') { node -> + node / 'wipeOutWorkspace' << true + } + } +} \ No newline at end of file From 71c51022a43dcc268b0fc80b3e93552a1d8fc5cf Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 17:15:46 -0700 Subject: [PATCH 57/67] fix a typo --- jenkins/jobs.groovy | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index 4c3ffd5d73..5333e38412 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -114,8 +114,8 @@ hifiJob('interface', false) /* setup the parametrized-build job for builds from jenkins */ -parametrizedJob = hifiJob('$TARGET', true) -parametrizedJob.with { +parameterizedJob = hifiJob('$TARGET', true) +parameterizedJob.with { name 'hifi-branch-deploy' parameters { stringParam('GITHUB_USER', '', "Specifies the name of the GitHub user that we're building from.") From c9d7cf1e8fbd773c4165e0e17270c4ae6cd238e1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 17:17:13 -0700 Subject: [PATCH 58/67] remove a comment and add copyright to StdDev class --- libraries/shared/src/StdDev.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/shared/src/StdDev.cpp b/libraries/shared/src/StdDev.cpp index 040f51dd50..2c29a4254b 100644 --- a/libraries/shared/src/StdDev.cpp +++ b/libraries/shared/src/StdDev.cpp @@ -3,13 +3,13 @@ // hifi // // Created by Philip Rosedale on 3/12/13. -// +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // #include "StdDev.h" #include -const int MAX_STDEV_SAMPLES = 1000; // Don't add more than this number of samples. +const int MAX_STDEV_SAMPLES = 1000; StDev::StDev() { data = new float[MAX_STDEV_SAMPLES]; From db118d3bfc1e1ea84424858bcd9ad42b813833ac Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 17:31:07 -0700 Subject: [PATCH 59/67] remove the HIPCHAT_AUTH_TOKEN and ARTIFACT_DESTINATION --- jenkins/jobs.groovy | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index 5333e38412..628168fa4b 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -2,9 +2,7 @@ def hifiJob(String targetName, Boolean deploy) { def JENKINS_URL = 'https://jenkins.below92.com/' def GITHUB_HOOK_URL = 'https://github.com/worklist/hifi/' def GIT_REPO_URL = 'git@github.com:worklist/hifi.git' - def HIPCHAT_AUTH_TOKEN = '4ad6553471db605629852ff3265408' def HIPCHAT_ROOM = 'High Fidelity' - def ARTIFACT_DESTINATION = 'a-tower.below92.com' job { name "hifi-${targetName}" @@ -54,7 +52,7 @@ def hifiJob(String targetName, Boolean deploy) { if (deploy) { publishers { - publishScp(ARTIFACT_DESTINATION) { + publishScp("${ARTIFACT_DESTINATION}") { entry("**/build/${targetName}", "deploy/${targetName}") } } @@ -83,7 +81,7 @@ def hifiJob(String targetName, Boolean deploy) { 'jenkins.plugins.hipchat.HipChatNotifier' { jenkinsUrl JENKINS_URL - authToken HIPCHAT_AUTH_TOKEN + authToken "${HIPCHAT_AUTH_TOKEN}" room HIPCHAT_ROOM } } From dfbf5bdfb9213f37b6317ebc94d43725364ed905 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 17:33:50 -0700 Subject: [PATCH 60/67] use constant for deploy script --- jenkins/jobs.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index 628168fa4b..6baba60e1d 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -73,7 +73,7 @@ def hifiJob(String targetName, Boolean deploy) { } EscalateStatus true RunIfJobSuccessful true - script "curl -d 'action=deploy&role=highfidelity-live&revision=${targetName}' https://a-tower.below92.com" + script "curl -d 'action=deploy&role=highfidelity-live&revision=${targetName}' ${ARTIFACT_DESTINATION}" } } } From a0bab71755b38324403c4234eb61c3abf7279ae2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 17:36:40 -0700 Subject: [PATCH 61/67] prepend artifact destination url with https --- jenkins/jobs.groovy | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index 6baba60e1d..63d7e7f5cf 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -73,7 +73,7 @@ def hifiJob(String targetName, Boolean deploy) { } EscalateStatus true RunIfJobSuccessful true - script "curl -d 'action=deploy&role=highfidelity-live&revision=${targetName}' ${ARTIFACT_DESTINATION}" + script "curl -d 'action=deploy&role=highfidelity-live&revision=${targetName}' https://${ARTIFACT_DESTINATION}" } } } From c48cc3c3a65dcbed0fd8efb8d8b3161a30633fd3 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 17:39:32 -0700 Subject: [PATCH 62/67] add copyright to SharedUtil --- libraries/shared/src/SharedUtil.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 57dc75c7b2..2c9e1e6317 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -3,7 +3,7 @@ // hifi // // Created by Stephen Birarda on 2/22/13. -// +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // #ifndef __hifi__SharedUtil__ From 6d3a1d2b64f81cabb3c715be1907917bf9d9b1c4 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 17:55:39 -0700 Subject: [PATCH 63/67] fix syntax on scm for editor sanity, remove blocker --- jenkins/jobs.groovy | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index 63d7e7f5cf..d44b17cacd 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -9,8 +9,8 @@ def hifiJob(String targetName, Boolean deploy) { logRotator(7, -1, -1, -1) scm { - git(GIT_REPO_URL, 'master') { node -> - node / includedRegions << "${targetName}/.*\nlibraries/.*" + git(GIT_REPO_URL, 'master') { node -> + node << includedRegions << "${targetName}/.*\nlibraries/.*" } } @@ -22,11 +22,7 @@ def hifiJob(String targetName, Boolean deploy) { 'jenkins.plugins.hipchat.HipChatNotifier_-HipChatJobProperty' { room HIPCHAT_ROOM - } - 'hudson.plugins.buildblocker.BuildBlockerProperty' { - useBuildBlocker true - blockingJobs 'hifi-seed' - } + } } project / 'triggers' << 'com.cloudbees.jenkins.GitHubPushTrigger' { From 2344a8c18de693ab3250a61fd30234d3c8f6aaef Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 17:56:43 -0700 Subject: [PATCH 64/67] add copyright to SharedUtil.cpp --- libraries/shared/src/SharedUtil.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 85a51422c7..bdc35ff3f5 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -3,7 +3,7 @@ // hifi // // Created by Stephen Birarda on 2/22/13. -// +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // #include From 41c605918426a13bab568c41a34595a84d955a18 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 18:03:58 -0700 Subject: [PATCH 65/67] remove some lines in the groovy script --- jenkins/jobs.groovy | 3 --- 1 file changed, 3 deletions(-) diff --git a/jenkins/jobs.groovy b/jenkins/jobs.groovy index d44b17cacd..273ad6c674 100644 --- a/jenkins/jobs.groovy +++ b/jenkins/jobs.groovy @@ -97,17 +97,14 @@ def deployTargets = [ ] /* setup all of the deploys jobs that use the above template */ - deployTargets.each { hifiJob(it, true) } /* setup the interface job, doesn't deploy */ - hifiJob('interface', false) /* setup the parametrized-build job for builds from jenkins */ - parameterizedJob = hifiJob('$TARGET', true) parameterizedJob.with { name 'hifi-branch-deploy' From f0330e9f487c615ea1391a9b65e54229a0aa37d6 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 18:04:38 -0700 Subject: [PATCH 66/67] add copyright to stat header --- libraries/shared/src/PerfStat.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/PerfStat.h b/libraries/shared/src/PerfStat.h index f57d49aa46..d39c1f31fb 100644 --- a/libraries/shared/src/PerfStat.h +++ b/libraries/shared/src/PerfStat.h @@ -3,6 +3,7 @@ // hifi // // Created by Brad Hefta-Gaub on 3/29/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // // Poor-man's performance stats collector class. Useful for collecting timing // details from various portions of the code. From 8fd6bc41aae001ba4d995def1d920bae7a54f966 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 18 Jun 2013 18:09:03 -0700 Subject: [PATCH 67/67] add copyright to PerfStat implementation file --- libraries/shared/src/PerfStat.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 2de5aa2816..c376cfcb3e 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -3,6 +3,7 @@ // hifi // // Created by Brad Hefta-Gaub on 3/29/13. +// Copyright (c) 2013 HighFidelity, Inc. All rights reserved. // // Poor-man's performance stats collector class. Useful for collecting timing // details from various portions of the code.