diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 62de224e99..2250bda751 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -172,8 +172,6 @@ Avatar::~Avatar() { void Avatar::init() { _voxels.init(); - - _voxels.createVoxel(0.0f, 0.0f, 0.0f, 1.0f, 255, 0, 255); } void Avatar::reset() { @@ -953,8 +951,11 @@ void Avatar::updateBodyBalls(float deltaTime) { } */ - //update position by velocity... + // update position by velocity... _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; + + // update rotation + _bodyBall[b].rotation = _skeleton.joint[b].rotation; } } @@ -1016,14 +1017,7 @@ void Avatar::renderBody(bool lookingInMirror) { const float RENDER_TRANSLUCENT_BEYOND = 0.5f; // Render the body's voxels - glPushMatrix(); - const glm::vec3& voxelPosition = _joint[AVATAR_JOINT_PELVIS].springyPosition; - glTranslatef(voxelPosition.x, voxelPosition.y, voxelPosition.z); - glm::quat rotation = getOrientation(); - glm::vec3 axis = glm::axis(rotation); - glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z); _voxels.render(false); - glPopMatrix(); // Render the body as balls and cones for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { @@ -1130,6 +1124,11 @@ void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity } } +void Avatar::getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const { + position = _bodyBall[jointID].position; + rotation = _bodyBall[jointID].rotation; +} + void Avatar::writeAvatarDataToFile() { Application::getInstance()->setSetting("avatarPos", _position); Application::getInstance()->setSetting("avatarRotation", glm::vec3(_bodyYaw, _bodyPitch, _bodyRoll)); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 4fff0bdc40..c7561d3986 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -66,7 +66,7 @@ public: void setOrientation (const glm::quat& orientation); //getters - + const Skeleton& getSkeleton () const { return _skeleton;} float getHeadYawRate () const { return _head.yawRate;} float getBodyYaw () const { return _bodyYaw;} bool getIsNearInteractingOther() const { return _avatarTouch.getAbleToReachOtherAvatar();} @@ -97,6 +97,9 @@ public: void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; glm::vec3 getThrust() { return _thrust; }; + // Get the position/rotation of a single body ball + void getBodyBallTransform(AvatarJointID jointID, glm::vec3& position, glm::quat& rotation) const; + //read/write avatar data void writeAvatarDataToFile(); void readAvatarDataFromFile(); @@ -108,7 +111,8 @@ private: struct AvatarBall { - glm::vec3 position; + glm::vec3 position; + glm::quat rotation; glm::vec3 velocity; float jointTightness; float radius; diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index dcea2816ec..50c8ca8a71 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -7,15 +7,15 @@ #include +#include + +#include "Avatar.h" #include "AvatarVoxelSystem.h" #include "renderer/ProgramObject.h" const float AVATAR_TREE_SCALE = 1.0f; const int MAX_VOXELS_PER_AVATAR = 2000; -const int BONE_INDEX_ELEMENTS_PER_VERTEX = 4; -const int BONE_INDEX_ELEMENTS_PER_VOXEL = BONE_INDEX_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; -const int BONE_WEIGHT_ELEMENTS_PER_VERTEX = 4; -const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = BONE_WEIGHT_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; +const int BONE_ELEMENTS_PER_VOXEL = BONE_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXEL; AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), @@ -38,21 +38,31 @@ void AvatarVoxelSystem::init() { VoxelSystem::init(); // prep the data structures for incoming voxel data - _writeBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; - _readBoneIndicesArray = new GLubyte[BONE_INDEX_ELEMENTS_PER_VOXEL * _maxVoxels]; + _writeBoneIndicesArray = new GLubyte[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneIndicesArray = new GLubyte[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; - _writeBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; - _readBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; + _writeBoneWeightsArray = new GLfloat[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneWeightsArray = new GLfloat[BONE_ELEMENTS_PER_VOXEL * _maxVoxels]; // VBO for the boneIndicesArray glGenBuffers(1, &_vboBoneIndicesID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); - glBufferData(GL_ARRAY_BUFFER, BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); // VBO for the boneWeightsArray glGenBuffers(1, &_vboBoneWeightsID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); - glBufferData(GL_ARRAY_BUFFER, BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + + for (int i = 0; i < 150; i++) { + int power = pow(2, randIntInRange(6, 8)); + float size = 1.0f / power; + _tree->createVoxel( + randIntInRange(0, power - 1) * size, + randIntInRange(0, power - 1) * size, + randIntInRange(0, power - 1) * size, size, 255, 0, 255, true); + } + setupNewVoxelsForDrawing(); // load our skin program if this is the first avatar system to initialize if (_skinProgram != 0) { @@ -75,14 +85,15 @@ void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::v float voxelScale, const nodeColor& color) { VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); - GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); - GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_ELEMENTS_PER_VOXEL); for (int i = 0; i < VERTICES_PER_VOXEL; i++) { - GLubyte boneIndices[] = { 0, 0, 0, 0}; - glm::vec4 boneWeights = glm::vec4(1.0f, 0.0f, 0.0f, 0.0f); - for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VERTEX; j++) { - *(writeBoneIndicesAt + i * BONE_INDEX_ELEMENTS_PER_VERTEX + j) = boneIndices[j]; - *(writeBoneWeightsAt + i * BONE_WEIGHT_ELEMENTS_PER_VERTEX + j) = boneWeights[j]; + BoneIndices boneIndices; + glm::vec4 boneWeights; + computeBoneIndicesAndWeights(computeVoxelVertex(startVertex, voxelScale, i), boneIndices, boneWeights); + for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { + *(writeBoneIndicesAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneIndices[j]; + *(writeBoneWeightsAt + i * BONE_ELEMENTS_PER_VERTEX + j) = boneWeights[j]; } } } @@ -91,16 +102,16 @@ void AvatarVoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segment VoxelSystem::copyWrittenDataSegmentToReadArrays(segmentStart, segmentEnd); int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); - GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLintptr segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLsizeiptr segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readBoneIndicesAt = _readBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); memcpy(readBoneIndicesAt, writeBoneIndicesAt, segmentSizeBytes); - segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); - GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readBoneWeightsAt = _readBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); memcpy(readBoneWeightsAt, writeBoneWeightsAt, segmentSizeBytes); } @@ -108,38 +119,94 @@ void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferInd VoxelSystem::updateVBOSegment(segmentStart, segmentEnd); int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLsizeiptr segmentSizeBytes = segmentLength * BONE_INDEX_ELEMENTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLintptr segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLsizeiptr segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readBoneIndicesFrom = _readBoneIndicesArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneIndicesFrom); - segmentStartAt = segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - segmentSizeBytes = segmentLength * BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + segmentStartAt = segmentStart * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + segmentSizeBytes = segmentLength * BONE_ELEMENTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readBoneWeightsFrom = _readBoneWeightsArray + (segmentStart * BONE_ELEMENTS_PER_VOXEL); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); } -void AvatarVoxelSystem::bindProgram(bool texture) { +void AvatarVoxelSystem::applyScaleAndBindProgram(bool texture) { _skinProgram->bind(); - QMatrix4x4 boneMatrices[1]; + // the base matrix includes centering and scale + QMatrix4x4 baseMatrix; + baseMatrix.scale(_treeScale); + baseMatrix.translate(-0.5f, -0.5f, -0.5f); - _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, sizeof(boneMatrices) / sizeof(boneMatrices[0])); + // bone matrices include joint transforms + QMatrix4x4 boneMatrices[NUM_AVATAR_JOINTS]; + for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { + glm::vec3 position; + glm::quat orientation; + _avatar->getBodyBallTransform((AvatarJointID)i, position, orientation); + boneMatrices[i].translate(position.x, position.y, position.z); + boneMatrices[i].rotate(QQuaternion(orientation.w, orientation.x, orientation.y, orientation.z)); + const glm::vec3& defaultPosition = _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition; + boneMatrices[i].translate(-defaultPosition.x, -defaultPosition.y, -defaultPosition.z); + boneMatrices[i] *= baseMatrix; + } + _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, NUM_AVATAR_JOINTS); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); - _skinProgram->setAttributeBuffer(_boneIndicesLocation, GL_UNSIGNED_BYTE, 0, BONE_INDEX_ELEMENTS_PER_VERTEX); + glVertexAttribPointer(_boneIndicesLocation, BONE_ELEMENTS_PER_VERTEX, GL_UNSIGNED_BYTE, false, 0, 0); _skinProgram->enableAttributeArray(_boneIndicesLocation); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); - _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_WEIGHT_ELEMENTS_PER_VERTEX); + _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_ELEMENTS_PER_VERTEX); _skinProgram->enableAttributeArray(_boneWeightsLocation); } -void AvatarVoxelSystem::releaseProgram(bool texture) { +void AvatarVoxelSystem::removeScaleAndReleaseProgram(bool texture) { _skinProgram->release(); _skinProgram->disableAttributeArray(_boneIndicesLocation); _skinProgram->disableAttributeArray(_boneWeightsLocation); } +class IndexDistance { +public: + IndexDistance(GLubyte index = 0, float distance = FLT_MAX) : index(index), distance(distance) { } + + GLubyte index; + float distance; +}; + +void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const { + // transform into joint space + glm::vec3 jointVertex = (vertex - glm::vec3(0.5f, 0.5f, 0.5f)) * AVATAR_TREE_SCALE; + + // find the nearest four joints (TODO: use a better data structure for the pose positions to speed this up) + IndexDistance nearest[BONE_ELEMENTS_PER_VERTEX]; + for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { + float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteDefaultPosePosition); + for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { + if (distance < nearest[j].distance) { + // move the rest of the indices down + for (int k = BONE_ELEMENTS_PER_VERTEX - 1; k > j; k--) { + nearest[k] = nearest[k - 1]; + } + nearest[j] = IndexDistance(i, distance); + break; + } + } + } + + // compute the weights based on inverse distance + float totalWeight = 0.0f; + for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { + indices[i] = nearest[i].index; + weights[i] = (i == 0) ? 1.0f : 0.0f; // 1.0f / glm::max(nearest[i].distance, EPSILON); + totalWeight += weights[i]; + } + + // normalize the weights + for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { + weights[i] /= totalWeight; + } +} diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index 1b28a1a60d..e3a80c3817 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -11,6 +11,9 @@ #include "VoxelSystem.h" +const int BONE_ELEMENTS_PER_VERTEX = 4; +typedef GLubyte BoneIndices[BONE_ELEMENTS_PER_VERTEX]; + class Avatar; class AvatarVoxelSystem : public VoxelSystem { @@ -28,11 +31,13 @@ protected: float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); - virtual void bindProgram(bool texture); - virtual void releaseProgram(bool texture); + virtual void applyScaleAndBindProgram(bool texture); + virtual void removeScaleAndReleaseProgram(bool texture); private: + void computeBoneIndicesAndWeights(const glm::vec3& vertex, BoneIndices& indices, glm::vec4& weights) const; + Avatar* _avatar; GLubyte* _readBoneIndicesArray; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 64a8645247..ae31810d8e 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -18,7 +18,7 @@ void Skeleton::initialize() { joint[b].parent = AVATAR_JOINT_NULL; joint[b].position = glm::vec3(0.0, 0.0, 0.0); joint[b].defaultPosePosition = glm::vec3(0.0, 0.0, 0.0); - joint[b].rotation = glm::quat(0.0f, 0.0f, 0.0f, 0.0f); + joint[b].rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); joint[b].length = 0.0; } @@ -77,9 +77,18 @@ void Skeleton::initialize() { joint[ AVATAR_JOINT_RIGHT_HEEL ].defaultPosePosition = glm::vec3( -0.01, -0.22, 0.08 ); joint[ AVATAR_JOINT_RIGHT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); - // calculate bone length + // calculate bone length, absolute positions for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { joint[b].length = glm::length(joint[b].defaultPosePosition); + + if (joint[b].parent == AVATAR_JOINT_NULL) { + joint[b].absoluteDefaultPosePosition = glm::vec3(0.0f, 0.0f, 0.0f); + } else { + joint[b].absoluteDefaultPosePosition = joint[ joint[b].parent ].absoluteDefaultPosePosition; + } + + glm::vec3 rotatedJointVector = joint[b].defaultPosePosition; + joint[b].absoluteDefaultPosePosition += rotatedJointVector; } } diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index 4c1152728d..5602dfc136 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -58,11 +58,12 @@ public: struct AvatarJoint { - AvatarJointID parent; // which joint is this joint connected to? - glm::vec3 position; // the position at the "end" of the joint - in global space - glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" - glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion - float length; // the length of vector connecting the joint and its parent + AvatarJointID parent; // which joint is this joint connected to? + glm::vec3 position; // the position at the "end" of the joint - in global space + glm::vec3 defaultPosePosition; // the parent relative position when the avatar is in the "T-pose" + glm::vec3 absoluteDefaultPosePosition; // the absolute position when the avatar is in the "T-pose" + glm::quat rotation; // the parent-relative rotation (orientation) of the joint as a quaternion + float length; // the length of vector connecting the joint and its parent }; AvatarJoint joint[ NUM_AVATAR_JOINTS ]; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index c2d3de8da1..dc2e06506f 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -415,6 +415,11 @@ void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& s } } +glm::vec3 VoxelSystem::computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const { + const float* identityVertex = identityVertices + index * 3; + return startVertex + glm::vec3(identityVertex[0], identityVertex[1], identityVertex[2]) * voxelScale; +} + ProgramObject* VoxelSystem::_perlinModulateProgram = 0; GLuint VoxelSystem::_permutationNormalTextureID = 0; @@ -609,8 +614,8 @@ void VoxelSystem::render(bool texture) { // get the lock so that the update thread won't change anything pthread_mutex_lock(&_bufferWriteLock); - glPushMatrix(); updateVBOs(); + // tell OpenGL where to find vertex and color information glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); @@ -625,7 +630,7 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); - bindProgram(texture); + applyScaleAndBindProgram(texture); // for performance, disable blending and enable backface culling glDisable(GL_BLEND); @@ -633,14 +638,13 @@ void VoxelSystem::render(bool texture) { // draw the number of voxels we have glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); - glScalef(_treeScale, _treeScale, _treeScale); glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); glEnable(GL_BLEND); glDisable(GL_CULL_FACE); - releaseProgram(texture); + removeScaleAndReleaseProgram(texture); // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -650,21 +654,24 @@ void VoxelSystem::render(bool texture) { // bind with 0 to switch back to normal operation glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - // scale back down to 1 so heads aren't massive - glPopMatrix(); pthread_mutex_unlock(&_bufferWriteLock); } -void VoxelSystem::bindProgram(bool texture) { +void VoxelSystem::applyScaleAndBindProgram(bool texture) { + glPushMatrix(); + glScalef(_treeScale, _treeScale, _treeScale); + if (texture) { _perlinModulateProgram->bind(); glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); } } -void VoxelSystem::releaseProgram(bool texture) { +void VoxelSystem::removeScaleAndReleaseProgram(bool texture) { + // scale back down to 1 so heads aren't massive + glPopMatrix(); + if (texture) { _perlinModulateProgram->release(); glBindTexture(GL_TEXTURE_2D, 0); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 8c9337bbe5..3a46e19517 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -81,14 +81,20 @@ public: protected: - int _maxVoxels; + float _treeScale; + int _maxVoxels; + VoxelTree* _tree; + + glm::vec3 computeVoxelVertex(const glm::vec3& startVertex, float voxelScale, int index) const; + + void setupNewVoxelsForDrawing(); virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, float voxelScale, const nodeColor& color); virtual void copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); - virtual void bindProgram(bool texture); - virtual void releaseProgram(bool texture); + virtual void applyScaleAndBindProgram(bool texture); + virtual void removeScaleAndReleaseProgram(bool texture); private: // disallow copying of VoxelSystem objects @@ -123,8 +129,6 @@ private: static float _maxDistance; static float _minDistance; - float _treeScale; - VoxelTree* _tree; GLfloat* _readVerticesArray; GLubyte* _readColorsArray; GLfloat* _writeVerticesArray; @@ -157,7 +161,6 @@ private: int newTreeToArrays(VoxelNode *currentNode); void cleanupRemovedVoxels(); - void setupNewVoxelsForDrawing(); void copyWrittenDataToReadArrays(bool fullVBOs); void updateFullVBOs(); // all voxels in the VBO