diff --git a/interface/resources/images/iris.png b/interface/resources/images/iris.png index 3c5b605e3d..0e6251474e 100644 Binary files a/interface/resources/images/iris.png and b/interface/resources/images/iris.png differ diff --git a/interface/resources/shaders/iris.frag b/interface/resources/shaders/iris.frag index 2f5b06d6c6..a5931c3cbe 100644 --- a/interface/resources/shaders/iris.frag +++ b/interface/resources/shaders/iris.frag @@ -15,7 +15,10 @@ uniform sampler2D texture; varying vec4 normal; void main(void) { + // compute the specular component (sans exponent) based on the normal OpenGL lighting model float specular = max(0.0, dot(normalize(gl_LightSource[0].position + vec4(0.0, 0.0, 1.0, 0.0)), normalize(normal))); - gl_FragColor = vec4(gl_Color.rgb * texture2D(texture, gl_TexCoord[0].st).rgb + - pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular.rgb, 1.0); + + // modulate texture by diffuse color and add specular contribution + gl_FragColor = gl_Color * texture2D(texture, gl_TexCoord[0].st) + + pow(specular, gl_FrontMaterial.shininess) * gl_FrontLightProduct[0].specular; } diff --git a/interface/resources/shaders/iris.vert b/interface/resources/shaders/iris.vert index 83602f3e99..66906a93c3 100644 --- a/interface/resources/shaders/iris.vert +++ b/interface/resources/shaders/iris.vert @@ -8,13 +8,29 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // +// the location of the eye in model space +uniform vec3 eyePosition; + // the interpolated normal varying vec4 normal; +// the ratio of the indices of refraction +const float refractionEta = 0.75; + void main(void) { + + // transform and store the normal for interpolation normal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0)); - gl_FrontColor = gl_Color * (gl_LightModel.ambient + gl_LightSource[0].ambient + - gl_LightSource[0].diffuse * max(0.0, dot(normal, gl_LightSource[0].position))); - gl_TexCoord[0] = gl_MultiTexCoord0; + + // compute standard diffuse lighting per-vertex + gl_FrontColor = vec4(gl_Color.rgb * (gl_LightModel.ambient.rgb + gl_LightSource[0].ambient.rgb + + gl_LightSource[0].diffuse.rgb * max(0.0, dot(normal, gl_LightSource[0].position))), gl_Color.a); + + // compute the texture coordinate based on where refracted vector hits z=0 in model space + vec4 incidence = normalize(gl_Vertex - vec4(eyePosition, 1.0)); + vec4 refracted = refract(incidence, normalize(vec4(gl_Normal, 0.0)), refractionEta); + gl_TexCoord[0] = (gl_Vertex - (gl_Vertex.z / refracted.z) * refracted) + vec4(0.5, 0.5, 0.0, 0.0); + + // use standard pipeline transform gl_Position = ftransform(); } diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 63fc6d6c25..aebb8837a5 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -41,6 +41,7 @@ const char IRIS_TEXTURE_FILENAME[] = "resources/images/iris.png"; ProgramObject* Head::_irisProgram = 0; GLuint Head::_irisTextureID; +int Head::_eyePositionLocation; Head::Head(Avatar* owningAvatar) : HeadData((AvatarData*)owningAvatar), @@ -86,13 +87,16 @@ void Head::init() { _irisProgram->link(); _irisProgram->setUniformValue("texture", 0); + _eyePositionLocation = _irisProgram->uniformLocation("eyePosition"); - QImage image = QImage(IRIS_TEXTURE_FILENAME).convertToFormat(QImage::Format_RGB888); + QImage image = QImage(IRIS_TEXTURE_FILENAME).convertToFormat(QImage::Format_ARGB32); glGenTextures(1, &_irisTextureID); glBindTexture(GL_TEXTURE_2D, _irisTextureID); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, image.width(), image.height(), 0, GL_RGB, GL_UNSIGNED_BYTE, image.constBits()); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width(), image.height(), 1, GL_BGRA, GL_UNSIGNED_BYTE, image.constBits()); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glBindTexture(GL_TEXTURE_2D, 0); } } @@ -462,73 +466,74 @@ void Head::renderEyeBrows() { void Head::renderEyeBalls() { - // setup the texture to be used on each iris - GLUquadric* irisQuadric = gluNewQuadric(); - gluQuadricTexture(irisQuadric, GL_TRUE); - - gluQuadricOrientation(irisQuadric, GLU_OUTSIDE); - // render white ball of left eyeball glPushMatrix(); glColor3fv(EYEBALL_COLOR); glTranslatef(_leftEyePosition.x, _leftEyePosition.y, _leftEyePosition.z); - gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30); + glutSolidSphere(EYEBALL_RADIUS, 30, 30); glPopMatrix(); //render white ball of right eyeball glPushMatrix(); glColor3fv(EYEBALL_COLOR); - glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); - gluSphere(irisQuadric, EYEBALL_RADIUS, 30, 30); + glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); + glutSolidSphere(EYEBALL_RADIUS, 30, 30); glPopMatrix(); _irisProgram->bind(); glBindTexture(GL_TEXTURE_2D, _irisTextureID); glEnable(GL_TEXTURE_2D); - glm::vec3 front = getFrontDirection(); + glm::quat orientation = getOrientation(); + glm::vec3 front = orientation * IDENTITY_FRONT; // render left iris glPushMatrix(); { glTranslatef(_leftEyePosition.x, _leftEyePosition.y, _leftEyePosition.z); //translate to eyeball position - glPushMatrix(); - //rotate the eyeball to aim towards the lookat position - glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _leftEyePosition); - glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP); - float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP); - glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z); - glRotatef(180.0, 0.0f, 1.0f, 0.0f); //adjust roll to correct after previous rotations - glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f); - glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris - gluSphere(irisQuadric, IRIS_RADIUS, 15, 15); - glPopMatrix(); + + //rotate the eyeball to aim towards the lookat position + glm::vec3 targetLookatVector = _lookAtPosition + _saccade - _leftEyePosition; + glm::quat rotation = rotationBetween(front, targetLookatVector) * orientation; + glm::vec3 rotationAxis = glm::axis(rotation); + glRotatef(glm::angle(rotation), rotationAxis.x, rotationAxis.y, rotationAxis.z); + glTranslatef(0.0f, 0.0f, -IRIS_PROTRUSION); + glScalef(IRIS_RADIUS * 2.0f, IRIS_RADIUS * 2.0f, IRIS_RADIUS); // flatten the iris + + // this ugliness is simply to invert the model transform and get the eye position in model space + _irisProgram->setUniform(_eyePositionLocation, (glm::inverse(rotation) * + (Application::getInstance()->getCamera()->getPosition() - _leftEyePosition) + + glm::vec3(0.0f, 0.0f, IRIS_PROTRUSION)) * glm::vec3(1.0f / (IRIS_RADIUS * 2.0f), + 1.0f / (IRIS_RADIUS * 2.0f), 1.0f / IRIS_RADIUS)); + + glutSolidSphere(0.5f, 15, 15); } glPopMatrix(); // render right iris glPushMatrix(); { glTranslatef(_rightEyePosition.x, _rightEyePosition.y, _rightEyePosition.z); //translate to eyeball position - glPushMatrix(); - - //rotate the eyeball to aim towards the lookat position - glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition + _saccade - _rightEyePosition); - glm::vec3 rotationAxis = glm::cross(targetLookatAxis, IDENTITY_UP); - float angle = 180.0f - angleBetween(targetLookatAxis, IDENTITY_UP); - glRotatef(angle, rotationAxis.x, rotationAxis.y, rotationAxis.z); - glRotatef(180.0f, 0.0f, 1.0f, 0.0f); //adjust roll to correct after previous rotations - glTranslatef( 0.0f, -IRIS_PROTRUSION, 0.0f); - glScalef( 1.0f, 0.5f, 1.0f); // flatten the iris - gluSphere(irisQuadric, IRIS_RADIUS, 15, 15); - glPopMatrix(); + + //rotate the eyeball to aim towards the lookat position + glm::vec3 targetLookatVector = _lookAtPosition + _saccade - _rightEyePosition; + glm::quat rotation = rotationBetween(front, targetLookatVector) * orientation; + glm::vec3 rotationAxis = glm::axis(rotation); + glRotatef(glm::angle(rotation), rotationAxis.x, rotationAxis.y, rotationAxis.z); + glTranslatef(0.0f, 0.0f, -IRIS_PROTRUSION); + glScalef(IRIS_RADIUS * 2.0f, IRIS_RADIUS * 2.0f, IRIS_RADIUS); // flatten the iris + + // this ugliness is simply to invert the model transform and get the eye position in model space + _irisProgram->setUniform(_eyePositionLocation, (glm::inverse(rotation) * + (Application::getInstance()->getCamera()->getPosition() - _rightEyePosition) + + glm::vec3(0.0f, 0.0f, IRIS_PROTRUSION)) * glm::vec3(1.0f / (IRIS_RADIUS * 2.0f), + 1.0f / (IRIS_RADIUS * 2.0f), 1.0f / IRIS_RADIUS)); + + glutSolidSphere(0.5f, 15, 15); } + glPopMatrix(); _irisProgram->release(); glBindTexture(GL_TEXTURE_2D, 0); glDisable(GL_TEXTURE_2D); - - // delete the iris quadric now that we're done with it - gluDeleteQuadric(irisQuadric); - glPopMatrix(); } void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) { diff --git a/interface/src/Head.h b/interface/src/Head.h index 30636c37fe..840954b0b9 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -109,6 +109,7 @@ private: static ProgramObject* _irisProgram; static GLuint _irisTextureID; + static int _eyePositionLocation; // private methods void createMohawk(); diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 93596e1c1d..4bfdb1f587 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -85,7 +85,7 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) { if (isnan(angle) || angle < EPSILON) { return glm::quat(); } - glm::vec3 axis = glm::cross(v1, v2); + glm::vec3 axis; if (angle > 179.99f) { // 180 degree rotation; must use another axis axis = glm::cross(v1, glm::vec3(1.0f, 0.0f, 0.0f)); float axisLength = glm::length(axis); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index b67e87597a..100f343b6d 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -988,22 +988,21 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe return maxChildLevel; } -int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - int chopLevels, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { +int VoxelTree::encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, + EncodeBitstreamParams& params) const { // How many bytes have we written so far at this level; int bytesWritten = 0; // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! - if (viewFrustum && !node->isInView(*viewFrustum)) { + if (params.viewFrustum && !node->isInView(*params.viewFrustum)) { return bytesWritten; } // write the octal code int codeLength; - if (chopLevels) { - unsigned char* newCode = chopOctalCode(node->getOctalCode(), chopLevels); + if (params.chopLevels) { + unsigned char* newCode = chopOctalCode(node->getOctalCode(), params.chopLevels); if (newCode) { codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(newCode)); memcpy(outputBuffer, newCode, codeLength); @@ -1022,16 +1021,14 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned availableBytes -= codeLength; // keep track or remaining space int currentEncodeLevel = 0; - int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel, node, outputBuffer, availableBytes, - bag, viewFrustum, includeColor, includeExistsBits, chopLevels, - deltaViewFrustum, lastViewFrustum); + int childBytesWritten = encodeTreeBitstreamRecursion(node, outputBuffer, availableBytes, bag, params, currentEncodeLevel); // if childBytesWritten == 1 then something went wrong... that's not possible assert(childBytesWritten != 1); // if includeColor and childBytesWritten == 2, then it can only mean that the lower level trees don't exist or for some reason // couldn't be written... so reset them here... This isn't true for the non-color included case - if (includeColor && childBytesWritten == 2) { + if (params.includeColor && childBytesWritten == 2) { childBytesWritten = 0; } @@ -1045,10 +1042,8 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned return bytesWritten; } -int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, - unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, - const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - int chopLevels, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { +int VoxelTree::encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, + EncodeBitstreamParams& params, int& currentEncodeLevel) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -1057,13 +1052,13 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco currentEncodeLevel++; // If we've reached our max Search Level, then stop searching. - if (currentEncodeLevel >= maxEncodeLevel) { + if (currentEncodeLevel >= params.maxEncodeLevel) { return bytesAtThisLevel; } // caller can pass NULL as viewFrustum if they want everything - if (viewFrustum) { - float distance = node->distanceToCamera(*viewFrustum); + if (params.viewFrustum) { + float distance = node->distanceToCamera(*params.viewFrustum); float boundaryDistance = boundaryDistanceForRenderLevel(*node->getOctalCode() + 1); // If we're too far away for our render level, then just return @@ -1074,7 +1069,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // If we're at a node that is out of view, then we can return, because no nodes below us will be in view! // although technically, we really shouldn't ever be here, because our callers shouldn't be calling us if // we're out of view - if (!node->isInView(*viewFrustum)) { + if (!node->isInView(*params.viewFrustum)) { return bytesAtThisLevel; } } @@ -1107,16 +1102,16 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco VoxelNode* childNode = node->getChildAtIndex(i); // if the caller wants to include childExistsBits, then include them even if not in view - if (includeExistsBits && childNode) { + if (params.includeExistsBits && childNode) { childrenExistInTreeBits += (1 << (7 - i)); } - bool childIsInView = (childNode && (!viewFrustum || childNode->isInView(*viewFrustum))); + 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 = viewFrustum ? childNode->distanceToCamera(*viewFrustum) : 0; - float boundaryDistance = viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1; + float distance = params.viewFrustum ? childNode->distanceToCamera(*params.viewFrustum) : 0; + float boundaryDistance = params.viewFrustum ? boundaryDistanceForRenderLevel(*childNode->getOctalCode() + 1) : 1; if (distance < boundaryDistance) { inViewCount++; @@ -1129,8 +1124,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco inViewNotLeafCount++; } - bool childWasInView = (childNode && deltaViewFrustum && - (lastViewFrustum && ViewFrustum::INSIDE == childNode->inFrustum(*lastViewFrustum))); + 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) { @@ -1145,7 +1140,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco bytesAtThisLevel += sizeof(childrenColoredBits); // keep track of byte count // write the color data... - if (includeColor) { + if (params.includeColor) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { if (oneAtBit(childrenColoredBits, i)) { memcpy(writeToThisLevelBuffer, &node->getChildAtIndex(i)->getColor(), BYTES_PER_COLOR); @@ -1157,7 +1152,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // if the caller wants to include childExistsBits, then include them even if not in view, put them before the // childrenExistInPacketBits, so that the lower code can properly repair the packet exists bits - if (includeExistsBits) { + if (params.includeExistsBits) { *writeToThisLevelBuffer = childrenExistInTreeBits; writeToThisLevelBuffer += sizeof(childrenExistInTreeBits); // move the pointer bytesAtThisLevel += sizeof(childrenExistInTreeBits); // keep track of byte count @@ -1201,10 +1196,8 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco VoxelNode* childNode = node->getChildAtIndex(i); int thisLevel = currentEncodeLevel; - int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode, - outputBuffer, availableBytes, bag, - viewFrustum, includeColor, includeExistsBits, chopLevels, - deltaViewFrustum, lastViewFrustum); + int childTreeBytesOut = encodeTreeBitstreamRecursion(childNode, outputBuffer, availableBytes, bag, + params, thisLevel); // 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. @@ -1222,7 +1215,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco // so, if the child returns 2 bytes out, we can actually consider that an empty tree also!! // // we can make this act like no bytes out, by just resetting the bytes out in this case - if (includeColor && childTreeBytesOut == 2) { + if (params.includeColor && childTreeBytesOut == 2) { childTreeBytesOut = 0; // this is the degenerate case of a tree with no colors and no child trees } @@ -1287,8 +1280,9 @@ void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) const { while (!nodeBag.isEmpty()) { VoxelNode* subTree = nodeBag.extract(); - bytesWritten = encodeTreeBitstream(INT_MAX, subTree, &outputBuffer[0], - MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + + EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params); file.write((const char*)&outputBuffer[0], bytesWritten); } @@ -1322,8 +1316,8 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat VoxelNode* subTree = nodeBag.extract(); // ask our tree to write a bitsteam - bytesWritten = encodeTreeBitstream(INT_MAX, subTree, &outputBuffer[0], - MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels); + EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels); + bytesWritten = encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params); // ask destination tree to read the bitstream destinationTree->readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS); @@ -1342,9 +1336,9 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin VoxelNode* subTree = nodeBag.extract(); // ask our tree to write a bitsteam - bytesWritten = sourceTree->encodeTreeBitstream(INT_MAX, subTree, &outputBuffer[0], - MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); - + EncodeBitstreamParams params(INT_MAX, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); + bytesWritten = sourceTree->encodeTreeBitstream(subTree, &outputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, nodeBag, params); + // ask destination tree to read the bitstream readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS, destinationNode); } diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index a238cb603a..9550c6c6b3 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -28,6 +28,35 @@ typedef enum {GRADIENT, RANDOM, NATURAL} creationMode; #define COLLAPSE_EMPTY_TREE true #define DONT_COLLAPSE false +class EncodeBitstreamParams { +public: + int maxEncodeLevel; + const ViewFrustum* viewFrustum; + bool includeColor; + bool includeExistsBits; + int chopLevels; + bool deltaViewFrustum; + const ViewFrustum* lastViewFrustum; + + EncodeBitstreamParams( + int maxEncodeLevel = INT_MAX, + const ViewFrustum* viewFrustum = IGNORE_VIEW_FRUSTUM, + bool includeColor = WANT_COLOR, + bool includeExistsBits = WANT_EXISTS_BITS, + int chopLevels = 0, + bool deltaViewFrustum = false, + const ViewFrustum* lastViewFrustum = IGNORE_VIEW_FRUSTUM) : + + maxEncodeLevel (maxEncodeLevel), + viewFrustum (viewFrustum), + includeColor (includeColor), + includeExistsBits (includeExistsBits), + chopLevels (chopLevels), + deltaViewFrustum (deltaViewFrustum), + lastViewFrustum (lastViewFrustum) + {} +}; + class VoxelTree { public: // when a voxel is created in the tree (object new'd) @@ -68,10 +97,8 @@ public: void recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData=NULL); - int encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, - VoxelNodeBag& bag, const ViewFrustum* viewFrustum, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, - bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = NULL) const; + int encodeTreeBitstream(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, + EncodeBitstreamParams& params) const; int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = NULL); @@ -105,10 +132,8 @@ private: void deleteVoxelCodeFromTreeRecursion(VoxelNode* node, void* extraData); void readCodeColorBufferToTreeRecursion(VoxelNode* node, void* extraData); - int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, - VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, - const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - int chopLevels, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const; + int encodeTreeBitstreamRecursion(VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, + EncodeBitstreamParams& params, int& currentEncodeLevel) const; int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index aae631bb16..5853e3f245 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -167,10 +167,12 @@ void resInVoxelDistributor(AgentList* agentList, while (packetsSentThisInterval < PACKETS_PER_CLIENT_PER_INTERVAL - (shouldSendEnvironments ? 1 : 0)) { if (!agentData->nodeBag.isEmpty()) { VoxelNode* subTree = agentData->nodeBag.extract(); - bytesWritten = serverTree.encodeTreeBitstream(agentData->getMaxSearchLevel(), subTree, - &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, - agentData->nodeBag, &viewFrustum, - agentData->getWantColor(), WANT_EXISTS_BITS); + + EncodeBitstreamParams params(agentData->getMaxSearchLevel(), &viewFrustum, + agentData->getWantColor(), WANT_EXISTS_BITS); + + bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, + agentData->nodeBag, params); if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); @@ -310,12 +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(); - bytesWritten = serverTree.encodeTreeBitstream(INT_MAX, subTree, - &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, - agentData->nodeBag, &agentData->getCurrentViewFrustum(), - agentData->getWantColor(), WANT_EXISTS_BITS, - wantDelta, lastViewFrustum); + + EncodeBitstreamParams params(INT_MAX, &agentData->getCurrentViewFrustum(), agentData->getWantColor(), + WANT_EXISTS_BITS, wantDelta, lastViewFrustum); + bytesWritten = serverTree.encodeTreeBitstream(subTree, &tempOutputBuffer[0], MAX_VOXEL_PACKET_SIZE - 1, + agentData->nodeBag, params); + if (agentData->getAvailable() >= bytesWritten) { agentData->writeToPacket(&tempOutputBuffer[0], bytesWritten); } else {