From 5d1ba857c55c402858edf678c07f6dcc9c236d0f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 May 2013 09:56:35 -0700 Subject: [PATCH 01/73] Optimize View Frustum wire format. - Changed View frstum orientaton to be a quaternion - Implemented packing formats for Orientation Quats, Ratios, and Clipping values - Changed wire format for View Frustum details to be more efficient 28 bytes vs 64 bytes --- interface/src/Application.cpp | 8 +- interface/src/Avatar.cpp | 2 +- interface/src/Head.cpp | 4 +- libraries/avatars/src/AvatarData.cpp | 167 +++++++++++++++++++-------- libraries/avatars/src/AvatarData.h | 50 +++++--- libraries/shared/src/SharedUtil.cpp | 1 + libraries/shared/src/SharedUtil.h | 1 + libraries/voxels/src/ViewFrustum.cpp | 42 +++++-- libraries/voxels/src/ViewFrustum.h | 29 ++--- voxel-server/src/VoxelAgentData.cpp | 2 +- 10 files changed, 210 insertions(+), 96 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a0979eb4b9..790a7f9495 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1092,7 +1092,7 @@ static void sendVoxelEditMessage(PACKET_HEADER header, VoxelDetail& detail) { void Application::addVoxelInFrontOfAvatar() { VoxelDetail detail; - glm::vec3 position = (_myAvatar.getPosition() + _myAvatar.getCameraDirection()) * (1.0f / TREE_SCALE); + glm::vec3 position = (_myAvatar.getPosition() + _myAvatar.calculateCameraDirection()) * (1.0f / TREE_SCALE); detail.s = _mouseVoxelScale; detail.x = detail.s * floor(position.x / detail.s); @@ -1347,9 +1347,7 @@ void Application::updateAvatar(float deltaTime) { // to the server. loadViewFrustum(_myCamera, _viewFrustum); _myAvatar.setCameraPosition(_viewFrustum.getPosition()); - _myAvatar.setCameraDirection(_viewFrustum.getDirection()); - _myAvatar.setCameraUp(_viewFrustum.getUp()); - _myAvatar.setCameraRight(_viewFrustum.getRight()); + _myAvatar.setCameraOrientation(_viewFrustum.getOrientation()); _myAvatar.setCameraFov(_viewFrustum.getFieldOfView()); _myAvatar.setCameraAspectRatio(_viewFrustum.getAspectRatio()); _myAvatar.setCameraNearClip(_viewFrustum.getNearClip()); @@ -1435,7 +1433,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { // Set the viewFrustum up with the correct position and orientation of the camera viewFrustum.setPosition(position); - viewFrustum.setOrientation(direction,up,right); + viewFrustum.setOrientation(o.getQuat()); // Also make sure it's got the correct lens details from the camera viewFrustum.setFieldOfView(fov); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 8ce1abb05b..fce56ff670 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -80,8 +80,8 @@ Avatar::Avatar(Agent* owningAgent) : _bodyRollDelta(0.0f), _movedHandOffset(0.0f, 0.0f, 0.0f), _rotation(0.0f, 0.0f, 0.0f, 0.0f), - _cameraPosition(0.0f, 0.0f, 0.0f), _mode(AVATAR_MODE_STANDING), + _cameraPosition(0.0f, 0.0f, 0.0f), _handHoldingPosition(0.0f, 0.0f, 0.0f), _velocity(0.0f, 0.0f, 0.0f), _thrust(0.0f, 0.0f, 0.0f), diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 1486013c9c..736534f087 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -62,9 +62,9 @@ Head::Head(Avatar* owningAvatar) : _audioAttack(0.0f), _returnSpringScale(1.0f), _bodyRotation(0.0f, 0.0f, 0.0f), + _renderLookatVectors(false), _mohawkTriangleFan(NULL), - _mohawkColors(NULL), - _renderLookatVectors(false) { + _mohawkColors(NULL) { for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { _hairTuft[t].length = HAIR_LENGTH; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 4b97a2a047..fa0a8d1e20 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -17,20 +17,6 @@ using namespace std; -int packFloatAngleToTwoByte(unsigned char* buffer, float angle) { - const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.0); - - uint16_t angleHolder = floorf((angle + 180) * ANGLE_CONVERSION_RATIO); - memcpy(buffer, &angleHolder, sizeof(uint16_t)); - - return sizeof(uint16_t); -} - -int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPointer) { - *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits::max()) * 360.0 - 180; - return sizeof(uint16_t); -} - AvatarData::AvatarData(Agent* owningAgent) : AgentData(owningAgent), _handPosition(0,0,0), @@ -40,9 +26,7 @@ AvatarData::AvatarData(Agent* owningAgent) : _audioLoudness(0), _handState(0), _cameraPosition(0,0,0), - _cameraDirection(0,0,0), - _cameraUp(0,0,0), - _cameraRight(0,0,0), + _cameraOrientation(), _cameraFov(0.0f), _cameraAspectRatio(0.0f), _cameraNearClip(0.0f), @@ -110,20 +94,11 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { // camera details memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition)); destinationBuffer += sizeof(_cameraPosition); - memcpy(destinationBuffer, &_cameraDirection, sizeof(_cameraDirection)); - destinationBuffer += sizeof(_cameraDirection); - memcpy(destinationBuffer, &_cameraRight, sizeof(_cameraRight)); - destinationBuffer += sizeof(_cameraRight); - memcpy(destinationBuffer, &_cameraUp, sizeof(_cameraUp)); - destinationBuffer += sizeof(_cameraUp); - memcpy(destinationBuffer, &_cameraFov, sizeof(_cameraFov)); - destinationBuffer += sizeof(_cameraFov); - memcpy(destinationBuffer, &_cameraAspectRatio, sizeof(_cameraAspectRatio)); - destinationBuffer += sizeof(_cameraAspectRatio); - memcpy(destinationBuffer, &_cameraNearClip, sizeof(_cameraNearClip)); - destinationBuffer += sizeof(_cameraNearClip); - memcpy(destinationBuffer, &_cameraFarClip, sizeof(_cameraFarClip)); - destinationBuffer += sizeof(_cameraFarClip); + destinationBuffer += packOrientationQuatToBytes(destinationBuffer, _cameraOrientation); + destinationBuffer += packFloatAngleToTwoByte(destinationBuffer, _cameraFov); + destinationBuffer += packFloatRatioToTwoByte(destinationBuffer, _cameraAspectRatio); + destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraNearClip); + destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraFarClip); // key state *destinationBuffer++ = _keyState; @@ -204,21 +179,12 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { // camera details memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition)); sourceBuffer += sizeof(_cameraPosition); - memcpy(&_cameraDirection, sourceBuffer, sizeof(_cameraDirection)); - sourceBuffer += sizeof(_cameraDirection); - memcpy(&_cameraRight, sourceBuffer, sizeof(_cameraRight)); - sourceBuffer += sizeof(_cameraRight); - memcpy(&_cameraUp, sourceBuffer, sizeof(_cameraUp)); - sourceBuffer += sizeof(_cameraUp); - memcpy(&_cameraFov, sourceBuffer, sizeof(_cameraFov)); - sourceBuffer += sizeof(_cameraFov); - memcpy(&_cameraAspectRatio, sourceBuffer, sizeof(_cameraAspectRatio)); - sourceBuffer += sizeof(_cameraAspectRatio); - memcpy(&_cameraNearClip, sourceBuffer, sizeof(_cameraNearClip)); - sourceBuffer += sizeof(_cameraNearClip); - memcpy(&_cameraFarClip, sourceBuffer, sizeof(_cameraFarClip)); - sourceBuffer += sizeof(_cameraFarClip); - + sourceBuffer += unpackOrientationQuatFromBytes(sourceBuffer, _cameraOrientation); + sourceBuffer += unpackFloatAngleFromTwoByte((uint16_t*) sourceBuffer, &_cameraFov); + sourceBuffer += unpackFloatRatioFromTwoByte(sourceBuffer,_cameraAspectRatio); + sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraNearClip); + sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraFarClip); + // key state _keyState = (KeyState)*sourceBuffer++; @@ -236,3 +202,112 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { return sourceBuffer - startPosition; } + +glm::vec3 AvatarData::calculateCameraDirection() const { + const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f, 1.0f); + glm::mat4 rotationMatrix = glm::mat4_cast(_cameraOrientation); + glm::vec3 direction = glm::vec3(glm::vec4(IDENTITY_FRONT, 0.0f) * rotationMatrix); + return direction; +} + + +int packFloatAngleToTwoByte(unsigned char* buffer, float angle) { + const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.0); + + uint16_t angleHolder = floorf((angle + 180) * ANGLE_CONVERSION_RATIO); + memcpy(buffer, &angleHolder, sizeof(uint16_t)); + + return sizeof(uint16_t); +} + +int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPointer) { + *destinationPointer = (*byteAnglePointer / (float) std::numeric_limits::max()) * 360.0 - 180; + return sizeof(uint16_t); +} + +int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput) { + const float QUAT_PART_CONVERSION_RATIO = (std::numeric_limits::max() / 2.0); + uint16_t quatParts[4]; + quatParts[0] = floorf((quatInput.x + 1.0) * QUAT_PART_CONVERSION_RATIO); + quatParts[1] = floorf((quatInput.y + 1.0) * QUAT_PART_CONVERSION_RATIO); + quatParts[2] = floorf((quatInput.z + 1.0) * QUAT_PART_CONVERSION_RATIO); + quatParts[3] = floorf((quatInput.w + 1.0) * QUAT_PART_CONVERSION_RATIO); + + memcpy(buffer, &quatParts, sizeof(quatParts)); + return sizeof(quatParts); +} + +int unpackOrientationQuatFromBytes(unsigned char* buffer, glm::quat& quatOutput) { + uint16_t quatParts[4]; + memcpy(&quatParts, buffer, sizeof(quatParts)); + + quatOutput.x = ((quatParts[0] / (float) std::numeric_limits::max()) * 2.0) - 1.0; + quatOutput.y = ((quatParts[1] / (float) std::numeric_limits::max()) * 2.0) - 1.0; + quatOutput.z = ((quatParts[2] / (float) std::numeric_limits::max()) * 2.0) - 1.0; + quatOutput.w = ((quatParts[3] / (float) std::numeric_limits::max()) * 2.0) - 1.0; + + return sizeof(quatParts); +} + +float SMALL_LIMIT = 10.0; +float LARGE_LIMIT = 1000.0; + +int packFloatRatioToTwoByte(unsigned char* buffer, float ratio) { + // if the ratio is less than 10, then encode it as a positive number scaled from 0 to int16::max() + int16_t ratioHolder; + + if (ratio < SMALL_LIMIT) { + const float SMALL_RATIO_CONVERSION_RATIO = (std::numeric_limits::max() / SMALL_LIMIT); + ratioHolder = floorf(ratio * SMALL_RATIO_CONVERSION_RATIO); + } else { + const float LARGE_RATIO_CONVERSION_RATIO = std::numeric_limits::min() / LARGE_LIMIT; + ratioHolder = floorf((std::min(ratio,LARGE_LIMIT) - SMALL_LIMIT) * LARGE_RATIO_CONVERSION_RATIO); + } + memcpy(buffer, &ratioHolder, sizeof(ratioHolder)); + return sizeof(ratioHolder); +} + +int unpackFloatRatioFromTwoByte(unsigned char* buffer, float& ratio) { + int16_t ratioHolder; + memcpy(&ratioHolder, buffer, sizeof(ratioHolder)); + + // If it's positive, than the original ratio was less than SMALL_LIMIT + if (ratioHolder > 0) { + ratio = (ratioHolder / (float) std::numeric_limits::max()) * SMALL_LIMIT; + } else { + // If it's negative, than the original ratio was between SMALL_LIMIT and LARGE_LIMIT + ratio = ((ratioHolder / (float) std::numeric_limits::min()) * LARGE_LIMIT) + SMALL_LIMIT; + } + return sizeof(ratioHolder); +} + +int packClipValueToTwoByte(unsigned char* buffer, float clipValue) { + // Clip values must be less than max signed 16bit integers + assert(clipValue < std::numeric_limits::max()); + int16_t holder; + + // if the clip is less than 10, then encode it as a positive number scaled from 0 to int16::max() + if (clipValue < SMALL_LIMIT) { + const float SMALL_RATIO_CONVERSION_RATIO = (std::numeric_limits::max() / SMALL_LIMIT); + holder = floorf(clipValue * SMALL_RATIO_CONVERSION_RATIO); + } else { + // otherwise we store it as a negative integer + holder = -1 * floorf(clipValue); + } + memcpy(buffer, &holder, sizeof(holder)); + return sizeof(holder); +} + +int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue) { + int16_t holder; + memcpy(&holder, buffer, sizeof(holder)); + + // If it's positive, than the original clipValue was less than SMALL_LIMIT + if (holder > 0) { + clipValue = (holder / (float) std::numeric_limits::max()) * SMALL_LIMIT; + } else { + // If it's negative, than the original holder can be found as the opposite sign of holder + clipValue = -1.0f * holder; + } + return sizeof(holder); +} diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 5773dedffd..d86cc6078b 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -12,6 +12,7 @@ #include #include +#include #include #include "HeadData.h" @@ -58,23 +59,21 @@ public: // getters for camera details const glm::vec3& getCameraPosition() const { return _cameraPosition; }; - const glm::vec3& getCameraDirection() const { return _cameraDirection; } - const glm::vec3& getCameraUp() const { return _cameraUp; } - const glm::vec3& getCameraRight() const { return _cameraRight; } + const glm::quat& getCameraOrientation() const { return _cameraOrientation; } float getCameraFov() const { return _cameraFov; } float getCameraAspectRatio() const { return _cameraAspectRatio; } float getCameraNearClip() const { return _cameraNearClip; } float getCameraFarClip() const { return _cameraFarClip; } + glm::vec3 calculateCameraDirection() const; + // setters for camera details - void setCameraPosition(const glm::vec3& position) { _cameraPosition = position; }; - void setCameraDirection(const glm::vec3& direction) { _cameraDirection = direction; } - void setCameraUp(const glm::vec3& up) { _cameraUp = up; } - void setCameraRight(const glm::vec3& right) { _cameraRight = right; } - void setCameraFov(float fov) { _cameraFov = fov; } - void setCameraAspectRatio(float aspectRatio) { _cameraAspectRatio = aspectRatio; } - void setCameraNearClip(float nearClip) { _cameraNearClip = nearClip; } - void setCameraFarClip(float farClip) { _cameraFarClip = farClip; } + void setCameraPosition(const glm::vec3& position) { _cameraPosition = position; } + void setCameraOrientation(const glm::quat& orientation) { _cameraOrientation = orientation; } + void setCameraFov(float fov) { _cameraFov = fov; } + void setCameraAspectRatio(float aspectRatio) { _cameraAspectRatio = aspectRatio; } + void setCameraNearClip(float nearClip) { _cameraNearClip = nearClip; } + void setCameraFarClip(float farClip) { _cameraFarClip = farClip; } // key state void setKeyState(KeyState s) { _keyState = s; } @@ -111,11 +110,7 @@ protected: // camera details for the avatar glm::vec3 _cameraPosition; - - // can we describe this in less space? For example, a Quaternion? or Euler angles? - glm::vec3 _cameraDirection; - glm::vec3 _cameraUp; - glm::vec3 _cameraRight; + glm::quat _cameraOrientation; float _cameraFov; float _cameraAspectRatio; float _cameraNearClip; @@ -139,4 +134,27 @@ private: AvatarData& operator= (const AvatarData&); }; + +// These pack/unpack functions are designed to start specific known types in as efficient a manner +// as possible. Taking advantage of the known characteristics of the semantic types. + +// Angles are known to be between 0 and 360deg, this allows us to encode in 16bits with great accuracy +int packFloatAngleToTwoByte(unsigned char* buffer, float angle); +int unpackFloatAngleFromTwoByte(uint16_t* byteAnglePointer, float* destinationPointer); + +// Orientation Quats are known to have 4 normalized components be between -1.0 and 1.0 +// this allows us to encode each component in 16bits with great accuracy +int packOrientationQuatToBytes(unsigned char* buffer, const glm::quat& quatInput); +int unpackOrientationQuatFromBytes(unsigned char* buffer, glm::quat& quatOutput); + +// Ratios need the be highly accurate when less than 10, but not very accurate above 10, and they +// are never greater than 1000 to 1, this allows us to encode each component in 16bits +int packFloatRatioToTwoByte(unsigned char* buffer, float ratio); +int unpackFloatRatioFromTwoByte(unsigned char* buffer, float& ratio); + +// Near/Far Clip values need the be highly accurate when less than 10, but only integer accuracy above 10 and +// they are never greater than 16,000, this allows us to encode each component in 16bits +int packClipValueToTwoByte(unsigned char* buffer, float clipValue); +int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue); + #endif /* defined(__hifi__AvatarData__) */ diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 5829bbe34a..ca31cdd994 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -421,3 +421,4 @@ int insertIntoSortedArrays(void* value, float key, int originalIndex, } return -1; // error case } + diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 8da9d7beca..9d858f11e0 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -87,4 +87,5 @@ class debug { public: static const char* valueOf(bool checkValue) { return checkValue ? "yes" : "no"; }; }; + #endif /* defined(__hifi__SharedUtil__) */ diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 061727b003..0f10428b23 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -19,22 +19,40 @@ using namespace std; ViewFrustum::ViewFrustum() : - _position(glm::vec3(0,0,0)), - _direction(glm::vec3(0,0,0)), - _up(glm::vec3(0,0,0)), - _right(glm::vec3(0,0,0)), + _position(0,0,0), + _orientation(), + _direction(0,0,0), + _up(0,0,0), + _right(0,0,0), _fieldOfView(0.0), _aspectRatio(1.0), _nearClip(0.1), _farClip(500.0), - _farTopLeft(glm::vec3(0,0,0)), - _farTopRight(glm::vec3(0,0,0)), - _farBottomLeft(glm::vec3(0,0,0)), - _farBottomRight(glm::vec3(0,0,0)), - _nearTopLeft(glm::vec3(0,0,0)), - _nearTopRight(glm::vec3(0,0,0)), - _nearBottomLeft(glm::vec3(0,0,0)), - _nearBottomRight(glm::vec3(0,0,0)) { } + _farTopLeft(0,0,0), + _farTopRight(0,0,0), + _farBottomLeft(0,0,0), + _farBottomRight(0,0,0), + _nearTopLeft(0,0,0), + _nearTopRight(0,0,0), + _nearBottomLeft(0,0,0), + _nearBottomRight(0,0,0) { } + +void ViewFrustum::setOrientation(const glm::quat& orientationAsQuaternion) { + glm::quat quat; + quat = quat * orientationAsQuaternion; + + // this is where the coordinate system is represented + const glm::vec3 IDENTITY_RIGHT = glm::vec3(-1.0f, 0.0f, 0.0f); + const glm::vec3 IDENTITY_UP = glm::vec3( 0.0f, 1.0f, 0.0f); + const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f, 1.0f); + + glm::mat4 rotationMatrix = glm::mat4_cast(quat); + + _orientation = orientationAsQuaternion; + _right = glm::vec3(glm::vec4(IDENTITY_RIGHT, 0.0f) * rotationMatrix); + _up = glm::vec3(glm::vec4(IDENTITY_UP, 0.0f) * rotationMatrix); + _direction = glm::vec3(glm::vec4(IDENTITY_FRONT, 0.0f) * rotationMatrix); +} ///////////////////////////////////////////////////////////////////////////////////// // ViewFrustum::calculateViewFrustum() diff --git a/libraries/voxels/src/ViewFrustum.h b/libraries/voxels/src/ViewFrustum.h index 1ae33d55ad..1c61160566 100644 --- a/libraries/voxels/src/ViewFrustum.h +++ b/libraries/voxels/src/ViewFrustum.h @@ -21,6 +21,9 @@ private: // camera location/orientation attributes glm::vec3 _position; + glm::quat _orientation; + + // calculated for orientation glm::vec3 _direction; glm::vec3 _up; glm::vec3 _right; @@ -53,23 +56,23 @@ private: public: // setters for camera attributes - void setPosition (const glm::vec3& p) { _position = p; } - void setOrientation (const glm::vec3& d, const glm::vec3& u, const glm::vec3& r ) - { _direction = d; _up = u; _right = r; } + void setPosition (const glm::vec3& p) { _position = p; }; + void setOrientation (const glm::quat& orientationAsQuaternion); // getters for camera attributes - const glm::vec3& getPosition() const { return _position; }; - const glm::vec3& getDirection() const { return _direction; }; - const glm::vec3& getUp() const { return _up; }; - const glm::vec3& getRight() const { return _right; }; + const glm::vec3& getPosition() const { return _position; }; + const glm::quat& getOrientation() const { return _orientation; }; + const glm::vec3& getDirection() const { return _direction; }; + const glm::vec3& getUp() const { return _up; }; + const glm::vec3& getRight() const { return _right; }; // setters for lens attributes - void setFieldOfView ( float f ) { _fieldOfView = f; } - void setAspectRatio ( float a ) { _aspectRatio = a; } - void setNearClip ( float n ) { _nearClip = n; } - void setFarClip ( float f ) { _farClip = f; } - void setEyeOffsetPosition (const glm::vec3& p) { _eyeOffsetPosition = p; } - void setEyeOffsetOrientation (const glm::quat& o) { _eyeOffsetOrientation = o; } + void setFieldOfView ( float f ) { _fieldOfView = f; }; + void setAspectRatio ( float a ) { _aspectRatio = a; }; + void setNearClip ( float n ) { _nearClip = n; }; + void setFarClip ( float f ) { _farClip = f; }; + void setEyeOffsetPosition (const glm::vec3& p) { _eyeOffsetPosition = p; }; + void setEyeOffsetOrientation (const glm::quat& o) { _eyeOffsetOrientation = o; }; // getters for lens attributes diff --git a/voxel-server/src/VoxelAgentData.cpp b/voxel-server/src/VoxelAgentData.cpp index 082fc5e7fc..289b1161e6 100644 --- a/voxel-server/src/VoxelAgentData.cpp +++ b/voxel-server/src/VoxelAgentData.cpp @@ -48,7 +48,7 @@ bool VoxelAgentData::updateCurrentViewFrustum() { ViewFrustum newestViewFrustum; // get position and orientation details from the camera newestViewFrustum.setPosition(getCameraPosition()); - newestViewFrustum.setOrientation(getCameraDirection(), getCameraUp(), getCameraRight()); + newestViewFrustum.setOrientation(getCameraOrientation()); // Also make sure it's got the correct lens details from the camera newestViewFrustum.setFieldOfView(getCameraFov()); From ddf4d7c748fb1bc6ca7389c839bd249264fae1be Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 May 2013 09:59:53 -0700 Subject: [PATCH 02/73] removed extra comment --- libraries/avatars/src/AvatarData.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index fa0a8d1e20..b5ef015c7b 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -108,7 +108,6 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, _chatMessage.data(), _chatMessage.size() * sizeof(char)); destinationBuffer += _chatMessage.size() * sizeof(char); - // voxel sending features... // voxel sending features... unsigned char wantItems = 0; if (_wantResIn) { setAtBit(wantItems,WANT_RESIN_AT_BIT); } From 04f4e499e131c88a74cb66ecc96dc71ee86c8cbf Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 May 2013 14:10:51 -0700 Subject: [PATCH 03/73] Optimize wire-format for AvatarData - moved HandState into semi-nibble in bitItems - moved KeyState into semi-nibble in bitItems - moved AudioLoudness into scaled float stored as byte - overall savings - 5 bytes --- interface/src/AvatarTouch.h | 2 +- libraries/avatars/src/AvatarData.cpp | 72 ++++++++++++++++------------ libraries/avatars/src/AvatarData.h | 12 ++++- libraries/shared/src/SharedUtil.cpp | 9 ++++ libraries/shared/src/SharedUtil.h | 4 ++ 5 files changed, 66 insertions(+), 33 deletions(-) diff --git a/interface/src/AvatarTouch.h b/interface/src/AvatarTouch.h index 2111c0ecf1..cc4d21ae82 100644 --- a/interface/src/AvatarTouch.h +++ b/interface/src/AvatarTouch.h @@ -12,7 +12,7 @@ enum AvatarHandState { - HAND_STATE_NULL = -1, + HAND_STATE_NULL = 0, HAND_STATE_OPEN, HAND_STATE_GRASPING, HAND_STATE_POINTING, diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index b5ef015c7b..1c126b7587 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -83,13 +83,8 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, &_headData->_lookAtPosition, sizeof(_headData->_lookAtPosition)); destinationBuffer += sizeof(_headData->_lookAtPosition); - // Hand State (0 = not grabbing, 1 = grabbing) - memcpy(destinationBuffer, &_handState, sizeof(char)); - destinationBuffer += sizeof(char); - // Instantaneous audio loudness (used to drive facial animation) - memcpy(destinationBuffer, &_audioLoudness, sizeof(float)); - destinationBuffer += sizeof(float); + destinationBuffer += packFloatToByte(destinationBuffer, std::min(MAX_AUDIO_LOUDNESS, _audioLoudness), MAX_AUDIO_LOUDNESS); // camera details memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition)); @@ -100,20 +95,22 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraNearClip); destinationBuffer += packClipValueToTwoByte(destinationBuffer, _cameraFarClip); - // key state - *destinationBuffer++ = _keyState; - // chat message *destinationBuffer++ = _chatMessage.size(); memcpy(destinationBuffer, _chatMessage.data(), _chatMessage.size() * sizeof(char)); destinationBuffer += _chatMessage.size() * sizeof(char); - // voxel sending features... - unsigned char wantItems = 0; - if (_wantResIn) { setAtBit(wantItems,WANT_RESIN_AT_BIT); } - if (_wantColor) { setAtBit(wantItems,WANT_COLOR_AT_BIT); } - if (_wantDelta) { setAtBit(wantItems,WANT_DELTA_AT_BIT); } - *destinationBuffer++ = wantItems; + // 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); } + + // key state + setSemiNibbleAt(bitItems,KEY_STATE_START_BIT,_keyState); + // hand state + setSemiNibbleAt(bitItems,HAND_STATE_START_BIT,_handState); + *destinationBuffer++ = bitItems; return destinationBuffer - bufferStart; } @@ -162,18 +159,13 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { // Hand Position memcpy(&_handPosition, sourceBuffer, sizeof(float) * 3); sourceBuffer += sizeof(float) * 3; - + // Lookat Position memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition)); sourceBuffer += sizeof(_headData->_lookAtPosition); - - // Hand State - memcpy(&_handState, sourceBuffer, sizeof(char)); - sourceBuffer += sizeof(char); - + // Instantaneous audio loudness (used to drive facial animation) - memcpy(&_audioLoudness, sourceBuffer, sizeof(float)); - sourceBuffer += sizeof(float); + sourceBuffer += unpackFloatFromByte(sourceBuffer, _audioLoudness, MAX_AUDIO_LOUDNESS); // camera details memcpy(&_cameraPosition, sourceBuffer, sizeof(_cameraPosition)); @@ -184,20 +176,23 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraNearClip); sourceBuffer += unpackClipValueFromTwoByte(sourceBuffer,_cameraFarClip); - // key state - _keyState = (KeyState)*sourceBuffer++; - // the rest is a chat message int chatMessageSize = *sourceBuffer++; _chatMessage = string((char*)sourceBuffer, chatMessageSize); sourceBuffer += chatMessageSize * sizeof(char); // voxel sending features... - unsigned char wantItems = 0; - wantItems = (unsigned char)*sourceBuffer++; - _wantResIn = oneAtBit(wantItems,WANT_RESIN_AT_BIT); - _wantColor = oneAtBit(wantItems,WANT_COLOR_AT_BIT); - _wantDelta = oneAtBit(wantItems,WANT_DELTA_AT_BIT); + 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); + + // key state, stored as a semi-nibble in the bitItems + _keyState = (KeyState)getSemiNibbleAt(bitItems,KEY_STATE_START_BIT); + + // hand state, stored as a semi-nibble in the bitItems + _handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT); return sourceBuffer - startPosition; } @@ -310,3 +305,18 @@ int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue) { } return sizeof(holder); } + +int packFloatToByte(unsigned char* buffer, float value, float scaleBy) { + unsigned char holder; + const float CONVERSION_RATIO = (255 / scaleBy); + holder = floorf(value * CONVERSION_RATIO); + memcpy(buffer, &holder, sizeof(holder)); + return sizeof(holder); +} + +int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy) { + unsigned char holder; + memcpy(&holder, buffer, sizeof(holder)); + value = ((float)holder / (float) 255) * scaleBy; + return sizeof(holder); +} diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index d86cc6078b..04bc7e6ad5 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -20,10 +20,15 @@ const int WANT_RESIN_AT_BIT = 0; 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 float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation + enum KeyState { - NO_KEY_DOWN, + NO_KEY_DOWN = 0, INSERT_KEY_DOWN, DELETE_KEY_DOWN }; @@ -157,4 +162,9 @@ int unpackFloatRatioFromTwoByte(unsigned char* buffer, float& ratio); int packClipValueToTwoByte(unsigned char* buffer, float clipValue); int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue); +// Positive floats that don't need to be very precise +int packFloatToByte(unsigned char* buffer, float value, float scaleBy); +int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy); + + #endif /* defined(__hifi__AvatarData__) */ diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index ca31cdd994..10967ea3e7 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -101,6 +101,15 @@ void setAtBit(unsigned char& byte, int bitIndex) { byte += (1 << (7 - bitIndex)); } +int getSemiNibbleAt(unsigned char& byte, int bitIndex) { + return (byte >> (7 - bitIndex) & 3); // semi-nibbles store 00, 01, 10, or 11 +} + +void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { + assert(value <= 3 && value >= 0); + byte += ((value & 3) << (7 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 +} + void switchToResourcesParentIfRequired() { #ifdef __APPLE__ diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 9d858f11e0..75c00c71f7 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -53,6 +53,10 @@ int numberOfOnes(unsigned char byte); bool oneAtBit(unsigned char byte, int bitIndex); void setAtBit(unsigned char& byte, int bitIndex); +int getSemiNibbleAt(unsigned char& byte, int bitIndex); +void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value); + + void switchToResourcesParentIfRequired(); void loadRandomIdentifier(unsigned char* identifierBuffer, int numBytes); From b3045ea6811de31fd500924b78aa45dc255619af Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 May 2013 16:11:07 -0700 Subject: [PATCH 04/73] working on handPosition optimizations --- libraries/avatars/src/AvatarData.cpp | 109 +++++++++++++++++++++++++-- libraries/avatars/src/AvatarData.h | 3 + 2 files changed, 107 insertions(+), 5 deletions(-) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 1c126b7587..7baee5f06a 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -75,8 +75,16 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { memcpy(destinationBuffer, &_headData->_leanForward, sizeof(_headData->_leanForward)); destinationBuffer += sizeof(_headData->_leanForward); - // Hand Position - memcpy(destinationBuffer, &_handPosition, sizeof(float) * 3); + // Hand Position - is relative to body position + glm::vec3 handPositionRelative = _handPosition - _position; + memcpy(destinationBuffer, &handPositionRelative, sizeof(float) * 3); + + printf("handPositionRelative=%f,%f,%f\n",handPositionRelative.x, handPositionRelative.y, handPositionRelative.z); + printf("_handPosition=%f,%f,%f\n",_handPosition.x, _handPosition.y, _handPosition.z); + printf("_position=%f,%f,%f\n",_position.x, _position.y, _position.z); + +packVec3ToBytes(NULL, handPositionRelative, -1.0f , 1.0f, 4); + destinationBuffer += sizeof(float) * 3; // Lookat Position @@ -156,10 +164,15 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { memcpy(&_headData->_leanForward, sourceBuffer, sizeof(_headData->_leanForward)); sourceBuffer += sizeof(_headData->_leanForward); - // Hand Position - memcpy(&_handPosition, sourceBuffer, sizeof(float) * 3); + // Hand Position - is relative to body position + glm::vec3 handPositionRelative; + memcpy(&handPositionRelative, sourceBuffer, sizeof(float) * 3); + _handPosition = _position + handPositionRelative; sourceBuffer += sizeof(float) * 3; - + printf("handPositionRelative=%f,%f,%f\n",handPositionRelative.x, handPositionRelative.y, handPositionRelative.z); + printf("_handPosition=%f,%f,%f\n",_handPosition.x, _handPosition.y, _handPosition.z); + printf("_position=%f,%f,%f\n",_position.x, _position.y, _position.z); + // Lookat Position memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition)); sourceBuffer += sizeof(_headData->_lookAtPosition); @@ -320,3 +333,89 @@ int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy) { value = ((float)holder / (float) 255) * scaleBy; return sizeof(holder); } + +int packVec3ToBytes(unsigned char* buffer, const glm::vec3& vec, float min, float max, int bytes) { + const int ITEMS_IN_VEC3 = 3; + const int BITS_IN_BYTE = 8; + const int BYTE_MASK = 0xff; + assert(bytes < sizeof(double) * ITEMS_IN_VEC3); + unsigned char holder[bytes]; + memset(&holder, 0, bytes); + + int bitsTotal = bytes * BITS_IN_BYTE; + int bitsPerItem = floor(bitsTotal / ITEMS_IN_VEC3); + long maxEncodedPerItem = powf(2, bitsPerItem) - 1; // must be a better way to get this + float scaleBy = (max - min); + float conversionRatio = (maxEncodedPerItem / scaleBy); + +printf("bitsTotal=%d\n", bitsTotal); +printf("bitsPerItem=%d\n", bitsPerItem); +printf("maxEncodedPerItem=%ld\n", maxEncodedPerItem); +printf("scaleBy=%f\n", scaleBy); +printf("conversionRatio=%f\n", conversionRatio); + + int bitInByte = 0; + int byteInHolder = 0; + long encodedItem = 0; + int leftShiftThisByte = 0; + + for (int i = 0; i < ITEMS_IN_VEC3; i++) { + +printf(">>> item=%d\n", i); +printf("vec[item]=%f\n", vec[i]); + + long encodedItemMask = maxEncodedPerItem; + encodedItem = floorf((vec[i] - min) * conversionRatio); + +printf("encodedItem=%ld\n", encodedItem); +printf("encodedItemMask=%ld\n", encodedItemMask); +printf("leftShiftThisByte=%d\n", leftShiftThisByte); + + for (int bitsInThisItem = 0; bitsInThisItem < bitsPerItem; ) { + +printf(">>> bitsInThisItem=%d\n", bitsInThisItem); + + unsigned char thisBytePortion = (encodedItemMask << leftShiftThisByte) & BYTE_MASK; + +printf("thisBytePortion=%d\n", (int)thisBytePortion); + + unsigned char thisByteValue = (encodedItem << leftShiftThisByte) & thisBytePortion; + +printf("thisByteValue=%d\n", (int)thisByteValue); + + holder[byteInHolder] |= thisByteValue; + +printf("after byte %d: ", byteInHolder); +outputBufferBits((unsigned char*)&holder, bytes); + + +///////not handling this correctly... second portion of second item is not moving to 3rd byte... + + leftShiftThisByte = 0; // reset after first time; + int numberOfBitsInThisByte = numberOfOnes(thisBytePortion); + bitsInThisItem += numberOfBitsInThisByte; + if (numberOfBitsInThisByte == 8) { + byteInHolder++; + encodedItemMask = encodedItemMask >> numberOfBitsInThisByte; + encodedItem = encodedItem >> numberOfBitsInThisByte; + } else { + leftShiftThisByte = numberOfBitsInThisByte; + } +printf("numberOfBitsInThisByte=%d\n", numberOfBitsInThisByte); +printf("AFTER bitsInThisItem=%d\n", bitsInThisItem); +printf("AFTER encodedItem=%ld\n", encodedItem); +printf("AFTER encodedItemMask=%ld\n", encodedItemMask); + } + } + + printf("done: "); + outputBufferBits((unsigned char*)&holder, bytes); + + //memcpy(buffer, &holder, sizeof(holder)); + return sizeof(holder); +} + +int unpackVec3FromBytes(unsigned char* buffer, glm::vec3& vec, float min, float max, int bytes) { + unsigned char holder[bytes]; + return sizeof(holder); +} diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 04bc7e6ad5..b530fe285d 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -166,5 +166,8 @@ int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue); int packFloatToByte(unsigned char* buffer, float value, float scaleBy); int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy); +int unpackVec3FromBytes(unsigned char* buffer, glm::vec3& vec, float min, float max, int bytes); +int packVec3ToBytes(unsigned char* buffer, const glm::vec3& vec, float min, float max, int bytes); + #endif /* defined(__hifi__AvatarData__) */ From d1d2e75143b110bbedd0e843fa0d898b716e4b69 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 28 May 2013 19:00:02 -0700 Subject: [PATCH 05/73] first cut at export and import of voxels --- interface/src/Application.cpp | 40 +++++++++++++++++++++++++++++- interface/src/Application.h | 5 +++- interface/src/VoxelSystem.cpp | 12 +++++++++ interface/src/VoxelSystem.h | 2 ++ libraries/voxels/src/VoxelTree.cpp | 11 +++++--- libraries/voxels/src/VoxelTree.h | 4 +-- voxel-server/src/main.cpp | 2 +- 7 files changed, 68 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index a0979eb4b9..b18a0095e7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -853,7 +854,10 @@ void Application::idle() { // red indicates deletion _mouseVoxel.red = 255; _mouseVoxel.green = _mouseVoxel.blue = 0; - + } else if (_selectVoxelMode->isChecked()) { + // yellow indicates deletion + _mouseVoxel.red = _mouseVoxel.green = 255; + _mouseVoxel.blue = 0; } else { // _addVoxelMode->isChecked() || _colorVoxelMode->isChecked() QColor paintColor = _voxelPaintColor->data().value(); _mouseVoxel.red = paintColor.red(); @@ -1136,6 +1140,35 @@ void Application::chooseVoxelPaintColor() { // restore the main window's active state _window->activateWindow(); } + +void Application::exportVoxels() { + QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), "~/voxels.hio2", + tr("High Fidelity Voxel Files (*.hio2)")); + QByteArray fileNameAscii = fileNameString.toAscii(); + const char* fileName = fileNameAscii.data(); + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + printf("exportVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, + _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (selectedNode) { + selectedNode->printDebugDetails("selected voxel"); + } + _voxels.writeToFileV2(fileName,selectedNode); +} + +void Application::importVoxels() { + QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), "~", tr("High Fidelity Voxel Files (*.hio2)")); + QByteArray fileNameAscii = fileNameString.toAscii(); + const char* fileName = fileNameAscii.data(); + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + printf("importVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, + _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (selectedNode) { + selectedNode->printDebugDetails("selected voxel"); + } + + // not yet supported!!! + _voxels.readFromFileV2(fileName,selectedNode); +} void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); @@ -1202,6 +1235,9 @@ void Application::initMenu() { (_colorVoxelMode = voxelMenu->addAction( "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_3))->setCheckable(true); _voxelModeActions->addAction(_colorVoxelMode); + (_selectVoxelMode = voxelMenu->addAction( + "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_8))->setCheckable(true); + _voxelModeActions->addAction(_selectVoxelMode); voxelMenu->addAction("Place Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::Key_4); voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), Qt::Key_5); @@ -1212,6 +1248,8 @@ void Application::initMenu() { _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); (_destructiveAddVoxel = voxelMenu->addAction("Create Voxel is Destructive"))->setCheckable(true); + voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); + voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); QMenu* frustumMenu = menuBar->addMenu("Frustum"); (_frustumOn = frustumMenu->addAction("Display Frustum"))->setCheckable(true); diff --git a/interface/src/Application.h b/interface/src/Application.h index 35d49d275a..ed03708bd9 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -99,7 +99,9 @@ private slots: void decreaseVoxelSize(); void increaseVoxelSize(); void chooseVoxelPaintColor(); - + void exportVoxels(); + void importVoxels(); + private: void initMenu(); @@ -155,6 +157,7 @@ private: QAction* _addVoxelMode; // Whether add voxel mode is enabled QAction* _deleteVoxelMode; // Whether delete voxel mode is enabled QAction* _colorVoxelMode; // Whether color voxel mode is enabled + QAction* _selectVoxelMode; // Whether select voxel mode is enabled QAction* _voxelPaintColor; // The color with which to paint voxels QAction* _destructiveAddVoxel; // when doing voxel editing do we want them to be destructive QAction* _frustumOn; // Whether or not to display the debug view frustum diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index ea8787a902..2a0a7e7a7a 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -70,6 +70,18 @@ void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) setupNewVoxelsForDrawing(); } +void VoxelSystem::writeToFileV2(const char* filename, VoxelNode* node) const { + _tree->writeToFileV2(filename, node); +} + +bool VoxelSystem::readFromFileV2(const char* filename, VoxelNode* node) { + bool result = _tree->readFromFileV2(filename, node); + if (result) { + setupNewVoxelsForDrawing(); + } + return result; +} + long int VoxelSystem::getVoxelsCreated() { return _tree->voxelsCreated; } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 7bffb1d33c..1aeb66a7c6 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -44,6 +44,8 @@ public: void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); + void writeToFileV2(const char* filename, VoxelNode* node) const; + bool readFromFileV2(const char* filename, VoxelNode* node); long int getVoxelsCreated(); long int getVoxelsColored(); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 798b447d6c..89b584a541 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1105,7 +1105,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco return bytesAtThisLevel; } -bool VoxelTree::readFromFileV2(const char* fileName) { +bool VoxelTree::readFromFileV2(const char* fileName, VoxelNode* node) { std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate); if(file.is_open()) { printLog("loading file %s...\n", fileName); @@ -1126,7 +1126,7 @@ bool VoxelTree::readFromFileV2(const char* fileName) { return false; } -void VoxelTree::writeToFileV2(const char* fileName) const { +void VoxelTree::writeToFileV2(const char* fileName, VoxelNode* node) const { std::ofstream file(fileName, std::ios::out|std::ios::binary); @@ -1134,7 +1134,12 @@ void VoxelTree::writeToFileV2(const char* fileName) const { printLog("saving to file %s...\n", fileName); VoxelNodeBag nodeBag; - nodeBag.insert(rootNode); + // If we were given a specific node, start from there, otherwise start from root + if (node) { + nodeBag.insert(node); + } else { + nodeBag.insert(rootNode); + } static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static int bytesWritten = 0; diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 0643b1038e..5e56be5062 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -91,8 +91,8 @@ public: void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); // these will read/write files that match the wireformat, excluding the 'V' leading - void writeToFileV2(const char* filename) const; - bool readFromFileV2(const char* filename); + void writeToFileV2(const char* filename, VoxelNode* node = NULL) const; + bool readFromFileV2(const char* filename, VoxelNode* node = NULL); unsigned long getVoxelCount(); diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 1a93021f09..70f7ab8752 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -517,7 +517,7 @@ int main(int argc, const char * argv[]) { const char* INPUT_FILE = "-i"; const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE); if (voxelsFilename) { - randomTree.loadVoxelsFile(voxelsFilename,wantColorRandomizer); + randomTree.readFromFileV2(voxelsFilename); } // Check to see if the user passed in a command line option for setting packet send rate From eb675c8dd79d16ca17d2e6de7da0b129247fe82e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 29 May 2013 08:25:30 -0700 Subject: [PATCH 06/73] fix crash when no audio mixer available --- libraries/audio/src/AudioInjectionManager.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioInjectionManager.cpp b/libraries/audio/src/AudioInjectionManager.cpp index 275161730e..b49151616d 100644 --- a/libraries/audio/src/AudioInjectionManager.cpp +++ b/libraries/audio/src/AudioInjectionManager.cpp @@ -58,7 +58,10 @@ void* AudioInjectionManager::injectAudioViaThread(void* args) { // if we don't have an explicit destination socket then pull active socket for current audio mixer from agent list if (!_isDestinationSocketExplicit) { - _destinationSocket = *AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER)->getActiveSocket(); + Agent* audioMixer = AgentList::getInstance()->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); + if (audioMixer) { + _destinationSocket = *audioMixer->getActiveSocket(); + } } injector->injectAudio(_injectorSocket, &_destinationSocket); From 377fb1e936ef64670145d947b771bba1d0e1ad18 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 29 May 2013 12:06:58 -0700 Subject: [PATCH 07/73] latest copy and paste --- interface/src/Application.cpp | 35 +++++++++++++++----- interface/src/Application.h | 2 ++ interface/src/main.cpp | 14 ++++++++ libraries/shared/src/OctalCode.cpp | 51 ++++++++++++++++++++++++++++++ libraries/shared/src/OctalCode.h | 3 ++ libraries/voxels/src/VoxelTree.cpp | 27 +++++++++++++++- libraries/voxels/src/VoxelTree.h | 4 +++ 7 files changed, 127 insertions(+), 9 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 3908164890..95e3e5f1c1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1153,6 +1153,22 @@ void Application::importVoxels() { // not yet supported!!! _voxels.readFromFileV2(fileName,selectedNode); } + +void Application::copyVoxels() { + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + printf("copyVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (selectedNode) { + selectedNode->printDebugDetails("selected voxel"); + } +} + +void Application::pasteVoxels() { + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + printf("pasteVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (selectedNode) { + selectedNode->printDebugDetails("selected voxel"); + } +} void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); @@ -1211,29 +1227,32 @@ void Application::initMenu() { _voxelModeActions = new QActionGroup(this); _voxelModeActions->setExclusive(false); // exclusivity implies one is always checked (_addVoxelMode = voxelMenu->addAction( - "Add Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_1))->setCheckable(true); + "Add Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_A))->setCheckable(true); _voxelModeActions->addAction(_addVoxelMode); (_deleteVoxelMode = voxelMenu->addAction( - "Delete Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_2))->setCheckable(true); + "Delete Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_D))->setCheckable(true); _voxelModeActions->addAction(_deleteVoxelMode); (_colorVoxelMode = voxelMenu->addAction( - "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_3))->setCheckable(true); + "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_C))->setCheckable(true); _voxelModeActions->addAction(_colorVoxelMode); (_selectVoxelMode = voxelMenu->addAction( - "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::Key_8))->setCheckable(true); + "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_S))->setCheckable(true); _voxelModeActions->addAction(_selectVoxelMode); - voxelMenu->addAction("Place Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::Key_4); - voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), Qt::Key_5); - voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), Qt::Key_6); + voxelMenu->addAction("Place Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::SHIFT | Qt::Key_P); + voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), Qt::CTRL | Qt::SHIFT | Qt::Key_Minus); + voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), Qt::CTRL | Qt::SHIFT | Qt::Key_Plus); - _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), Qt::Key_7); + _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), + Qt::CTRL | Qt::SHIFT | Qt::Key_C); QColor paintColor(128, 128, 128); _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); (_destructiveAddVoxel = voxelMenu->addAction("Create Voxel is Destructive"))->setCheckable(true); voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); + voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C); + voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V); QMenu* frustumMenu = menuBar->addMenu("Frustum"); (_frustumOn = frustumMenu->addAction("Display Frustum"))->setCheckable(true); diff --git a/interface/src/Application.h b/interface/src/Application.h index ed03708bd9..57605f8cc5 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -101,6 +101,8 @@ private slots: void chooseVoxelPaintColor(); void exportVoxels(); void importVoxels(); + void copyVoxels(); + void pasteVoxels(); private: diff --git a/interface/src/main.cpp b/interface/src/main.cpp index ea915658af..5091eb9f4f 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -18,7 +18,21 @@ #include "Application.h" #include "Log.h" +#include + int main(int argc, const char * argv[]) { + + unsigned char test1[2] = {2, 0xE0 }; + unsigned char test2[2] = {2, 0xFC }; + + unsigned char* result1 = chopOctalCode((unsigned char*)&test1, 1); + + printOctalCode((unsigned char*)&test1); + printOctalCode(result1); + + unsigned char* result2 = chopOctalCode((unsigned char*)&test2, 1); + printOctalCode((unsigned char*)&test2); + printOctalCode(result2); timeval startup_time; gettimeofday(&startup_time, NULL); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index d218639882..b69136ddb6 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -168,3 +168,54 @@ OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB return result; } + +char getOctalCodeSectionValue(unsigned char* octalCode, int section) { + return sectionValue(octalCode + 1 + (3 * section / 8), (3 * section) % 8); +} + +void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectionValue) { + unsigned char* byteAt = octalCode + 1 + (3 * section / 8); + char bitInByte = (3 * section) % 8; + char shiftBy = 8 - bitInByte - 3; + const unsigned char UNSHIFTED_MASK = 0x03; + unsigned char shiftedMask; + unsigned char shiftedValue; + + + if (shiftBy >=0) { + shiftedMask = UNSHIFTED_MASK << shiftBy; + shiftedValue = sectionValue << shiftBy; + } else { + shiftedMask = UNSHIFTED_MASK >> -shiftBy; + shiftedValue = sectionValue >> -shiftBy; + } + + byteAt[0] = byteAt[0] & (shiftedMask | shiftedValue); + if (bitInByte >= 6) { + shiftBy = bitInByte + 1; + shiftedMask = UNSHIFTED_MASK << shiftBy; + shiftedValue = sectionValue << shiftBy; + + byteAt[1] = byteAt[1] & (shiftedMask | shiftedValue); + } +} + +unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels) { + int codeLength = numberOfThreeBitSectionsInCode(originalOctalCode); + unsigned char* newCode = NULL; + if (codeLength > chopLevels) { + int newLength = codeLength - chopLevels; + newCode = new unsigned char[newLength+1]; + *newCode = newLength; // set the length byte + + for (int section = chopLevels; section < codeLength; section++) { + char sectionValue = getOctalCodeSectionValue(originalOctalCode, section); + setOctalCodeSectionValue(newCode, section - chopLevels, sectionValue); + } + } + return newCode; +} + +unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode) { +} + diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index bf4a6ef699..bce7a066b9 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -17,6 +17,9 @@ bool isDirectParentOfChild(unsigned char *parentOctalCode, unsigned char * child int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode); unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber); +unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels); +unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode); + // Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return // but other than that these do the same thing. diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 01a9ace8b6..a0864964a2 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -53,7 +53,7 @@ VoxelTree::~VoxelTree() { // Recurses voxel tree calling the RecurseVoxelTreeOperation function for each node. // stops recursion if operation function returns false. void VoxelTree::recurseTreeWithOperation(RecurseVoxelTreeOperation operation, void* extraData) { - recurseNodeWithOperation(rootNode, operation,extraData); + recurseNodeWithOperation(rootNode, operation, extraData); } // Recurses voxel node with an operation function @@ -1165,3 +1165,28 @@ bool VoxelTree::countVoxelsOperation(VoxelNode* node, void* extraData) { (*(unsigned long*)extraData)++; return true; // keep going } + +void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot) { + + printLog("copySubTreeIntoNewTree()...\n"); + + VoxelNodeBag nodeBag; + // If we were given a specific node, start from there, otherwise start from root + nodeBag.insert(startNode); + + static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static + int bytesWritten = 0; + + while (!nodeBag.isEmpty()) { + 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); + + // ask destination tree to read the bitstream + destinationTree->readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS); + } + + +} diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index 5e56be5062..eccc4e0434 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -95,6 +95,9 @@ public: bool readFromFileV2(const char* filename, VoxelNode* node = NULL); unsigned long getVoxelCount(); + + void copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot); + void copyNodeIntoTree(VoxelNode* node); private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, @@ -107,6 +110,7 @@ private: bool deltaViewFrustum, const ViewFrustum* lastViewFrustum); static bool countVoxelsOperation(VoxelNode* node, void* extraData); + static bool copySubTreeIntoNewTreeOperation(VoxelNode* node, void* extraData); void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; From 46c6f2f9b5f3add89a29fb695a53401a68c5057f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 29 May 2013 15:02:28 -0700 Subject: [PATCH 08/73] latest copy paste --- interface/src/Application.cpp | 13 +++++++- interface/src/Application.h | 2 ++ interface/src/VoxelSystem.cpp | 9 ++++++ interface/src/VoxelSystem.h | 4 +++ interface/src/main.cpp | 13 -------- libraries/shared/src/OctalCode.cpp | 16 ++++++--- libraries/shared/src/OctalCode.h | 1 + libraries/voxels/src/VoxelTree.cpp | 52 ++++++++++++++++++++++++------ libraries/voxels/src/VoxelTree.h | 26 +++++++-------- 9 files changed, 95 insertions(+), 41 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 95e3e5f1c1..7f5eeccd76 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1159,6 +1159,7 @@ void Application::copyVoxels() { printf("copyVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { selectedNode->printDebugDetails("selected voxel"); + _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboardTree, true); } } @@ -1166,7 +1167,17 @@ void Application::pasteVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); printf("pasteVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { - selectedNode->printDebugDetails("selected voxel"); + //selectedNode->printDebugDetails("selected voxel"); + + // First, create a temporary Paste Tree + VoxelTree _temporaryPasteTree; + + // Create a destination node to paste into + _temporaryPasteTree.createVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s, 0, 0, 0); + + // Paste into the temporary tree + destinationNode = _temporaryPasteTree.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + _temporaryPasteTree.copyFromTreeIntoSubTree(&_clipboardTree, destinationNode); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 57605f8cc5..85d5d7ef43 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -184,6 +184,8 @@ private: Stars _stars; VoxelSystem _voxels; + VoxelTree _clipboardTree; // if I copy/paste + QByteArray _voxelsFilename; bool _wantToKillLocalVoxels; diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 2a0a7e7a7a..359e5b77af 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -1156,3 +1156,12 @@ void VoxelSystem::createSphere(float r,float xc, float yc, float zc, float s, bo _tree->createSphere(r, xc, yc, zc, s, solid, mode, destructive, debug); setupNewVoxelsForDrawing(); }; + +void VoxelSystem::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot) { + _tree->copySubTreeIntoNewTree(startNode, destinationTree, rebaseToRoot); +} + +void VoxelSystem::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode) { + _tree->copyFromTreeIntoSubTree(sourceTree, destinationNode); +} + diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 1aeb66a7c6..c15ba53ba0 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -85,6 +85,10 @@ public: void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive = false); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool destructive = false, bool debug = false); + + void copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot); + void copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode); + private: // disallow copying of VoxelSystem objects VoxelSystem(const VoxelSystem&); diff --git a/interface/src/main.cpp b/interface/src/main.cpp index 5091eb9f4f..8894e5bd7c 100644 --- a/interface/src/main.cpp +++ b/interface/src/main.cpp @@ -21,19 +21,6 @@ #include int main(int argc, const char * argv[]) { - - unsigned char test1[2] = {2, 0xE0 }; - unsigned char test2[2] = {2, 0xFC }; - - unsigned char* result1 = chopOctalCode((unsigned char*)&test1, 1); - - printOctalCode((unsigned char*)&test1); - printOctalCode(result1); - - unsigned char* result2 = chopOctalCode((unsigned char*)&test2, 1); - printOctalCode((unsigned char*)&test2); - printOctalCode(result2); - timeval startup_time; gettimeofday(&startup_time, NULL); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index b69136ddb6..f331545b33 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -170,14 +170,18 @@ OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB char getOctalCodeSectionValue(unsigned char* octalCode, int section) { - return sectionValue(octalCode + 1 + (3 * section / 8), (3 * section) % 8); + int startAtByte = 1 + (3 * section / 8); + char startIndexInByte = (3 * section) % 8; + unsigned char* startByte = octalCode + startAtByte; + + return sectionValue(startByte, startIndexInByte); } void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectionValue) { unsigned char* byteAt = octalCode + 1 + (3 * section / 8); char bitInByte = (3 * section) % 8; char shiftBy = 8 - bitInByte - 3; - const unsigned char UNSHIFTED_MASK = 0x03; + const unsigned char UNSHIFTED_MASK = 0x07; unsigned char shiftedMask; unsigned char shiftedValue; @@ -190,13 +194,17 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio shiftedValue = sectionValue >> -shiftBy; } - byteAt[0] = byteAt[0] & (shiftedMask | shiftedValue); + unsigned char oldValue = *byteAt & ~shiftedMask; + unsigned char newValue = oldValue | shiftedValue; + *byteAt = newValue; if (bitInByte >= 6) { shiftBy = bitInByte + 1; shiftedMask = UNSHIFTED_MASK << shiftBy; shiftedValue = sectionValue << shiftBy; - byteAt[1] = byteAt[1] & (shiftedMask | shiftedValue); + oldValue = byteAt[1] & ~shiftedMask; + newValue = oldValue | shiftedValue; + byteAt[1] = newValue; } } diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index bce7a066b9..1849989cc3 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -19,6 +19,7 @@ unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels); unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode); +int numberOfThreeBitSectionsInCode(unsigned char * octalCode); // Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index a0864964a2..562cfcc88c 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -212,10 +212,15 @@ int VoxelTree::readNodeData(VoxelNode* destinationNode, unsigned char* nodeData, } void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, - bool includeColor, bool includeExistsBits) { + bool includeColor, bool includeExistsBits, VoxelNode* destinationNode) { int bytesRead = 0; unsigned char* bitstreamAt = bitstream; + // If destination node is not included, set it to root + if (!destinationNode) { + destinationNode = rootNode; + } + _nodesChangedFromBitstream = 0; // Keep looping through the buffer calling readNodeData() this allows us to pack multiple root-relative Octal codes @@ -223,14 +228,14 @@ void VoxelTree::readBitstreamToTree(unsigned char * bitstream, unsigned long int // if there are more bytes after that, it's assumed to be another root relative tree while (bitstreamAt < bitstream + bufferSizeBytes) { - VoxelNode* bitstreamRootNode = nodeForOctalCode(rootNode, (unsigned char *)bitstreamAt, NULL); + VoxelNode* bitstreamRootNode = nodeForOctalCode(destinationNode, (unsigned char *)bitstreamAt, NULL); if (*bitstreamAt != *bitstreamRootNode->getOctalCode()) { // if the octal code returned is not on the same level as // the code being searched for, we have VoxelNodes to create // Note: we need to create this node relative to root, because we're assuming that the bitstream for the initial // octal code is always relative to root! - bitstreamRootNode = createMissingNode(rootNode, (unsigned char*) bitstreamAt); + bitstreamRootNode = createMissingNode(destinationNode, (unsigned char*) bitstreamAt); if (bitstreamRootNode->isDirty()) { _isDirty = true; _nodesChangedFromBitstream++; @@ -862,7 +867,7 @@ int VoxelTree::searchForColoredNodesRecursion(int maxSearchLevel, int& currentSe int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { + int chopLevels, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { // How many bytes have we written so far at this level; int bytesWritten = 0; @@ -882,7 +887,7 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned int currentEncodeLevel = 0; int childBytesWritten = encodeTreeBitstreamRecursion(maxEncodeLevel, currentEncodeLevel, node, outputBuffer, availableBytes, - bag, viewFrustum, includeColor, includeExistsBits, + bag, viewFrustum, includeColor, includeExistsBits, chopLevels, deltaViewFrustum, lastViewFrustum); // if childBytesWritten == 1 then something went wrong... that's not possible @@ -907,7 +912,7 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { + int chopLevels, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const { // How many bytes have we written so far at this level; int bytesAtThisLevel = 0; @@ -1062,7 +1067,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco int thisLevel = currentEncodeLevel; int childTreeBytesOut = encodeTreeBitstreamRecursion(maxEncodeLevel, thisLevel, childNode, outputBuffer, availableBytes, bag, - viewFrustum, includeColor, includeExistsBits, + viewFrustum, includeColor, includeExistsBits, chopLevels, deltaViewFrustum, lastViewFrustum); // if the child wrote 0 bytes, it means that nothing below exists or was in view, or we ran out of space, @@ -1173,6 +1178,12 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat VoxelNodeBag nodeBag; // If we were given a specific node, start from there, otherwise start from root nodeBag.insert(startNode); + + int chopLevels = 0; + + if (rebaseToRoot) { + chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); + } static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static int bytesWritten = 0; @@ -1182,11 +1193,32 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat // 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); + MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS, chopLevels); // ask destination tree to read the bitstream destinationTree->readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS); } - - } + +void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode) { + printLog("copyFromTreeIntoSubTree()...\n"); + + VoxelNodeBag nodeBag; + // If we were given a specific node, start from there, otherwise start from root + nodeBag.insert(sourceTree->rootNode); + + static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static + int bytesWritten = 0; + + while (!nodeBag.isEmpty()) { + 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); + + // ask destination tree to read the bitstream + readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS); + } +} + diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index eccc4e0434..a2302f6cc7 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -44,19 +44,20 @@ public: VoxelTree(bool shouldReaverage = false); ~VoxelTree(); - VoxelNode *rootNode; + VoxelNode* rootNode; int leavesWrittenToBitstream; void eraseAllVoxels(); - void processRemoveVoxelBitstream(unsigned char * bitstream, int bufferSizeBytes); - void readBitstreamToTree(unsigned char * bitstream, unsigned long int bufferSizeBytes, - bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS); - void readCodeColorBufferToTree(unsigned char *codeColorBuffer, bool destructive = false); - void deleteVoxelCodeFromTree(unsigned char *codeBuffer, bool stage = ACTUALLY_DELETE, + void processRemoveVoxelBitstream(unsigned char* bitstream, int bufferSizeBytes); + void readBitstreamToTree(unsigned char* bitstream, unsigned long int bufferSizeBytes, + bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, + VoxelNode* destinationNode = NULL); + void readCodeColorBufferToTree(unsigned char* codeColorBuffer, bool destructive = false); + void deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage = ACTUALLY_DELETE, bool collapseEmptyTrees = DONT_COLLAPSE); - void printTreeForDebugging(VoxelNode *startNode); - void reaverageVoxelColors(VoxelNode *startNode); + void printTreeForDebugging(VoxelNode* startNode); + void reaverageVoxelColors(VoxelNode* startNode); void deleteVoxelAt(float x, float y, float z, float s, bool stage = false); VoxelNode* getVoxelAt(float x, float y, float z, float s) const; @@ -70,7 +71,7 @@ public: 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, + bool includeColor = WANT_COLOR, bool includeExistsBits = WANT_EXISTS_BITS, int chopLevels = 0, bool deltaViewFrustum = false, const ViewFrustum* lastViewFrustum = NULL) const; int searchForColoredNodes(int maxSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, @@ -97,20 +98,19 @@ public: unsigned long getVoxelCount(); void copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot); - void copyNodeIntoTree(VoxelNode* node); + void copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode); private: int encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEncodeLevel, VoxelNode* node, unsigned char* outputBuffer, int availableBytes, VoxelNodeBag& bag, - const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, - bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const; + const ViewFrustum* viewFrustum, bool includeColor, bool includeExistsBits, + int chopLevels, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum) const; int searchForColoredNodesRecursion(int maxSearchLevel, int& currentSearchLevel, VoxelNode* node, const ViewFrustum& viewFrustum, VoxelNodeBag& bag, bool deltaViewFrustum, const ViewFrustum* lastViewFrustum); static bool countVoxelsOperation(VoxelNode* node, void* extraData); - static bool copySubTreeIntoNewTreeOperation(VoxelNode* node, void* extraData); void recurseNodeWithOperation(VoxelNode* node, RecurseVoxelTreeOperation operation, void* extraData); VoxelNode* nodeForOctalCode(VoxelNode* ancestorNode, unsigned char* needleCode, VoxelNode** parentOfFoundNode) const; From e5e200345b93bcd42af1eb2102e7857e0f383470 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 31 May 2013 11:52:18 -0700 Subject: [PATCH 09/73] more work on copy and paste --- interface/src/Application.cpp | 67 ++++++++++++++++++++++++++---- interface/src/Application.h | 2 + libraries/shared/src/OctalCode.cpp | 21 +++++++++- libraries/shared/src/OctalCode.h | 7 ++-- libraries/voxels/src/VoxelTree.cpp | 22 ++++++++-- 5 files changed, 102 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b6aba80c06..5395bfa54f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include "Application.h" #include "InterfaceConfig.h" @@ -1319,26 +1320,76 @@ void Application::copyVoxels() { if (selectedNode) { selectedNode->printDebugDetails("selected voxel"); _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboardTree, true); + + // debug tree + _clipboardTree.printTreeForDebugging(_clipboardTree.rootNode); } } +const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500; +struct SendVoxelsOperataionArgs { + unsigned char* newBaseOctCode; + unsigned char messageBuffer[MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE]; + int bufferInUse; + +}; + void Application::pasteVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); printf("pasteVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { //selectedNode->printDebugDetails("selected voxel"); - // First, create a temporary Paste Tree - VoxelTree _temporaryPasteTree; + // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to + // the server as an set voxel message, this will also rebase the voxels to the new location + SendVoxelsOperataionArgs args; + args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; + unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; + *sequenceAt = 0; + args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence + args.newBaseOctCode = selectedNode->getOctalCode(); + _clipboardTree.recurseTreeWithOperation(sendVoxelsOperataion, &args); - // Create a destination node to paste into - _temporaryPasteTree.createVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s, 0, 0, 0); - - // Paste into the temporary tree - destinationNode = _temporaryPasteTree.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - _temporaryPasteTree.copyFromTreeIntoSubTree(&_clipboardTree, destinationNode); + // If we have voxels left in the packet, then send the packet + if (args.bufferInUse > 1) { + AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); + } } } + +bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { + SendVoxelsOperataionArgs* args = (SendVoxelsOperataionArgs*)extraData; + if (node->isColored()) { + const int SIZE_OF_COLOR_DATA = 3; + const int RED_INDEX = 0; + const int GREEN_INDEX = 1; + const int BLUE_INDEX = 2; + unsigned char* nodeOctalCode = node->getOctalCode(); + printOctalCode(nodeOctalCode); + unsigned char* rebasedCodeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true); + printOctalCode(rebasedCodeColorBuffer); + int rebasedCodeLength = numberOfThreeBitSectionsInCode(rebasedCodeColorBuffer); + int bytesInRebasedCode = bytesRequiredForCodeLength(rebasedCodeLength); + int codeAndColorLength = bytesInRebasedCode + SIZE_OF_COLOR_DATA; + + // copy the colors over + rebasedCodeColorBuffer[bytesInRebasedCode + RED_INDEX ] = node->getColor()[RED_INDEX ]; + rebasedCodeColorBuffer[bytesInRebasedCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX]; + rebasedCodeColorBuffer[bytesInRebasedCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ]; + + // if we have room don't have room in the buffer, then send the previously generated message first + if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { + AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL, 1); + args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(int); // reset to command + sequence + } + + // copy this node's code color details into our buffer. + memcpy(&args->messageBuffer[args->bufferInUse], rebasedCodeColorBuffer, codeAndColorLength); + args->bufferInUse += codeAndColorLength; + } + return true; // keep going +} + void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); diff --git a/interface/src/Application.h b/interface/src/Application.h index 9a6d02ecc0..7761d9a84b 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -160,6 +160,8 @@ private slots: void pasteVoxels(); private: + + static bool sendVoxelsOperataion(VoxelNode* node, void* extraData); void initMenu(); void updateFrustumRenderModeAction(); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index f331545b33..150789bec8 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -224,6 +224,25 @@ unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels) { return newCode; } -unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode) { +unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode, bool includeColorSpace) { + int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); + int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); + int newCodeLength = newParentCodeLength + oldCodeLength; + const int COLOR_SPACE = 3; + int bufferLength = newCodeLength + (includeColorSpace ? COLOR_SPACE : 0); + unsigned char* newCode = new unsigned char[bufferLength]; + *newCode = newCodeLength; // set the length byte + + // copy parent code section first + for (int sectionFromParent = 0; sectionFromParent < newParentCodeLength; sectionFromParent++) { + char sectionValue = getOctalCodeSectionValue(newParentOctalCode, sectionFromParent); + setOctalCodeSectionValue(newCode, sectionFromParent, sectionValue); + } + // copy original code section next + for (int sectionFromOriginal = 0; sectionFromOriginal < oldCodeLength; sectionFromOriginal++) { + char sectionValue = getOctalCodeSectionValue(originalOctalCode, sectionFromOriginal); + setOctalCodeSectionValue(newCode, sectionFromOriginal + newParentCodeLength, sectionValue); + } + return newCode; } diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index 1849989cc3..bfed24a87c 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -16,11 +16,10 @@ int bytesRequiredForCodeLength(unsigned char threeBitCodes); bool isDirectParentOfChild(unsigned char *parentOctalCode, unsigned char * childOctalCode); int branchIndexWithDescendant(unsigned char * ancestorOctalCode, unsigned char * descendantOctalCode); unsigned char * childOctalCode(unsigned char * parentOctalCode, char childNumber); - -unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels); -unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode); int numberOfThreeBitSectionsInCode(unsigned char * octalCode); - +unsigned char* chopOctalCode(unsigned char* originalOctalCode, int chopLevels); +unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* newParentOctalCode, + bool includeColorSpace = false); // Note: copyFirstVertexForCode() is preferred because it doesn't allocate memory for the return // but other than that these do the same thing. diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 562cfcc88c..704c15e4db 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -878,9 +878,22 @@ int VoxelTree::encodeTreeBitstream(int maxEncodeLevel, VoxelNode* node, unsigned } // write the octal code - int codeLength = bytesRequiredForCodeLength(*node->getOctalCode()); - memcpy(outputBuffer,node->getOctalCode(),codeLength); - + int codeLength; + if (chopLevels) { + unsigned char* newCode = chopOctalCode(node->getOctalCode(), chopLevels); + if (newCode) { + codeLength = bytesRequiredForCodeLength(numberOfThreeBitSectionsInCode(newCode)); + memcpy(outputBuffer, newCode, codeLength); + delete newCode; + } else { + codeLength = 1; // chopped to root! + *outputBuffer = 0; // root + } + } else { + codeLength = bytesRequiredForCodeLength(*node->getOctalCode()); + memcpy(outputBuffer, node->getOctalCode(), codeLength); + } + outputBuffer += codeLength; // move the pointer bytesWritten += codeLength; // keep track of byte count availableBytes -= codeLength; // keep track or remaining space @@ -1183,6 +1196,7 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat if (rebaseToRoot) { chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); + printLog("copySubTreeIntoNewTree()...rebaseToRoot=true, chopLevels=%d\n", chopLevels); } static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static @@ -1218,7 +1232,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); // ask destination tree to read the bitstream - readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS); + readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS,destinationNode); } } From e4bc7af6b4a95a52dde268a2f09a5ef40eca7a38 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 31 May 2013 14:52:29 -0700 Subject: [PATCH 10/73] Working on avatar voxels. --- interface/src/Application.cpp | 9 +++-- interface/src/Application.h | 1 + interface/src/Avatar.cpp | 20 ++++++++++- interface/src/Avatar.h | 3 ++ interface/src/VoxelSystem.cpp | 63 +++++++++++++++++++---------------- interface/src/VoxelSystem.h | 15 ++++----- 6 files changed, 68 insertions(+), 43 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4dd3dba178..12af31234b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -156,8 +156,6 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _window->setWindowTitle("Interface"); printLog("Interface Startup:\n"); - _voxels.setViewFrustum(&_viewFrustum); - unsigned int listenPort = AGENT_SOCKET_LISTEN_PORT; const char** constArgv = const_cast(argv); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); @@ -1417,8 +1415,6 @@ void Application::initDisplay() { void Application::init() { _voxels.init(); - _voxels.setViewerAvatar(&_myAvatar); - _voxels.setCamera(&_myCamera); _environment.init(); @@ -1429,6 +1425,7 @@ void Application::init() { _stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0); + _myAvatar.init(); _myAvatar.setPosition(START_LOCATION); _myCamera.setMode(CAMERA_MODE_THIRD_PERSON ); _myCamera.setModeShiftRate(1.0f); @@ -2298,7 +2295,9 @@ QAction* Application::checkedVoxelModeAction() const { void Application::attachNewHeadToAgent(Agent* newAgent) { if (newAgent->getLinkedData() == NULL) { - newAgent->setLinkedData(new Avatar(newAgent)); + Avatar* newAvatar = new Avatar(newAgent); + newAvatar->init(); + newAgent->setLinkedData(newAvatar); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 22694aaae5..c2918f1add 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -65,6 +65,7 @@ public: Avatar* getAvatar() { return &_myAvatar; } Camera* getCamera() { return &_myCamera; } + ViewFrustum* getViewFrustum() { return &_viewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } Environment* getEnvironment() { return &_environment; } bool shouldEchoAudio() { return _echoAudioMode->isChecked(); } diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 3a4162d296..886fb78d97 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -61,6 +61,8 @@ const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; const int NUM_BODY_CONE_SIDES = 9; +const float AVATAR_TREE_SCALE = 1.0f; +const int MAX_VOXELS_PER_AVATAR = 2000; bool usingBigSphereCollisionTest = true; @@ -93,7 +95,8 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _cumulativeMouseYaw(0.0f), - _isMouseTurningRight(false) + _isMouseTurningRight(false), + _voxels(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) { // give the pointer to our head to inherited _headData variable from AvatarData @@ -119,6 +122,12 @@ Avatar::~Avatar() { delete _balls; } +void Avatar::init() { + _voxels.init(); + + _voxels.createVoxel(0.0f, 0.0f, 0.0f, 1.0f, 255, 0, 255); +} + void Avatar::reset() { _head.reset(); } @@ -1132,6 +1141,15 @@ void Avatar::renderBody(bool lookingInMirror) { const float RENDER_OPAQUE_BEYOND = 1.0f; // Meters beyond which body is shown opaque const float RENDER_TRANSLUCENT_BEYOND = 0.5f; + // Render the body's voxels + glPushMatrix(); + glTranslatef(_position.x, _position.y, _position.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++) { float distanceToCamera = glm::length(_cameraPosition - _joint[b].position); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index d272514ed1..d1bc651eff 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -19,6 +19,7 @@ #include "Head.h" #include "Skeleton.h" #include "Transmitter.h" +#include "VoxelSystem.h" enum DriveKeys { @@ -46,6 +47,7 @@ public: Avatar(Agent* owningAgent = NULL); ~Avatar(); + void init(); void reset(); void simulate(float deltaTime, Transmitter* transmitter); void updateHeadFromGyros(float frametime, SerialInterface * serialInterface); @@ -147,6 +149,7 @@ private: Avatar* _interactingOther; float _cumulativeMouseYaw; bool _isMouseTurningRight; + VoxelSystem _voxels; // private methods... glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 5e1b72e5c4..b4202511e6 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -19,6 +19,7 @@ #include #include #include +#include "Application.h" #include "Log.h" #include "VoxelConstants.h" #include "InterfaceConfig.h" @@ -37,14 +38,15 @@ GLfloat identityNormals[] = { 0,0,-1, 0,0,-1, 0,0,-1, 0,0,-1, -1,0,0, +1,0,0, +1,0,0, -1,0,0, -1,0,0, +1,0,0, +1,0,0, -1,0,0 }; -GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- . +GLubyte identityIndices[] = { 0,2,1, 0,3,2, // Z- 8,9,13, 8,13,12, // Y- 16,23,19, 16,20,23, // X- 17,18,22, 17,22,21, // X+ 10,11,15, 10,15,14, // Y+ - 4,5,6, 4,6,7 }; // Z+ . + 4,5,6, 4,6,7 }; // Z+ -VoxelSystem::VoxelSystem() : AgentData(NULL) { +VoxelSystem::VoxelSystem(float treeScale, int maxVoxels) : + AgentData(NULL), _treeScale(treeScale), _maxVoxels(maxVoxels) { _voxelsInReadArrays = _voxelsInWriteArrays = _voxelsUpdated = 0; _writeRenderFullVBO = true; _readRenderFullVBO = true; @@ -312,12 +314,11 @@ void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { } int VoxelSystem::newTreeToArrays(VoxelNode* node) { - assert(_viewFrustum); // you must set up _viewFrustum before calling this int voxelsUpdated = 0; bool shouldRender = false; // assume we don't need to render it // if it's colored, we might need to render it! if (node->isColored()) { - float distanceToNode = node->distanceToCamera(*_viewFrustum); + float distanceToNode = node->distanceToCamera(*Application::getInstance()->getViewFrustum()); float boundary = boundaryDistanceForRenderLevel(node->getLevel()); float childBoundary = boundaryDistanceForRenderLevel(node->getLevel() + 1); bool inBoundary = (distanceToNode <= boundary); @@ -352,7 +353,7 @@ int VoxelSystem::newTreeToArrays(VoxelNode* node) { int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { // If we've run out of room, then just bail... - if (_voxelsInWriteArrays >= MAX_VOXELS_PER_SYSTEM) { + if (_voxelsInWriteArrays >= _maxVoxels) { return 0; } @@ -382,7 +383,7 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { // If we've run out of room, then just bail... - if (_voxelsInWriteArrays >= MAX_VOXELS_PER_SYSTEM) { + if (_voxelsInWriteArrays >= _maxVoxels) { return 0; } @@ -425,6 +426,9 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { return 0; // not-updated } +ProgramObject* VoxelSystem::_perlinModulateProgram = 0; +GLuint VoxelSystem::_permutationNormalTextureID = 0; + void VoxelSystem::init() { _renderWarningsOn = false; @@ -440,23 +444,23 @@ void VoxelSystem::init() { _unusedArraySpace = 0; // we will track individual dirty sections with these arrays of bools - _writeVoxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; - memset(_writeVoxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool)); - _readVoxelDirtyArray = new bool[MAX_VOXELS_PER_SYSTEM]; - memset(_readVoxelDirtyArray, false, MAX_VOXELS_PER_SYSTEM * sizeof(bool)); + _writeVoxelDirtyArray = new bool[_maxVoxels]; + memset(_writeVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); + _readVoxelDirtyArray = new bool[_maxVoxels]; + memset(_readVoxelDirtyArray, false, _maxVoxels * sizeof(bool)); // prep the data structures for incoming voxel data - _writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - _readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + _writeVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; + _readVerticesArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - _writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; - _readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + _writeColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; + _readColorsArray = new GLubyte[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; - GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + GLuint* indicesArray = new GLuint[INDICES_PER_VOXEL * _maxVoxels]; // populate the indicesArray // this will not change given new voxels, so we can set it all up now - for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { + for (int n = 0; n < _maxVoxels; n++) { // fill the indices array int voxelIndexOffset = n * INDICES_PER_VOXEL; GLuint* currentIndicesPos = indicesArray + voxelIndexOffset; @@ -468,11 +472,11 @@ void VoxelSystem::init() { } } - GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * MAX_VOXELS_PER_SYSTEM]; + GLfloat* normalsArray = new GLfloat[VERTEX_POINTS_PER_VOXEL * _maxVoxels]; GLfloat* normalsArrayEndPointer = normalsArray; // populate the normalsArray - for (int n = 0; n < MAX_VOXELS_PER_SYSTEM; n++) { + for (int n = 0; n < _maxVoxels; n++) { for (int i = 0; i < VERTEX_POINTS_PER_VOXEL; i++) { *(normalsArrayEndPointer++) = identityNormals[i]; } @@ -481,32 +485,35 @@ void VoxelSystem::init() { // VBO for the verticesArray glGenBuffers(1, &_vboVerticesID); glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); // VBO for the normalsArray glGenBuffers(1, &_vboNormalsID); glBindBuffer(GL_ARRAY_BUFFER, _vboNormalsID); glBufferData(GL_ARRAY_BUFFER, - VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * MAX_VOXELS_PER_SYSTEM, + VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, normalsArray, GL_STATIC_DRAW); // VBO for colorsArray glGenBuffers(1, &_vboColorsID); glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * MAX_VOXELS_PER_SYSTEM, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); // VBO for the indicesArray glGenBuffers(1, &_vboIndicesID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, - INDICES_PER_VOXEL * sizeof(GLuint) * MAX_VOXELS_PER_SYSTEM, + INDICES_PER_VOXEL * sizeof(GLuint) * _maxVoxels, indicesArray, GL_STATIC_DRAW); // delete the indices and normals arrays that are no longer needed delete[] indicesArray; delete[] normalsArray; - // create our simple fragment shader + // create our simple fragment shader if we're the first system to init + if (_perlinModulateProgram != 0) { + return; + } switchToResourcesParentIfRequired(); _perlinModulateProgram = new ProgramObject(); _perlinModulateProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/perlin_modulate.vert"); @@ -661,7 +668,7 @@ void VoxelSystem::render(bool texture) { // draw the number of voxels we have glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _vboIndicesID); - glScalef(TREE_SCALE, TREE_SCALE, TREE_SCALE); + glScalef(_treeScale, _treeScale, _treeScale); glDrawRangeElementsEXT(GL_TRIANGLES, 0, VERTICES_PER_VOXEL * _voxelsInReadArrays - 1, 36 * _voxelsInReadArrays, GL_UNSIGNED_INT, 0); @@ -855,7 +862,7 @@ bool VoxelSystem::removeOutOfViewOperation(VoxelNode* node, void* extraData) { for (int i = 0; i < NUMBER_OF_CHILDREN; i++) { VoxelNode* childNode = node->getChildAtIndex(i); if (childNode) { - ViewFrustum::location inFrustum = childNode->inFrustum(*thisVoxelSystem->_viewFrustum); + ViewFrustum::location inFrustum = childNode->inFrustum(*Application::getInstance()->getViewFrustum()); switch (inFrustum) { case ViewFrustum::OUTSIDE: { args->nodesOutside++; @@ -907,9 +914,9 @@ bool VoxelSystem::hasViewChanged() { } // If our viewFrustum has changed since our _lastKnowViewFrustum - if (_viewFrustum && !_lastStableViewFrustum.matches(_viewFrustum)) { + if (!_lastStableViewFrustum.matches(Application::getInstance()->getViewFrustum())) { result = true; - _lastStableViewFrustum = *_viewFrustum; // save last stable + _lastStableViewFrustum = *Application::getInstance()->getViewFrustum(); // save last stable } return result; } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 7bffb1d33c..de904bb64f 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -16,7 +16,6 @@ #include #include #include -#include "Avatar.h" #include "Camera.h" #include "Util.h" #include "world.h" @@ -27,7 +26,7 @@ const int NUM_CHILDREN = 8; class VoxelSystem : public AgentData { public: - VoxelSystem(); + VoxelSystem(float treeScale = TREE_SCALE, int maxVoxels = MAX_VOXELS_PER_SYSTEM); ~VoxelSystem(); int parseData(unsigned char* sourceBuffer, int numBytes); @@ -41,8 +40,6 @@ public: unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;}; - void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; - void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); long int getVoxelsCreated(); @@ -114,8 +111,8 @@ private: static float _maxDistance; static float _minDistance; - Avatar* _viewerAvatar; - Camera* _camera; + float _treeScale; + int _maxVoxels; VoxelTree* _tree; GLfloat* _readVerticesArray; GLubyte* _readColorsArray; @@ -143,9 +140,6 @@ private: pthread_mutex_t _bufferWriteLock; pthread_mutex_t _treeLock; - ProgramObject* _perlinModulateProgram; - GLuint _permutationNormalTextureID; - ViewFrustum* _viewFrustum; ViewFrustum _lastKnowViewFrustum; ViewFrustum _lastStableViewFrustum; @@ -158,6 +152,9 @@ private: bool _voxelsDirty; + static ProgramObject* _perlinModulateProgram; + static GLuint _permutationNormalTextureID; + public: void updateVBOs(); void updateFullVBOs(); // all voxels in the VBO From 7425b392376223376c552c748b14aab906c91e07 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Fri, 31 May 2013 17:55:30 -0700 Subject: [PATCH 11/73] Working on avatar voxel system. --- interface/src/Avatar.cpp | 9 +- interface/src/Avatar.h | 5 +- interface/src/AvatarVoxelSystem.cpp | 97 ++++++++++++++++++++ interface/src/AvatarVoxelSystem.h | 43 +++++++++ interface/src/VoxelSystem.cpp | 134 +++++++++++----------------- interface/src/VoxelSystem.h | 33 ++++--- 6 files changed, 216 insertions(+), 105 deletions(-) create mode 100644 interface/src/AvatarVoxelSystem.cpp create mode 100644 interface/src/AvatarVoxelSystem.h diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index cc30a011af..7198c0030c 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -57,9 +57,6 @@ const float SKIN_COLOR[] = {1.0, 0.84, 0.66}; const float DARK_SKIN_COLOR[] = {0.9, 0.78, 0.63}; const int NUM_BODY_CONE_SIDES = 9; -const float AVATAR_TREE_SCALE = 1.0f; -const int MAX_VOXELS_PER_AVATAR = 2000; - bool usingBigSphereCollisionTest = true; float chatMessageScale = 0.0015; @@ -91,8 +88,7 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _cumulativeMouseYaw(0.0f), - _isMouseTurningRight(false), - _voxels(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) + _isMouseTurningRight(false) { // give the pointer to our head to inherited _headData variable from AvatarData @@ -1153,7 +1149,8 @@ void Avatar::renderBody(bool lookingInMirror) { // Render the body's voxels glPushMatrix(); - glTranslatef(_position.x, _position.y, _position.z); + 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); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index d1bc651eff..726ae972c2 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -13,13 +13,13 @@ #include #include "world.h" #include "AvatarTouch.h" +#include "AvatarVoxelSystem.h" #include "InterfaceConfig.h" #include "SerialInterface.h" #include "Balls.h" #include "Head.h" #include "Skeleton.h" #include "Transmitter.h" -#include "VoxelSystem.h" enum DriveKeys { @@ -149,7 +149,8 @@ private: Avatar* _interactingOther; float _cumulativeMouseYaw; bool _isMouseTurningRight; - VoxelSystem _voxels; + + AvatarVoxelSystem _voxels; // private methods... glm::vec3 caclulateAverageEyePosition() { return _head.caclulateAverageEyePosition(); } // get the position smack-dab between the eyes (for lookat) diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp new file mode 100644 index 0000000000..79f3f113b9 --- /dev/null +++ b/interface/src/AvatarVoxelSystem.cpp @@ -0,0 +1,97 @@ +// +// AvatarVoxelSystem.cpp +// interface +// +// Created by Andrzej Kapolka on 5/31/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. + +#include + +#include "AvatarVoxelSystem.h" + +const float AVATAR_TREE_SCALE = 1.0f; +const int MAX_VOXELS_PER_AVATAR = 2000; +const int BONE_INDEX_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; +const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; + +AvatarVoxelSystem::AvatarVoxelSystem() : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) { +} + +AvatarVoxelSystem::~AvatarVoxelSystem() { + delete[] _readBoneIndicesArray; + delete[] _readBoneWeightsArray; + delete[] _writeBoneIndicesArray; + delete[] _writeBoneWeightsArray; +} + +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]; + + _writeBoneWeightsArray = new GLfloat[BONE_WEIGHT_ELEMENTS_PER_VOXEL * _maxVoxels]; + _readBoneWeightsArray = new GLfloat[BONE_WEIGHT_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); + + // 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); +} + +void AvatarVoxelSystem::render(bool texture) { + VoxelSystem::render(texture); +} + +void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, + float voxelScale, const nodeColor& color) { + VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); + + for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VOXEL; j++) { + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); + *(writeBoneIndicesAt + j) = 0; + *(writeBoneWeightsAt + j) = 0.0f; + } +} + +void AvatarVoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + 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); + 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); + memcpy(readBoneWeightsAt, writeBoneWeightsAt, segmentSizeBytes); +} + +void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + 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); + 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); + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); +} + diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h new file mode 100644 index 0000000000..d129e046b9 --- /dev/null +++ b/interface/src/AvatarVoxelSystem.h @@ -0,0 +1,43 @@ +// +// AvatarVoxelSystem.h +// interface +// +// Created by Andrzej Kapolka on 5/31/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__AvatarVoxelSystem__ +#define __interface__AvatarVoxelSystem__ + +#include "VoxelSystem.h" + +class AvatarVoxelSystem : public VoxelSystem { +public: + + AvatarVoxelSystem(); + virtual ~AvatarVoxelSystem(); + + virtual void init(); + virtual void render(bool texture); + +protected: + + 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); + +private: + + GLubyte* _readBoneIndicesArray; + GLfloat* _readBoneWeightsArray; + GLubyte* _writeBoneIndicesArray; + GLfloat* _writeBoneWeightsArray; + + GLuint _vboBoneIndicesID; + GLuint _vboBoneWeightsID; + + ProgramObject* _skinProgram; +}; + +#endif /* defined(__interface__AvatarVoxelSystem__) */ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b4202511e6..7f5a926d28 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -231,10 +231,8 @@ void VoxelSystem::cleanupRemovedVoxels() { } void VoxelSystem::copyWrittenDataToReadArraysFullVBOs() { - int bytesOfVertices = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLfloat); - int bytesOfColors = (_voxelsInWriteArrays * VERTEX_POINTS_PER_VOXEL) * sizeof(GLubyte); - memcpy(_readVerticesArray, _writeVerticesArray, bytesOfVertices); - memcpy(_readColorsArray, _writeColorsArray, bytesOfColors ); + copyWrittenDataSegmentToReadArrays(0, _voxelsInWriteArrays - 1); + _voxelsInReadArrays = _voxelsInWriteArrays; // clear our dirty flags @@ -261,47 +259,37 @@ void VoxelSystem::copyWrittenDataToReadArraysPartialVBOs() { if (!thisVoxelDirty) { // If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before // this one and so that's where the "segment" ends - segmentEnd = i - 1; + copyWrittenDataSegmentToReadArrays(segmentStart, i - 1); inSegment = false; - int segmentLength = (segmentEnd - segmentStart) + 1; - - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); - - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); } } } // if we got to the end of the array, and we're in an active dirty segment... if (inSegment) { - segmentEnd = _voxelsInWriteArrays - 1; - int segmentLength = (segmentEnd - segmentStart) + 1; - - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); - - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); + copyWrittenDataSegmentToReadArrays(segmentStart, _voxelsInWriteArrays - 1); } // update our length _voxelsInReadArrays = _voxelsInWriteArrays; } +void VoxelSystem::copyWrittenDataSegmentToReadArrays(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + int segmentLength = (segmentEnd - segmentStart) + 1; + + GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readVerticesAt = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + GLfloat* writeVerticesAt = _writeVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + memcpy(readVerticesAt, writeVerticesAt, segmentSizeBytes); + + segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readColorsAt = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + GLubyte* writeColorsAt = _writeColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + memcpy(readColorsAt, writeColorsAt, segmentSizeBytes); +} + void VoxelSystem::copyWrittenDataToReadArrays(bool fullVBOs) { PerformanceWarning warn(_renderWarningsOn, "copyWrittenDataToReadArrays()"); if (_voxelsDirty && _voxelsUpdated) { @@ -364,12 +352,7 @@ int VoxelSystem::updateNodeInArraysAsFullVBO(VoxelNode* node) { // populate the array with points for the 8 vertices // and RGB color for each added vertex - for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { - GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); - *(writeColorsAt +j) = node->getColor()[j % 3]; - } + updateNodeInArrays(nodeIndex, startVertex, voxelScale, node->getColor()); node->setBufferIndex(nodeIndex); _writeVoxelDirtyArray[nodeIndex] = true; // just in case we switch to Partial mode _voxelsInWriteArrays++; // our know vertices in the arrays @@ -415,17 +398,23 @@ int VoxelSystem::updateNodeInArraysAsPartialVBO(VoxelNode* node) { // populate the array with points for the 8 vertices // and RGB color for each added vertex - for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { - GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); - *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); - *(writeColorsAt +j) = node->getColor()[j % 3]; - } + updateNodeInArrays(nodeIndex, startVertex, voxelScale, node->getColor()); + return 1; // updated! } return 0; // not-updated } +void VoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, + float voxelScale, const nodeColor& color) { + for (int j = 0; j < VERTEX_POINTS_PER_VOXEL; j++ ) { + GLfloat* writeVerticesAt = _writeVerticesArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + GLubyte* writeColorsAt = _writeColorsArray + (nodeIndex * VERTEX_POINTS_PER_VOXEL); + *(writeVerticesAt+j) = startVertex[j % 3] + (identityVertices[j] * voxelScale); + *(writeColorsAt +j) = color[j % 3]; + } +} + ProgramObject* VoxelSystem::_perlinModulateProgram = 0; GLuint VoxelSystem::_permutationNormalTextureID = 0; @@ -546,20 +535,7 @@ void VoxelSystem::init() { } void VoxelSystem::updateFullVBOs() { - glBufferIndex segmentStart = 0; - glBufferIndex segmentEnd = _voxelsInReadArrays; - - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); + updateVBOSegment(0, _voxelsInReadArrays); // consider the _readVoxelDirtyArray[] clean! memset(_readVoxelDirtyArray, false, _voxelsInReadArrays * sizeof(bool)); @@ -581,39 +557,17 @@ void VoxelSystem::updatePartialVBOs() { if (!thisVoxelDirty) { // If we got here because because this voxel is NOT dirty, so the last dirty voxel was the one before // this one and so that's where the "segment" ends - segmentEnd = i - 1; + updateVBOSegment(segmentStart, i - 1); inSegment = false; - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); } _readVoxelDirtyArray[i] = false; // consider us clean! } } // if we got to the end of the array, and we're in an active dirty segment... - if (inSegment) { - segmentEnd = _voxelsInReadArrays - 1; + if (inSegment) { + updateVBOSegment(segmentStart, _voxelsInReadArrays - 1); inSegment = false; - int segmentLength = (segmentEnd - segmentStart) + 1; - GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); - GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); - segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); - GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); - glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); - glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); } } @@ -635,6 +589,20 @@ void VoxelSystem::updateVBOs() { _callsToTreesToArrays = 0; // clear it } +void VoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd) { + int segmentLength = (segmentEnd - segmentStart) + 1; + GLintptr segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLsizeiptr segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLfloat); + GLfloat* readVerticesFrom = _readVerticesArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboVerticesID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readVerticesFrom); + segmentStartAt = segmentStart * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + segmentSizeBytes = segmentLength * VERTEX_POINTS_PER_VOXEL * sizeof(GLubyte); + GLubyte* readColorsFrom = _readColorsArray + (segmentStart * VERTEX_POINTS_PER_VOXEL); + glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); + glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readColorsFrom); +} + void VoxelSystem::render(bool texture) { PerformanceWarning warn(_renderWarningsOn, "render()"); diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index de904bb64f..a7824d8326 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -31,11 +31,9 @@ public: int parseData(unsigned char* sourceBuffer, int numBytes); - void setViewFrustum(ViewFrustum* viewFrustum) { _viewFrustum = viewFrustum; }; - - void init(); + virtual void init(); void simulate(float deltaTime) { }; - void render(bool texture); + virtual void render(bool texture); unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;}; @@ -80,6 +78,16 @@ public: void createLine(glm::vec3 point1, glm::vec3 point2, float unitSize, rgbColor color, bool destructive = false); void createSphere(float r,float xc, float yc, float zc, float s, bool solid, creationMode mode, bool destructive = false, bool debug = false); + +protected: + + int _maxVoxels; + + 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); + private: // disallow copying of VoxelSystem objects VoxelSystem(const VoxelSystem&); @@ -107,12 +115,13 @@ private: void copyWrittenDataToReadArraysFullVBOs(); void copyWrittenDataToReadArraysPartialVBOs(); + void updateVBOs(); + // these are kinda hacks, used by getDistanceFromViewRangeOperation() probably shouldn't be here static float _maxDistance; static float _minDistance; - float _treeScale; - int _maxVoxels; + float _treeScale; VoxelTree* _tree; GLfloat* _readVerticesArray; GLubyte* _readColorsArray; @@ -121,8 +130,8 @@ private: bool* _writeVoxelDirtyArray; bool* _readVoxelDirtyArray; unsigned long _voxelsUpdated; - unsigned long _voxelsInWriteArrays; unsigned long _voxelsInReadArrays; + unsigned long _voxelsInWriteArrays; unsigned long _unusedArraySpace; bool _writeRenderFullVBO; @@ -140,7 +149,6 @@ private: pthread_mutex_t _bufferWriteLock; pthread_mutex_t _treeLock; - ViewFrustum* _viewFrustum; ViewFrustum _lastKnowViewFrustum; ViewFrustum _lastStableViewFrustum; @@ -149,17 +157,14 @@ private: void setupNewVoxelsForDrawing(); void copyWrittenDataToReadArrays(bool fullVBOs); + + void updateFullVBOs(); // all voxels in the VBO + void updatePartialVBOs(); // multiple segments, only dirty voxels bool _voxelsDirty; static ProgramObject* _perlinModulateProgram; static GLuint _permutationNormalTextureID; - -public: - void updateVBOs(); - void updateFullVBOs(); // all voxels in the VBO - void updatePartialVBOs(); // multiple segments, only dirty voxels - }; #endif From 6c975f9c6fe2a95a9225909de722721290637f2e Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sat, 1 Jun 2013 15:06:29 -0700 Subject: [PATCH 12/73] More work on avatar voxels. --- interface/resources/shaders/skin_voxels.vert | 34 +++++++++++ interface/src/Avatar.cpp | 3 +- interface/src/AvatarVoxelSystem.cpp | 64 +++++++++++++++++--- interface/src/AvatarVoxelSystem.h | 13 +++- interface/src/VoxelSystem.cpp | 24 +++++--- interface/src/VoxelSystem.h | 2 + 6 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 interface/resources/shaders/skin_voxels.vert diff --git a/interface/resources/shaders/skin_voxels.vert b/interface/resources/shaders/skin_voxels.vert new file mode 100644 index 0000000000..c63b2e1b31 --- /dev/null +++ b/interface/resources/shaders/skin_voxels.vert @@ -0,0 +1,34 @@ +#version 120 + +// +// skin_voxels.vert +// vertex shader +// +// Created by Andrzej Kapolka on 5/31/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +const int MAX_BONES = 32; +const int INDICES_PER_VERTEX = 4; + +uniform mat4 boneMatrices[MAX_BONES]; + +attribute vec4 boneIndices; +attribute vec4 boneWeights; + +void main(void) { + vec4 position = vec4(0.0, 0.0, 0.0, 0.0); + vec4 normal = vec4(0.0, 0.0, 0.0, 0.0); + for (int i = 0; i < INDICES_PER_VERTEX; i++) { + mat4 boneMatrix = boneMatrices[int(boneIndices[i])]; + float boneWeight = boneWeights[i]; + position += boneMatrix * gl_Vertex * boneWeight; + normal += boneMatrix * vec4(gl_Normal, 0.0) * boneWeight; + } + position = gl_ModelViewProjectionMatrix * position; + normal = normalize(gl_ModelViewMatrix * normal); + + 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_Position = position; +} diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 7198c0030c..6ee8cefb55 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -88,7 +88,8 @@ Avatar::Avatar(Agent* owningAgent) : _mouseRayDirection(0.0f, 0.0f, 0.0f), _interactingOther(NULL), _cumulativeMouseYaw(0.0f), - _isMouseTurningRight(false) + _isMouseTurningRight(false), + _voxels(this) { // give the pointer to our head to inherited _headData variable from AvatarData diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 79f3f113b9..dcea2816ec 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -8,13 +8,18 @@ #include #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_VOXEL = 4 * VERTICES_PER_VOXEL; -const int BONE_WEIGHT_ELEMENTS_PER_VOXEL = 4 * VERTICES_PER_VOXEL; +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; -AvatarVoxelSystem::AvatarVoxelSystem() : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR) { +AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : + VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), + _avatar(avatar) { } AvatarVoxelSystem::~AvatarVoxelSystem() { @@ -24,6 +29,11 @@ AvatarVoxelSystem::~AvatarVoxelSystem() { delete[] _writeBoneWeightsArray; } +ProgramObject* AvatarVoxelSystem::_skinProgram = 0; +int AvatarVoxelSystem::_boneMatricesLocation; +int AvatarVoxelSystem::_boneIndicesLocation; +int AvatarVoxelSystem::_boneWeightsLocation; + void AvatarVoxelSystem::init() { VoxelSystem::init(); @@ -43,6 +53,18 @@ void AvatarVoxelSystem::init() { glGenBuffers(1, &_vboBoneWeightsID); glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); glBufferData(GL_ARRAY_BUFFER, BONE_WEIGHT_ELEMENTS_PER_VOXEL * sizeof(GLfloat) * _maxVoxels, NULL, GL_DYNAMIC_DRAW); + + // load our skin program if this is the first avatar system to initialize + if (_skinProgram != 0) { + return; + } + _skinProgram = new ProgramObject(); + _skinProgram->addShaderFromSourceFile(QGLShader::Vertex, "resources/shaders/skin_voxels.vert"); + _skinProgram->link(); + + _boneMatricesLocation = _skinProgram->uniformLocation("boneMatrices"); + _boneIndicesLocation = _skinProgram->attributeLocation("boneIndices"); + _boneWeightsLocation = _skinProgram->attributeLocation("boneWeights"); } void AvatarVoxelSystem::render(bool texture) { @@ -53,11 +75,15 @@ void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::v float voxelScale, const nodeColor& color) { VoxelSystem::updateNodeInArrays(nodeIndex, startVertex, voxelScale, color); - for (int j = 0; j < BONE_INDEX_ELEMENTS_PER_VOXEL; j++) { - GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); - GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_ELEMENTS_PER_VOXEL); - *(writeBoneIndicesAt + j) = 0; - *(writeBoneWeightsAt + j) = 0.0f; + GLubyte* writeBoneIndicesAt = _writeBoneIndicesArray + (nodeIndex * BONE_INDEX_ELEMENTS_PER_VOXEL); + GLfloat* writeBoneWeightsAt = _writeBoneWeightsArray + (nodeIndex * BONE_WEIGHT_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]; + } } } @@ -95,3 +121,25 @@ void AvatarVoxelSystem::updateVBOSegment(glBufferIndex segmentStart, glBufferInd glBufferSubData(GL_ARRAY_BUFFER, segmentStartAt, segmentSizeBytes, readBoneWeightsFrom); } +void AvatarVoxelSystem::bindProgram(bool texture) { + _skinProgram->bind(); + + QMatrix4x4 boneMatrices[1]; + + _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, sizeof(boneMatrices) / sizeof(boneMatrices[0])); + + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneIndicesID); + _skinProgram->setAttributeBuffer(_boneIndicesLocation, GL_UNSIGNED_BYTE, 0, BONE_INDEX_ELEMENTS_PER_VERTEX); + _skinProgram->enableAttributeArray(_boneIndicesLocation); + + glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); + _skinProgram->setAttributeBuffer(_boneWeightsLocation, GL_FLOAT, 0, BONE_WEIGHT_ELEMENTS_PER_VERTEX); + _skinProgram->enableAttributeArray(_boneWeightsLocation); +} + +void AvatarVoxelSystem::releaseProgram(bool texture) { + _skinProgram->release(); + _skinProgram->disableAttributeArray(_boneIndicesLocation); + _skinProgram->disableAttributeArray(_boneWeightsLocation); +} + diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index d129e046b9..1b28a1a60d 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -11,10 +11,12 @@ #include "VoxelSystem.h" +class Avatar; + class AvatarVoxelSystem : public VoxelSystem { public: - AvatarVoxelSystem(); + AvatarVoxelSystem(Avatar* avatar); virtual ~AvatarVoxelSystem(); virtual void init(); @@ -26,9 +28,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); private: + Avatar* _avatar; + GLubyte* _readBoneIndicesArray; GLfloat* _readBoneWeightsArray; GLubyte* _writeBoneIndicesArray; @@ -37,7 +43,10 @@ private: GLuint _vboBoneIndicesID; GLuint _vboBoneWeightsID; - ProgramObject* _skinProgram; + static ProgramObject* _skinProgram; + static int _boneMatricesLocation; + static int _boneIndicesLocation; + static int _boneWeightsLocation; }; #endif /* defined(__interface__AvatarVoxelSystem__) */ diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index 7f5a926d28..c2d3de8da1 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -625,10 +625,7 @@ void VoxelSystem::render(bool texture) { glBindBuffer(GL_ARRAY_BUFFER, _vboColorsID); glColorPointer(3, GL_UNSIGNED_BYTE, 0, 0); - if (texture) { - _perlinModulateProgram->bind(); - glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); - } + bindProgram(texture); // for performance, disable blending and enable backface culling glDisable(GL_BLEND); @@ -643,10 +640,7 @@ void VoxelSystem::render(bool texture) { glEnable(GL_BLEND); glDisable(GL_CULL_FACE); - if (texture) { - _perlinModulateProgram->release(); - glBindTexture(GL_TEXTURE_2D, 0); - } + releaseProgram(texture); // deactivate vertex and color arrays after drawing glDisableClientState(GL_VERTEX_ARRAY); @@ -663,6 +657,20 @@ void VoxelSystem::render(bool texture) { pthread_mutex_unlock(&_bufferWriteLock); } +void VoxelSystem::bindProgram(bool texture) { + if (texture) { + _perlinModulateProgram->bind(); + glBindTexture(GL_TEXTURE_2D, _permutationNormalTextureID); + } +} + +void VoxelSystem::releaseProgram(bool texture) { + if (texture) { + _perlinModulateProgram->release(); + glBindTexture(GL_TEXTURE_2D, 0); + } +} + int VoxelSystem::_nodeCount = 0; void VoxelSystem::killLocalVoxels() { diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index a7824d8326..8c9337bbe5 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -87,6 +87,8 @@ 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); private: // disallow copying of VoxelSystem objects From dccc44a6f54480700ddeb21d641fa636ece0b65e Mon Sep 17 00:00:00 2001 From: atlante45 Date: Sun, 2 Jun 2013 14:58:51 +0200 Subject: [PATCH 13/73] Added settings management using QSettings --- interface/src/Application.cpp | 362 +++++++++------------------------- interface/src/Application.h | 82 ++------ interface/src/Avatar.cpp | 40 ++-- interface/src/Avatar.h | 7 +- 4 files changed, 146 insertions(+), 345 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fe84ec4748..d4ef038487 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -150,7 +151,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _packetCount(0), _packetsPerSecond(0), _bytesPerSecond(0), - _bytesCount(0) + _bytesCount(0), + _settings("HighFidelity", "Interface") { _applicationStartupTime = startup_time; _window->setWindowTitle("Interface"); @@ -215,6 +217,8 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _glWidget->setMouseTracking(true); // initialization continues in initializeGL when OpenGL context is ready + + QCoreApplication::setOrganizationDomain("highfidelity.io"); // Used by QSettings on OS X } void Application::initializeGL() { @@ -267,8 +271,6 @@ void Application::initializeGL() { connect(idleTimer, SIGNAL(timeout()), SLOT(idle())); idleTimer->start(0); - readSettings(); - if (_justStarted) { float startupTime = (usecTimestampNow() - usecTimestamp(&_applicationStartupTime))/1000000.0; _justStarted = false; @@ -724,177 +726,6 @@ void Application::wheelEvent(QWheelEvent* event) { } } -const char AVATAR_DATA_FILENAME[] = "avatar.ifd"; - -void Application::readSettingsFile() { - FILE* settingsFile = fopen(AVATAR_DATA_FILENAME, "rt"); - - if (settingsFile) { - char line[LINE_MAX]; - - while (fgets(line, LINE_MAX, settingsFile) != NULL) - { - if (strcmp(line, " \n") > 0) { - char* token = NULL; - char* settingLine = NULL; - char* toFree = NULL; - - settingLine = strdup(line); - - if (settingLine != NULL) { - toFree = settingLine; - - int i = 0; - - char key[128]; - char value[128]; - - - while ((token = strsep(&settingLine, "=")) != NULL) - { - switch (i) { - case 0: - strcpy(key, token); - _settingsTable[key] = ""; - break; - - case 1: - strcpy(value, token); - _settingsTable[key] = token; - break; - - default: - break; - } - - i++; - } - - free(toFree); - } - } - } - - fclose(settingsFile); - } -} - -void Application::saveSettingsFile() { - FILE* settingsFile = fopen(AVATAR_DATA_FILENAME, "wt"); - - if (settingsFile) { - for (std::map::iterator i = _settingsTable.begin(); i != _settingsTable.end(); i++) - { - fprintf(settingsFile, "\n%s=%s", i->first.data(), i->second.data()); - } - } - - fclose(settingsFile); -} - -bool Application::getSetting(const char* setting, bool& value, const bool defaultSetting) const { - std::map::const_iterator iter = _settingsTable.find(setting); - - if (iter != _settingsTable.end()) { - int readBool; - - int res = sscanf(iter->second.data(), "%d", &readBool); - - const char EXPECTED_ITEMS = 1; - - if (res == EXPECTED_ITEMS) { - if (readBool == 1) { - value = true; - } else if (readBool == 0) { - value = false; - } - } - } else { - value = defaultSetting; - return false; - } - - return true; -} - -bool Application::getSetting(const char* setting, float& value, const float defaultSetting) const { - std::map::const_iterator iter = _settingsTable.find(setting); - - if (iter != _settingsTable.end()) { - float readFloat; - - int res = sscanf(iter->second.data(), "%f", &readFloat); - - const char EXPECTED_ITEMS = 1; - - if (res == EXPECTED_ITEMS) { - if (!isnan(readFloat)) { - value = readFloat; - } else { - value = defaultSetting; - return false; - } - } else { - value = defaultSetting; - return false; - } - } else { - value = defaultSetting; - return false; - } - - return true; -} - -bool Application::getSetting(const char* setting, glm::vec3& value, const glm::vec3& defaultSetting) const { - std::map::const_iterator iter = _settingsTable.find(setting); - - if (iter != _settingsTable.end()) { - glm::vec3 readVec; - - int res = sscanf(iter->second.data(), "%f,%f,%f", &readVec.x, &readVec.y, &readVec.z); - - const char EXPECTED_ITEMS = 3; - - if (res == EXPECTED_ITEMS) { - if (!isnan(readVec.x) && !isnan(readVec.y) && !isnan(readVec.z)) { - value = readVec; - } else { - value = defaultSetting; - return false; - } - } else { - value = defaultSetting; - return false; - } - } else { - value = defaultSetting; - return false; - } - - return true; -} - -const short MAX_SETTINGS_LENGTH = 128; - -void Application::setSetting(const char* setting, const bool value) { - char settingValues[MAX_SETTINGS_LENGTH]; - sprintf(settingValues, "%d", value); - _settingsTable[setting] = settingValues; -} - -void Application::setSetting(const char* setting, const float value) { - char settingValues[MAX_SETTINGS_LENGTH]; - sprintf(settingValues, "%f", value); - _settingsTable[setting] = settingValues; -} - -void Application::setSetting(const char* setting, const glm::vec3& value) { - char settingValues[MAX_SETTINGS_LENGTH]; - sprintf(settingValues, "%f,%f,%f", value.x, value.y, value.z); - _settingsTable[setting] = settingValues; -} - // Every second, check the frame rates and other stuff void Application::timer() { gettimeofday(&_timerEnd, NULL); @@ -1116,7 +947,10 @@ void Application::terminate() { // Close serial port // close(serial_fd); - saveSettings(); + if (_autosave) { + saveSettings(); + _settings.sync(); + } if (_enableNetworkThread) { _stopNetworkReceiveThread = true; @@ -1279,7 +1113,7 @@ void Application::chooseVoxelPaintColor() { // restore the main window's active state _window->activateWindow(); } - + void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); _window->setMenuBar(menuBar); @@ -1383,6 +1217,14 @@ 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); + + QMenu* settingsMenu = menuBar->addMenu("Settings"); + (_settingsAutosave = settingsMenu->addAction("Autosave", this, SLOT(setAutosave(bool))))->setCheckable(true); + _settingsAutosave->setChecked(true); + settingsMenu->addAction("Load settings", this, SLOT(loadSettings())); + settingsMenu->addAction("Save settings", this, SLOT(saveSettings())); + settingsMenu->addAction("Import settings", this, SLOT(importSettings())); + settingsMenu->addAction("Export settings", this, SLOT(exportSettings())); } void Application::updateFrustumRenderModeAction() { @@ -1443,6 +1285,8 @@ void Application::init() { gettimeofday(&_timerStart, NULL); gettimeofday(&_lastTimeIdle, NULL); + + loadSettings(); } void Application::updateAvatar(float deltaTime) { @@ -2357,95 +2201,85 @@ void* Application::networkReceive(void* args) { return NULL; } -void Application::saveSettings() -{ - // Handle any persistent settings saving here when we get a call to terminate. - // This should probably be moved to a map stored in memory at some point to cache settings. - _myAvatar.writeAvatarDataToFile(); - - setSetting("_gyroLook", _gyroLook->isChecked()); - - setSetting("_mouseLook", _mouseLook->isChecked()); - - setSetting("_transmitterDrives", _transmitterDrives->isChecked()); - - setSetting("_renderVoxels", _renderVoxels->isChecked()); - - setSetting("_renderVoxelTextures", _renderVoxelTextures->isChecked()); - - setSetting("_renderStarsOn", _renderStarsOn->isChecked()); - - setSetting("_renderAtmosphereOn", _renderAtmosphereOn->isChecked()); - - setSetting("_renderAvatarsOn", _renderAvatarsOn->isChecked()); - - setSetting("_renderStatsOn", _renderStatsOn->isChecked()); - - setSetting("_renderFrameTimerOn", _renderFrameTimerOn->isChecked()); - - setSetting("_renderLookatOn", _renderLookatOn->isChecked()); - - setSetting("_logOn", _logOn->isChecked()); - - setSetting("_frustumOn", _frustumOn->isChecked()); - - setSetting("_viewFrustumFromOffset", _viewFrustumFromOffset->isChecked()); - - setSetting("_cameraFrustum", _cameraFrustum->isChecked()); - - saveSettingsFile(); +void Application::scanMenuBar(settingsAction f, QSettings *set) { + if (NULL == _window->menuBar()) { + return; + } + + QList menus = _window->menuBar()->findChildren(); + + for (QList::const_iterator it = menus.begin(); menus.end() != it; ++it) { + scanMenu(*it, f, set); + } } -void Application::readSettings() -{ - readSettingsFile(); - _myAvatar.readAvatarDataFromFile(); - - bool settingState; - getSetting("_gyroLook", settingState, _gyroLook->isChecked()); - _gyroLook->setChecked(settingState); - - getSetting("_mouseLook", settingState, _mouseLook->isChecked()); - _mouseLook->setChecked(settingState); - - getSetting("_transmitterDrives", settingState, _transmitterDrives->isChecked()); - _transmitterDrives->setChecked(settingState); - - getSetting("_renderVoxels", settingState, _renderVoxels->isChecked()); - _renderVoxels->setChecked(settingState); - - getSetting("_renderVoxelTextures", settingState, _renderVoxelTextures->isChecked()); - _renderVoxelTextures->setChecked(settingState); - - getSetting("_renderStarsOn", settingState, _renderStarsOn->isChecked()); - _renderStarsOn->setChecked(settingState); - - getSetting("_renderAtmosphereOn", settingState, _renderAtmosphereOn->isChecked()); - _renderAtmosphereOn->setChecked(settingState); - - getSetting("_renderAvatarsOn", settingState, _renderAvatarsOn->isChecked()); - _renderAvatarsOn->setChecked(settingState); - - getSetting("_renderStatsOn", settingState, _renderStatsOn->isChecked()); - _renderStatsOn->setChecked(settingState); - - getSetting("_renderFrameTimerOn", settingState, _renderFrameTimerOn->isChecked()); - _renderFrameTimerOn->setChecked(settingState); - - getSetting("_renderLookatOn", settingState, _renderLookatOn->isChecked()); - _renderLookatOn->setChecked(settingState); - - getSetting("_logOn", settingState, _logOn->isChecked()); - _logOn->setChecked(settingState); - - getSetting("_frustumOn", settingState, _frustumOn->isChecked()); - _frustumOn->setChecked(settingState); - - getSetting("_viewFrustumFromOffset", settingState, _viewFrustumFromOffset->isChecked()); - _viewFrustumFromOffset->setChecked(settingState); - - getSetting("_cameraFrustum", settingState, _cameraFrustum->isChecked()); - _cameraFrustum->setChecked(settingState); - +void Application::scanMenu(QMenu *menu, settingsAction f, QSettings *set) { + QList actions = menu->actions(); + + set->beginGroup(menu->title()); + for (QList::const_iterator it = actions.begin(); actions.end() != it; ++it) { + if ((*it)->menu()) { + scanMenu((*it)->menu(), f, set); + } + if ((*it)->isCheckable()) { + f(set, *it); + } + } + set->endGroup(); } +void Application::loadAction(QSettings *set, QAction *action) { + action->setChecked(set->value(action->text(), action->isChecked()).toBool()); + } + +void Application::saveAction(QSettings *set, QAction *action) { + set->setValue(action->text(), action->isChecked()); +} + +void Application::setAutosave(bool wantsAutosave) { + _autosave = wantsAutosave; +} + +void Application::loadSettings(QSettings *set) { + if (!set) set = this->getSettings(); + + scanMenuBar(&Application::loadAction, set); + getAvatar()->getData(set); +} + +void Application::saveSettings(QSettings *set) { + if (!set) set = this->getSettings(); + + scanMenuBar(&Application::saveAction, set); + getAvatar()->setData(set); +} + +void Application::importSettings() { + QString fileName = QFileDialog::getOpenFileName(this->_window, + tr("Open .ini config file"), + "", + tr("Text files (*.ini)")); + + if (fileName != "") { + QSettings tmp(fileName, QSettings::IniFormat); + + loadSettings(&tmp); + } +} + +void Application::exportSettings() { + QString fileName = QFileDialog::getSaveFileName(this->_window, + tr("Save .ini config file"), + "", + tr("Text files (*.ini)")); + + if (fileName != "") { + QSettings tmp(fileName, QSettings::IniFormat); + + saveSettings(&tmp); + + tmp.sync(); + } +} + + diff --git a/interface/src/Application.h b/interface/src/Application.h index 22694aaae5..4a5cb04622 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -15,6 +15,8 @@ #include #include +#include +#include #include @@ -66,59 +68,9 @@ public: Avatar* getAvatar() { return &_myAvatar; } Camera* getCamera() { return &_myCamera; } VoxelSystem* getVoxels() { return &_voxels; } + QSettings* getSettings() { return &_settings; } Environment* getEnvironment() { return &_environment; } bool shouldEchoAudio() { return _echoAudioMode->isChecked(); } - - /*! - @fn getSettingBool - @brief A function for getting boolean settings from the settings file. - @param settingName The desired setting to get the value for. - @param boolSetting The referenced variable where the setting will be stored. - @param defaultSetting The default setting to assign to boolSetting if this function fails to find the appropriate setting. Defaults to false. - */ - bool getSetting(const char* setting, bool &value, const bool defaultSetting = false) const; - - /*! - @fn getSettingFloat - @brief A function for getting float settings from the settings file. - @param settingName The desired setting to get the value for. - @param floatSetting The referenced variable where the setting will be stored. - @param defaultSetting The default setting to assign to boolSetting if this function fails to find the appropriate setting. Defaults to 0.0f. - */ - bool getSetting(const char* setting, float &value, const float defaultSetting = 0.0f) const; - - /*! - @fn getSettingVec3 - @brief A function for getting boolean settings from the settings file. - @param settingName The desired setting to get the value for. - @param vecSetting The referenced variable where the setting will be stored. - @param defaultSetting The default setting to assign to boolSetting if this function fails to find the appropriate setting. Defaults to <0.0f, 0.0f, 0.0f> - */ - bool getSetting(const char* setting, glm::vec3 &value, const glm::vec3& defaultSetting = glm::vec3(0.0f, 0.0f, 0.0f)) const; - - /*! - @fn setSettingBool - @brief A function for setting boolean setting values when saving the settings file. - @param settingName The desired setting to populate a value for. - @param boolSetting The value to set. - */ - void setSetting(const char* setting, const bool value); - - /*! - @fn setSettingFloat - @brief A function for setting boolean setting values when saving the settings file. - @param settingName The desired setting to populate a value for. - @param floatSetting The value to set. - */ - void setSetting(const char* setting, const float value); - - /*! - @fn setSettingVec3 - @brief A function for setting boolean setting values when saving the settings file. - @param settingName The desired setting to populate a value for. - @param vecSetting The value to set. - */ - void setSetting(const char* setting, const glm::vec3& value); private slots: @@ -154,6 +106,12 @@ private slots: void decreaseVoxelSize(); void increaseVoxelSize(); void chooseVoxelPaintColor(); + + void setAutosave(bool wantsAutosave); + void loadSettings(QSettings *set = NULL); + void saveSettings(QSettings *set = NULL); + void importSettings(); + void exportSettings(); private: @@ -189,13 +147,13 @@ private: static void attachNewHeadToAgent(Agent *newAgent); static void* networkReceive(void* args); - // These two functions are technically not necessary, but they help keep things in one place. - void readSettings(); //! This function is largely to help consolidate getting settings in one place. - void saveSettings(); //! This function is to consolidate any settings setting in one place. - - void readSettingsFile(); //! This function reads data from the settings file, splitting data into key value pairs using '=' as a delimiter. - void saveSettingsFile(); //! This function writes all changes in the settings table to the settings file, serializing all settings added through the setSetting functions. - + // methodes handling menu settings + typedef void(*settingsAction)(QSettings *, QAction *); + static void loadAction(QSettings *set, QAction *action); + static void saveAction(QSettings *set, QAction *action); + void scanMenuBar(settingsAction, QSettings *set); + void scanMenu(QMenu *menu, settingsAction f, QSettings *set); + QMainWindow* _window; QGLWidget* _glWidget; @@ -225,6 +183,7 @@ private: 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 SerialInterface _serialPort; bool _displayLevels; @@ -315,11 +274,8 @@ private: int _bytesPerSecond; int _bytesCount; - /*! - * Store settings in a map, storing keys and values as strings. - * Interpret values as needed on demand. through the appropriate getters and setters. - */ - std::map _settingsTable; + QSettings _settings; // Contain Menu settings and Avatar data + bool _autosave; // True if the autosave is on. }; #endif /* defined(__interface__Application__) */ diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 46a4d302ca..7d2aa9784d 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -1114,28 +1114,38 @@ void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity } } -void Avatar::writeAvatarDataToFile() { - Application::getInstance()->setSetting("avatarPos", _position); - Application::getInstance()->setSetting("avatarRotation", glm::vec3(_bodyYaw, _bodyPitch, _bodyRoll)); +void Avatar::getData(QSettings *set) { + set->beginGroup("Avatar"); + + _bodyYaw = set->value("bodyYawn", _bodyYaw).toFloat(); + _bodyPitch = set->value("bodyPitch", _bodyPitch).toFloat(); + _bodyRoll = set->value("bodyRoll", _bodyRoll).toFloat(); + + _position.x = set->value("position_x", _position.x).toFloat(); + _position.y = set->value("position_y", _position.y).toFloat(); + _position.z = set->value("position_z", _position.z).toFloat(); + + set->endGroup(); } -void Avatar::readAvatarDataFromFile() { - glm::vec3 readPosition; - glm::vec3 readRotation; - - Application::getInstance()->getSetting("avatarPos", readPosition, glm::vec3(6.1f, 0, 1.4f)); - Application::getInstance()->getSetting("avatarRotation", readRotation, glm::vec3(0, 0, 0)); - - _bodyYaw = readRotation.x; - _bodyPitch = readRotation.y; - _bodyRoll = readRotation.z; - _position = readPosition; +void Avatar::setData(QSettings *set) { + set->beginGroup("Avatar"); + + set->setValue("bodyYawn", _bodyYaw); + set->setValue("bodyPitch", _bodyPitch); + set->setValue("bodyRoll", _bodyRoll); + + set->setValue("position_x", _position.x); + set->setValue("position_y", _position.y); + set->setValue("position_z", _position.z); + + set->endGroup(); } // render a makeshift cone section that serves as a body part connecting joint spheres void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2) { - glBegin(GL_TRIANGLES); + glBegin(GL_TRIANGLES); glm::vec3 axis = position2 - position1; float length = glm::length(axis); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 6746ba51cd..3b18ed1c1e 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -11,6 +11,7 @@ #include #include #include +#include #include "world.h" #include "AvatarTouch.h" #include "InterfaceConfig.h" @@ -95,9 +96,9 @@ public: void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; glm::vec3 getThrust() { return _thrust; }; - //read/write avatar data - void writeAvatarDataToFile(); - void readAvatarDataFromFile(); + // get/set avatar data + void setData(QSettings *set); + void getData(QSettings *set); private: // privatize copy constructor and assignment operator to avoid copying From 8d757e148fb5007b0f12a50c7e794fe78262ae52 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Sun, 2 Jun 2013 19:55:51 -0700 Subject: [PATCH 14/73] More work on voxeltars; basic skinning works. --- interface/src/Avatar.cpp | 19 ++-- interface/src/Avatar.h | 8 +- interface/src/AvatarVoxelSystem.cpp | 141 ++++++++++++++++++++-------- interface/src/AvatarVoxelSystem.h | 9 +- interface/src/Skeleton.cpp | 13 ++- interface/src/Skeleton.h | 11 ++- interface/src/VoxelSystem.cpp | 25 +++-- interface/src/VoxelSystem.h | 15 +-- 8 files changed, 168 insertions(+), 73 deletions(-) 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 From 9e046b74e67b457fdae56b7fb7bf238574145d47 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 08:09:27 -0700 Subject: [PATCH 15/73] working on avatar touch --- interface/src/Application.cpp | 39 +++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index fe84ec4748..e0e5ea8046 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -50,6 +50,8 @@ using namespace std; +const bool TESTING_AVATAR_TOUCH = false; + // Starfield information static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; static char STAR_CACHE_FILE[] = "cachedStars.txt"; @@ -1078,24 +1080,31 @@ void Application::idle() { _myAvatar.simulate(deltaTime, NULL); } - if (_myCamera.getMode() != CAMERA_MODE_MIRROR && !OculusManager::isConnected()) { - if (_manualFirstPerson) { - if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) { - _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); - _myCamera.setModeShiftRate(1.0f); - } - } else { - - if (_myAvatar.getIsNearInteractingOther()) { - if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { + if (TESTING_AVATAR_TOUCH) { + if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { + _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); + _myCamera.setModeShiftRate(1.0f); + } + } else { + if (_myCamera.getMode() != CAMERA_MODE_MIRROR && !OculusManager::isConnected()) { + if (_manualFirstPerson) { + if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON ) { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setModeShiftRate(1.0f); } - } - else { - if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { - _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); - _myCamera.setModeShiftRate(1.0f); + } else { + + if (_myAvatar.getIsNearInteractingOther()) { + if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { + _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); + _myCamera.setModeShiftRate(1.0f); + } + } + else { + if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { + _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); + _myCamera.setModeShiftRate(1.0f); + } } } } From cf67f28b57eb4c7eda9f3f4c9a6c8c45ac637337 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 08:10:41 -0700 Subject: [PATCH 16/73] merge --- .../resources/shaders/SkyFromAtmosphere.frag | 212 +++++++++--------- 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/interface/resources/shaders/SkyFromAtmosphere.frag b/interface/resources/shaders/SkyFromAtmosphere.frag index b640f5f952..dbefc8270e 100644 --- a/interface/resources/shaders/SkyFromAtmosphere.frag +++ b/interface/resources/shaders/SkyFromAtmosphere.frag @@ -1,106 +1,106 @@ -#version 120 - -// -// For licensing information, see http://http.developer.nvidia.com/GPUGems/gpugems_app01.html: -// -// NVIDIA Statement on the Software -// -// The source code provided is freely distributable, so long as the NVIDIA header remains unaltered and user modifications are -// detailed. -// -// No Warranty -// -// THE SOFTWARE AND ANY OTHER MATERIALS PROVIDED BY NVIDIA ON THE ENCLOSED CD-ROM ARE PROVIDED "AS IS." NVIDIA DISCLAIMS ALL -// WARRANTIES, EXPRESS, IMPLIED OR STATUTORY, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -// -// Limitation of Liability -// -// NVIDIA SHALL NOT BE LIABLE TO ANY USER, DEVELOPER, DEVELOPER'S CUSTOMERS, OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH OR -// UNDER DEVELOPER FOR ANY LOSS OF PROFITS, INCOME, SAVINGS, OR ANY OTHER CONSEQUENTIAL, INCIDENTAL, SPECIAL, PUNITIVE, DIRECT -// OR INDIRECT DAMAGES (WHETHER IN AN ACTION IN CONTRACT, TORT OR BASED ON A WARRANTY), EVEN IF NVIDIA HAS BEEN ADVISED OF THE -// POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF THE ESSENTIAL PURPOSE OF ANY -// LIMITED REMEDY. IN NO EVENT SHALL NVIDIA'S AGGREGATE LIABILITY TO DEVELOPER OR ANY OTHER PERSON OR ENTITY CLAIMING THROUGH -// OR UNDER DEVELOPER EXCEED THE AMOUNT OF MONEY ACTUALLY PAID BY DEVELOPER TO NVIDIA FOR THE SOFTWARE OR ANY OTHER MATERIALS. -// - -// -// Atmospheric scattering fragment shader -// -// Author: Sean O'Neil -// -// Copyright (c) 2004 Sean O'Neil -// - -uniform vec3 v3CameraPos; // The camera's current position -uniform vec3 v3InvWavelength; // 1 / pow(wavelength, 4) for the red, green, and blue channels -uniform float fInnerRadius; // The inner (planetary) radius -uniform float fKrESun; // Kr * ESun -uniform float fKmESun; // Km * ESun -uniform float fKr4PI; // Kr * 4 * PI -uniform float fKm4PI; // Km * 4 * PI -uniform float fScale; // 1 / (fOuterRadius - fInnerRadius) -uniform float fScaleDepth; // The scale depth (i.e. the altitude at which the atmosphere's average density is found) -uniform float fScaleOverScaleDepth; // fScale / fScaleDepth - -const int nSamples = 2; -const float fSamples = 2.0; - -uniform vec3 v3LightPos; -uniform float g; -uniform float g2; - -varying vec3 position; - -float scale(float fCos) -{ - float x = 1.0 - fCos; - return fScaleDepth * exp(-0.00287 + x*(0.459 + x*(3.83 + x*(-6.80 + x*5.25)))); -} - -void main (void) -{ - // Get the ray from the camera to the vertex, and its length (which is the far point of the ray passing through the atmosphere) - vec3 v3Pos = position; - vec3 v3Ray = v3Pos - v3CameraPos; - float fFar = length(v3Ray); - v3Ray /= fFar; - - // Calculate the ray's starting position, then calculate its scattering offset - vec3 v3Start = v3CameraPos; - float fHeight = length(v3Start); - float fDepth = exp(fScaleOverScaleDepth * (fInnerRadius - fHeight)); - float fStartAngle = dot(v3Ray, v3Start) / fHeight; - float fStartOffset = fDepth * scale(fStartAngle); - - // Initialize the scattering loop variables - //gl_FrontColor = vec4(0.0, 0.0, 0.0, 0.0); - float fSampleLength = fFar / fSamples; - float fScaledLength = fSampleLength * fScale; - vec3 v3SampleRay = v3Ray * fSampleLength; - vec3 v3SamplePoint = v3Start + v3SampleRay * 0.5; - - // Now loop through the sample rays - vec3 v3FrontColor = vec3(0.0, 0.0, 0.0); - for(int i=0; i Date: Mon, 3 Jun 2013 10:08:42 -0700 Subject: [PATCH 17/73] Slight fix to capsule/box penetration test: we should use the smaller distance to the diagonal, not the first one we find. --- interface/src/AvatarVoxelSystem.cpp | 4 +--- libraries/voxels/src/AABox.cpp | 7 +++++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 50c8ca8a71..d6b51bec82 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -7,8 +7,6 @@ #include -#include - #include "Avatar.h" #include "AvatarVoxelSystem.h" #include "renderer/ProgramObject.h" @@ -201,7 +199,7 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo 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); + weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); totalWeight += weights[i]; } diff --git a/libraries/voxels/src/AABox.cpp b/libraries/voxels/src/AABox.cpp index b7580b243e..1b29c70b59 100644 --- a/libraries/voxels/src/AABox.cpp +++ b/libraries/voxels/src/AABox.cpp @@ -292,13 +292,16 @@ glm::vec3 AABox::getClosestPointOnFace(const glm::vec4& origin, const glm::vec4& 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 } - float directionalDistance = -glm::dot(origin, diagonals[i]) / divisor; - return getClosestPointOnFace(glm::vec3(origin + direction * directionalDistance), face); + minDistance = glm::min(-glm::dot(origin, diagonals[i]) / divisor, minDistance); + } + if (minDistance != FLT_MAX) { + return getClosestPointOnFace(glm::vec3(origin + direction * minDistance), face); } } From 7dd217b3182eb6df44439d53c60a0accbd25c821 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 10:57:18 -0700 Subject: [PATCH 18/73] more work on copy and paste --- interface/src/Application.cpp | 79 +++++++++++++++++++------------ libraries/shared/src/SharedUtil.h | 2 +- 2 files changed, 50 insertions(+), 31 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 5395bfa54f..30f4d958a2 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1002,7 +1002,7 @@ void Application::idle() { _mouseVoxel.z += faceVector.z * _mouseVoxel.s; } } - } else if (_addVoxelMode->isChecked()) { + } else if (_addVoxelMode->isChecked() || _selectVoxelMode->isChecked()) { // place the voxel a fixed distance away float worldMouseVoxelScale = _mouseVoxelScale * TREE_SCALE; glm::vec3 pt = mouseRayOrigin + mouseRayDirection * (2.0f + worldMouseVoxelScale * 0.5f); @@ -1318,11 +1318,16 @@ void Application::copyVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); printf("copyVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { - selectedNode->printDebugDetails("selected voxel"); + //selectedNode->printDebugDetails("selected voxel"); + + // clear the clipboard first... + _clipboardTree.eraseAllVoxels(); + + // then copy onto it _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboardTree, true); // debug tree - _clipboardTree.printTreeForDebugging(_clipboardTree.rootNode); + //_clipboardTree.printTreeForDebugging(_clipboardTree.rootNode); } } @@ -1335,25 +1340,37 @@ struct SendVoxelsOperataionArgs { }; void Application::pasteVoxels() { + unsigned char* calculatedOctCode = NULL; VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); printf("pasteVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + + // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to + // the server as an set voxel message, this will also rebase the voxels to the new location + SendVoxelsOperataionArgs args; + args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; + unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; + *sequenceAt = 0; + args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence + + // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the + // voxel size/position details. if (selectedNode) { //selectedNode->printDebugDetails("selected voxel"); - - // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to - // the server as an set voxel message, this will also rebase the voxels to the new location - SendVoxelsOperataionArgs args; - args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; - unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; - *sequenceAt = 0; - args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence args.newBaseOctCode = selectedNode->getOctalCode(); - _clipboardTree.recurseTreeWithOperation(sendVoxelsOperataion, &args); - - // If we have voxels left in the packet, then send the packet - if (args.bufferInUse > 1) { - AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); - } + } else { + printf("pasteVoxels() no voxel at current location, calculate octCode... \n"); + args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + } + + _clipboardTree.recurseTreeWithOperation(sendVoxelsOperataion, &args); + + // If we have voxels left in the packet, then send the packet + if (args.bufferInUse > 1) { + AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); + } + + if (calculatedOctCode) { + delete calculatedOctCode; } } @@ -1449,33 +1466,35 @@ void Application::initMenu() { QMenu* voxelMenu = menuBar->addMenu("Voxels"); _voxelModeActions = new QActionGroup(this); _voxelModeActions->setExclusive(false); // exclusivity implies one is always checked + (_addVoxelMode = voxelMenu->addAction( - "Add Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_A))->setCheckable(true); + "Add Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_A))->setCheckable(true); _voxelModeActions->addAction(_addVoxelMode); (_deleteVoxelMode = voxelMenu->addAction( - "Delete Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_D))->setCheckable(true); + "Delete Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_D))->setCheckable(true); _voxelModeActions->addAction(_deleteVoxelMode); (_colorVoxelMode = voxelMenu->addAction( - "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_C))->setCheckable(true); + "Color Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_B))->setCheckable(true); _voxelModeActions->addAction(_colorVoxelMode); (_selectVoxelMode = voxelMenu->addAction( - "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::SHIFT | Qt::Key_S))->setCheckable(true); + "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_S))->setCheckable(true); _voxelModeActions->addAction(_selectVoxelMode); - voxelMenu->addAction("Place Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::SHIFT | Qt::Key_P); - voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), Qt::CTRL | Qt::SHIFT | Qt::Key_Minus); - voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), Qt::CTRL | Qt::SHIFT | Qt::Key_Plus); + voxelMenu->addAction("Place New Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::Key_N); + voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), QKeySequence::ZoomOut); + voxelMenu->addAction("Increase Voxel Size", this, SLOT(increaseVoxelSize()), QKeySequence::ZoomIn); - _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), - Qt::CTRL | Qt::SHIFT | Qt::Key_C); + _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, + SLOT(chooseVoxelPaintColor()), Qt::META | Qt::Key_C); QColor paintColor(128, 128, 128); _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); (_destructiveAddVoxel = voxelMenu->addAction("Create Voxel is Destructive"))->setCheckable(true); - voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); - voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); - voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C); - voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V); + + voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); + voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); + voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C); + voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V); QMenu* frustumMenu = menuBar->addMenu("Frustum"); (_frustumOn = frustumMenu->addAction("Display Frustum"))->setCheckable(true); diff --git a/libraries/shared/src/SharedUtil.h b/libraries/shared/src/SharedUtil.h index 8da9d7beca..6c48c9e42e 100644 --- a/libraries/shared/src/SharedUtil.h +++ b/libraries/shared/src/SharedUtil.h @@ -70,7 +70,7 @@ struct VoxelDetail { unsigned char blue; }; -unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r, unsigned char g, unsigned char b ); +unsigned char* pointToVoxel(float x, float y, float z, float s, unsigned char r = 0, unsigned char g = 0, unsigned char b = 0); bool createVoxelEditMessage(unsigned char command, short int sequence, int voxelCount, VoxelDetail* voxelDetails, unsigned char*& bufferOut, int& sizeOut); From 8d031b5c2d4a075fbe039bf708163437544c6de7 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 11:53:00 -0700 Subject: [PATCH 19/73] preparation for extending the avatar ball array to accommodate more touch capabilities --- interface/src/Application.cpp | 10 +++--- interface/src/Audio.cpp | 2 +- interface/src/Avatar.cpp | 43 +++++++++++----------- interface/src/Avatar.h | 68 ++++++++++++++++++++++++----------- interface/src/Skeleton.h | 4 +-- 5 files changed, 77 insertions(+), 50 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e0e5ea8046..130bd5e7fe 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -289,22 +289,22 @@ void Application::paintGL() { if (_myCamera.getMode() == CAMERA_MODE_MIRROR) { _myCamera.setTightness (100.0f); - _myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition()); + _myCamera.setTargetPosition(_myAvatar.getBallPosition(AVATAR_JOINT_HEAD_BASE)); _myCamera.setTargetRotation(_myAvatar.getWorldAlignedOrientation() * glm::quat(glm::vec3(0.0f, PI, 0.0f))); } else if (OculusManager::isConnected()) { _myCamera.setUpShift (0.0f); _myCamera.setDistance (0.0f); _myCamera.setTightness (100.0f); - _myCamera.setTargetPosition(_myAvatar.getHeadPosition()); + _myCamera.setTargetPosition(_myAvatar.getHeadJointPosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_FIRST_PERSON) { - _myCamera.setTargetPosition(_myAvatar.getSpringyHeadPosition()); + _myCamera.setTargetPosition(_myAvatar.getBallPosition(AVATAR_JOINT_HEAD_BASE)); _myCamera.setTargetRotation(_myAvatar.getHead().getWorldAlignedOrientation()); } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { - _myCamera.setTargetPosition(_myAvatar.getHeadPosition()); + _myCamera.setTargetPosition(_myAvatar.getHeadJointPosition()); _myCamera.setTargetRotation(_myAvatar.getHead().getWorldAlignedOrientation()); } @@ -1556,7 +1556,7 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { if (_cameraFrustum->isChecked()) { position = camera.getPosition(); } else { - position = _myAvatar.getHeadPosition(); + position = _myAvatar.getHeadJointPosition(); } float fov = camera.getFieldOfView(); diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 97929a99ca..3f5068a577 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -143,7 +143,7 @@ int audioCallback (const void* inputBuffer, unsigned char *currentPacketPtr = dataPacket + 1; // memcpy the three float positions - memcpy(currentPacketPtr, &interfaceAvatar->getHeadPosition(), sizeof(float) * 3); + memcpy(currentPacketPtr, &interfaceAvatar->getHeadJointPosition(), sizeof(float) * 3); currentPacketPtr += (sizeof(float) * 3); // tell the mixer not to add additional attenuation to our source diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 46a4d302ca..c02a6ccaa7 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -118,16 +118,18 @@ Avatar::Avatar(Agent* owningAgent) : void Avatar::initializeBodyBalls() { - for (int b=0; b 0.0) { glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; - - _bodyBall[b].velocity += collisionForce * 0.0f * deltaTime; - _velocity += collisionForce * 40.0f * deltaTime; + + _velocity += collisionForce * 40.0f * deltaTime; _bodyBall[b].position = position + directionVector * combinedRadius; } } @@ -760,11 +759,11 @@ void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f); - // loop through the joints of each avatar to check for every possible collision - for (int b=1; b_bodyBall[o].isCollidable) { glm::vec3 vectorBetweenJoints(_bodyBall[b].position - otherAvatar->_bodyBall[o].position); @@ -893,8 +892,8 @@ void Avatar::render(bool lookingInMirror) { } void Avatar::resetBodyBalls() { - for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { - _bodyBall[b].position = _skeleton.joint[b].position; + for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { + _bodyBall[b].position = _skeleton.joint[b].position; // put balls on joints _bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } } @@ -905,7 +904,7 @@ void Avatar::updateBodyBalls(float deltaTime) { if (glm::length(_position - _bodyBall[AVATAR_JOINT_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { resetBodyBalls(); } - for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { + for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { glm::vec3 springVector(_bodyBall[b].position); if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL) { @@ -942,8 +941,8 @@ void Avatar::updateBodyBalls(float deltaTime) { /* //apply forces from touch... - if (_skeleton.joint[b].touchForce > 0.0) { - _skeleton.joint[b].springyVelocity += _mouseRayDirection * _skeleton.joint[b].touchForce * 0.7f; + if (_bodyBall[b].touchForce > 0.0) { + _bodyBall[b].velocity += _mouseRayDirection * _bodyBall[b].touchForce * 0.7f; } */ @@ -1010,8 +1009,8 @@ void Avatar::renderBody(bool lookingInMirror) { const float RENDER_TRANSLUCENT_BEYOND = 0.5f; // Render the body as balls and cones - for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { - float distanceToCamera = glm::length(_cameraPosition - _skeleton.joint[b].position); + for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { + float distanceToCamera = glm::length(_cameraPosition - _bodyBall[b].position); float alpha = lookingInMirror ? 1.0f : glm::clamp((distanceToCamera - RENDER_TRANSLUCENT_BEYOND) / (RENDER_OPAQUE_BEYOND - RENDER_TRANSLUCENT_BEYOND), 0.f, 1.f); @@ -1029,7 +1028,7 @@ void Avatar::renderBody(bool lookingInMirror) { || b == AVATAR_JOINT_RIGHT_ELBOW || b == AVATAR_JOINT_RIGHT_WRIST || b == AVATAR_JOINT_RIGHT_FINGERTIPS ) { - // Render the sphere at the joint + // Render the body ball sphere if (_owningAgent || b == AVATAR_JOINT_RIGHT_ELBOW || b == AVATAR_JOINT_RIGHT_WRIST || b == AVATAR_JOINT_RIGHT_FINGERTIPS ) { @@ -1051,7 +1050,7 @@ void Avatar::renderBody(bool lookingInMirror) { glPopMatrix(); } - // Render the cone connecting this joint to its parent + // Render the cone connecting this ball to its parent if (_skeleton.joint[b].parent != AVATAR_JOINT_NULL) { if ((b != AVATAR_JOINT_HEAD_TOP ) && (b != AVATAR_JOINT_HEAD_BASE ) diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 6746ba51cd..c1303287be 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -20,6 +20,37 @@ #include "Skeleton.h" #include "Transmitter.h" + +enum AvatarBodyBallID +{ + BODY_BALL_NULL = -1, + BODY_BALL_PELVIS, + BODY_BALL_TORSO, + BODY_BALL_CHEST, + BODY_BALL_NECK_BASE, + BODY_BALL_HEAD_BASE, + BODY_BALL_HEAD_TOP, + BODY_BALL_LEFT_COLLAR, + BODY_BALL_LEFT_SHOULDER, + BODY_BALL_LEFT_ELBOW, + BODY_BALL_LEFT_WRIST, + BODY_BALL_LEFT_FINGERTIPS, + BODY_BALL_RIGHT_COLLAR, + BODY_BALL_RIGHT_SHOULDER, + BODY_BALL_RIGHT_ELBOW, + BODY_BALL_RIGHT_WRIST, + BODY_BALL_RIGHT_FINGERTIPS, + BODY_BALL_LEFT_HIP, + BODY_BALL_LEFT_KNEE, + BODY_BALL_LEFT_HEEL, + BODY_BALL_LEFT_TOES, + BODY_BALL_RIGHT_HIP, + BODY_BALL_RIGHT_KNEE, + BODY_BALL_RIGHT_HEEL, + BODY_BALL_RIGHT_TOES, + NUM_AVATAR_BODY_BALLS +}; + enum DriveKeys { FWD = 0, @@ -64,19 +95,14 @@ public: void setOrientation (const glm::quat& orientation); //getters - - float getHeadYawRate () const { return _head.yawRate;} - float getBodyYaw () const { return _bodyYaw;} - bool getIsNearInteractingOther() const { return _avatarTouch.getAbleToReachOtherAvatar();} - const glm::vec3& getHeadPosition () const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position;} - const glm::vec3& getSpringyHeadPosition () const { return _bodyBall[ AVATAR_JOINT_HEAD_BASE ].position;} - const glm::vec3& getJointPosition (AvatarJointID j) const { return _bodyBall[j].position;} - - glm::vec3 getBodyRightDirection () const { return getOrientation() * AVATAR_RIGHT; } - glm::vec3 getBodyUpDirection () const { return getOrientation() * AVATAR_UP; } - glm::vec3 getBodyFrontDirection () const { return getOrientation() * AVATAR_FRONT; } - - + float getHeadYawRate () const { return _head.yawRate;} + float getBodyYaw () const { return _bodyYaw;} + bool getIsNearInteractingOther () const { return _avatarTouch.getAbleToReachOtherAvatar();} + const glm::vec3& getHeadJointPosition () const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position;} + const glm::vec3& getBallPosition (AvatarJointID j) const { return _bodyBall[j].position;} + glm::vec3 getBodyRightDirection () const { return getOrientation() * AVATAR_RIGHT; } + glm::vec3 getBodyUpDirection () const { return getOrientation() * AVATAR_UP; } + glm::vec3 getBodyFrontDirection () const { return getOrientation() * AVATAR_FRONT; } const glm::vec3& getVelocity () const { return _velocity;} float getSpeed () const { return _speed;} float getHeight () const { return _height;} @@ -106,12 +132,14 @@ private: struct AvatarBall { - glm::vec3 position; - glm::vec3 velocity; - float jointTightness; - float radius; - bool isCollidable; - float touchForce; + AvatarJointID parent; + glm::vec3 parentOffset; + glm::vec3 position; + glm::vec3 velocity; + float jointTightness; + float radius; + bool isCollidable; + float touchForce; }; Head _head; @@ -124,7 +152,7 @@ private: float _bodyRollDelta; glm::vec3 _movedHandOffset; glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion - AvatarBall _bodyBall[ NUM_AVATAR_JOINTS ]; + AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ]; AvatarMode _mode; glm::vec3 _cameraPosition; glm::vec3 _handHoldingPosition; diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index 4c1152728d..28d3a6e81e 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -60,9 +60,9 @@ public: { 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 defaultPosePosition; // the parent relative position when the avatar is in the default 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 + float length; // the length of vector between the joint and its parent }; AvatarJoint joint[ NUM_AVATAR_JOINTS ]; From 00dce6b59e0ae18125e75d346b6f922d87370d36 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 12:01:01 -0700 Subject: [PATCH 20/73] fix --- interface/src/Avatar.cpp | 2 +- interface/src/Avatar.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index c02a6ccaa7..6d2f0eefad 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -119,7 +119,7 @@ Avatar::Avatar(Agent* owningAgent) : void Avatar::initializeBodyBalls() { for (int b=0; b Date: Mon, 3 Jun 2013 12:10:18 -0700 Subject: [PATCH 21/73] don't attempt to send microphone audio if AgentList is NULL --- interface/src/Audio.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index 97929a99ca..995cb12a7f 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -116,7 +116,7 @@ int audioCallback (const void* inputBuffer, printLog("got output\n"); } - if (inputLeft) { + if (agentList && inputLeft) { // Measure the loudness of the signal from the microphone and store in audio object float loudness = 0; From f3ce68e5e4c40c34e67db5e4195a3a99b9207f84 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Jun 2013 12:21:44 -0700 Subject: [PATCH 22/73] remove space at the top of PacketHeaders --- libraries/shared/src/PacketHeaders.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/shared/src/PacketHeaders.h b/libraries/shared/src/PacketHeaders.h index 850eced59b..ea9f5f9fcf 100644 --- a/libraries/shared/src/PacketHeaders.h +++ b/libraries/shared/src/PacketHeaders.h @@ -1,4 +1,3 @@ - // // PacketHeaders.h // hifi From 78fe89172ac221ad59e8bfab4c478234c5a62c0e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 12:23:16 -0700 Subject: [PATCH 23/73] eyedropper mode, and import work --- interface/src/Application.cpp | 150 ++++++++++++++++++-------- interface/src/Application.h | 3 +- libraries/voxels/src/VoxelConstants.h | 9 +- 3 files changed, 115 insertions(+), 47 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 30f4d958a2..ab335dce97 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1285,6 +1285,58 @@ void Application::chooseVoxelPaintColor() { _window->activateWindow(); } +const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500; +struct SendVoxelsOperataionArgs { + unsigned char* newBaseOctCode; + unsigned char messageBuffer[MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE]; + int bufferInUse; + +}; + +bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { + SendVoxelsOperataionArgs* args = (SendVoxelsOperataionArgs*)extraData; + if (node->isColored()) { + unsigned char* nodeOctalCode = node->getOctalCode(); + printOctalCode(nodeOctalCode); + + unsigned char* codeColorBuffer = NULL; + int codeLength = 0; + int bytesInCode = 0; + int codeAndColorLength; + + // If the newBase is NULL, then don't rebase + if (args->newBaseOctCode) { + codeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true); + printOctalCode(codeColorBuffer); + codeLength = numberOfThreeBitSectionsInCode(codeColorBuffer); + bytesInCode = bytesRequiredForCodeLength(codeLength); + codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA; + } else { + codeLength = numberOfThreeBitSectionsInCode(nodeOctalCode); + bytesInCode = bytesRequiredForCodeLength(codeLength); + codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA; + codeColorBuffer = new unsigned char[codeAndColorLength]; + memcpy(codeColorBuffer, nodeOctalCode, bytesInCode); + } + + // copy the colors over + codeColorBuffer[bytesInCode + RED_INDEX ] = node->getColor()[RED_INDEX ]; + codeColorBuffer[bytesInCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX]; + codeColorBuffer[bytesInCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ]; + + // if we have room don't have room in the buffer, then send the previously generated message first + if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { + AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL, 1); + args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(int); // reset to command + sequence + } + + // copy this node's code color details into our buffer. + memcpy(&args->messageBuffer[args->bufferInUse], codeColorBuffer, codeAndColorLength); + args->bufferInUse += codeAndColorLength; + } + return true; // keep going +} + void Application::exportVoxels() { QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), "~/voxels.hio2", tr("High Fidelity Voxel Files (*.hio2)")); @@ -1303,15 +1355,45 @@ void Application::importVoxels() { QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), "~", tr("High Fidelity Voxel Files (*.hio2)")); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); + + // Read the file into a tree + VoxelTree importVoxels; + importVoxels.readFromFileV2(fileName); + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); printf("importVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + + // Recurse the Import Voxels tree, where everything is root relative, and send all the colored voxels to + // the server as an set voxel message, this will also rebase the voxels to the new location + unsigned char* calculatedOctCode = NULL; + SendVoxelsOperataionArgs args; + args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; + unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; + *sequenceAt = 0; + args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence + + // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the + // voxel size/position details. if (selectedNode) { - selectedNode->printDebugDetails("selected voxel"); + //selectedNode->printDebugDetails("selected voxel"); + args.newBaseOctCode = NULL; // selectedNode->getOctalCode(); + } else { + printf("importVoxels() no voxel at current location, calculate octCode... \n"); + args.newBaseOctCode = NULL; // = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + } + + importVoxels.recurseTreeWithOperation(sendVoxelsOperataion, &args); + + // If we have voxels left in the packet, then send the packet + if (args.bufferInUse > 1) { + AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); } - // not yet supported!!! - _voxels.readFromFileV2(fileName,selectedNode); + if (calculatedOctCode) { + delete calculatedOctCode; + } + } void Application::copyVoxels() { @@ -1331,14 +1413,6 @@ void Application::copyVoxels() { } } -const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500; -struct SendVoxelsOperataionArgs { - unsigned char* newBaseOctCode; - unsigned char messageBuffer[MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE]; - int bufferInUse; - -}; - void Application::pasteVoxels() { unsigned char* calculatedOctCode = NULL; VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); @@ -1374,40 +1448,6 @@ void Application::pasteVoxels() { } } -bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { - SendVoxelsOperataionArgs* args = (SendVoxelsOperataionArgs*)extraData; - if (node->isColored()) { - const int SIZE_OF_COLOR_DATA = 3; - const int RED_INDEX = 0; - const int GREEN_INDEX = 1; - const int BLUE_INDEX = 2; - unsigned char* nodeOctalCode = node->getOctalCode(); - printOctalCode(nodeOctalCode); - unsigned char* rebasedCodeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true); - printOctalCode(rebasedCodeColorBuffer); - int rebasedCodeLength = numberOfThreeBitSectionsInCode(rebasedCodeColorBuffer); - int bytesInRebasedCode = bytesRequiredForCodeLength(rebasedCodeLength); - int codeAndColorLength = bytesInRebasedCode + SIZE_OF_COLOR_DATA; - - // copy the colors over - rebasedCodeColorBuffer[bytesInRebasedCode + RED_INDEX ] = node->getColor()[RED_INDEX ]; - rebasedCodeColorBuffer[bytesInRebasedCode + GREEN_INDEX] = node->getColor()[GREEN_INDEX]; - rebasedCodeColorBuffer[bytesInRebasedCode + BLUE_INDEX ] = node->getColor()[BLUE_INDEX ]; - - // if we have room don't have room in the buffer, then send the previously generated message first - if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { - AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL, 1); - args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(int); // reset to command + sequence - } - - // copy this node's code color details into our buffer. - memcpy(&args->messageBuffer[args->bufferInUse], rebasedCodeColorBuffer, codeAndColorLength); - args->bufferInUse += codeAndColorLength; - } - return true; // keep going -} - - void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); _window->setMenuBar(menuBar); @@ -1479,6 +1519,9 @@ void Application::initMenu() { (_selectVoxelMode = voxelMenu->addAction( "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_S))->setCheckable(true); _voxelModeActions->addAction(_selectVoxelMode); + (_eyedropperMode = voxelMenu->addAction( + "Eyedropper Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_E))->setCheckable(true); + _voxelModeActions->addAction(_eyedropperMode); voxelMenu->addAction("Place New Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::Key_N); voxelMenu->addAction("Decrease Voxel Size", this, SLOT(decreaseVoxelSize()), QKeySequence::ZoomOut); @@ -1486,6 +1529,7 @@ void Application::initMenu() { _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), Qt::META | Qt::Key_C); + voxelMenu->addAction("Use Voxel Color", this, SLOT(useVoxelPaintColor()), Qt::CTRL | Qt::Key_U); QColor paintColor(128, 128, 128); _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); @@ -2359,6 +2403,8 @@ void Application::maybeEditVoxelUnderCursor() { } } else if (_deleteVoxelMode->isChecked()) { deleteVoxelUnderCursor(); + } else if (_eyedropperMode->isChecked()) { + eyedropperVoxelUnderCursor(); } } @@ -2383,6 +2429,20 @@ void Application::deleteVoxelUnderCursor() { _justEditedVoxel = true; } +void Application::eyedropperVoxelUnderCursor() { + VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + if (selectedNode && selectedNode->isColored()) { + QColor selectedColor(selectedNode->getColor()[RED_INDEX], + selectedNode->getColor()[GREEN_INDEX], + selectedNode->getColor()[BLUE_INDEX]); + + if (selectedColor.isValid()) { + _voxelPaintColor->setData(selectedColor); + _voxelPaintColor->setIcon(createSwatchIcon(selectedColor)); + } + } +} + void Application::goHome() { _myAvatar.setPosition(START_LOCATION); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 7761d9a84b..ee48307910 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -182,7 +182,7 @@ private: void shiftPaintingColor(); void maybeEditVoxelUnderCursor(); void deleteVoxelUnderCursor(); - + void eyedropperVoxelUnderCursor(); void goHome(); void resetSensors(); @@ -225,6 +225,7 @@ private: QAction* _deleteVoxelMode; // Whether delete voxel mode is enabled QAction* _colorVoxelMode; // Whether color voxel mode is enabled QAction* _selectVoxelMode; // Whether select voxel mode is enabled + QAction* _eyedropperMode; // Whether voxel color eyedropper mode is enabled QAction* _voxelPaintColor; // The color with which to paint voxels QAction* _destructiveAddVoxel; // when doing voxel editing do we want them to be destructive QAction* _frustumOn; // Whether or not to display the debug view frustum diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 156a310476..b18315402a 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -23,11 +23,18 @@ const int MAX_VOXELS_PER_SYSTEM = 200000; const int VERTICES_PER_VOXEL = 24; const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; const int INDICES_PER_VOXEL = 3 * 12; -const int COLOR_VALUES_PER_VOXEL = 3 * VERTICES_PER_VOXEL; + +const int NUMBER_OF_COLORS = 3; // RGB! +const int SIZE_OF_COLOR_DATA = NUMBER_OF_COLORS * sizeof(unsigned char); // size in bytes +const int RED_INDEX = 0; +const int GREEN_INDEX = 1; +const int BLUE_INDEX = 2; +const int COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * VERTICES_PER_VOXEL; typedef unsigned long int glBufferIndex; const glBufferIndex GLBUFFER_INDEX_UNKNOWN = ULONG_MAX; const double SIXTY_FPS_IN_MILLISECONDS = 1000.0/60; const double VIEW_CULLING_RATE_IN_MILLISECONDS = 1000.0; // once a second is fine + #endif From 6479a41206cb073ad11e7fd1e4e3693d13523af3 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 12:26:20 -0700 Subject: [PATCH 24/73] more ball prep --- interface/src/Avatar.cpp | 168 ++++++++++++++++++++++----------------- 1 file changed, 97 insertions(+), 71 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 6d2f0eefad..4fb2846a0f 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -101,10 +101,10 @@ Avatar::Avatar(Agent* owningAgent) : initializeBodyBalls(); - _height = _skeleton.getHeight() + _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius + _bodyBall[ AVATAR_JOINT_HEAD_BASE ].radius; + _height = _skeleton.getHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius + _bodyBall[ BODY_BALL_HEAD_BASE ].radius; _maxArmLength = _skeleton.getArmLength(); - _pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius; - _pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius; + _pelvisStandingHeight = _skeleton.getPelvisStandingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius; + _pelvisFloatingHeight = _skeleton.getPelvisFloatingHeight() + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius; _avatarTouch.setReachableRadius(PERIPERSONAL_RADIUS); @@ -128,41 +128,67 @@ void Avatar::initializeBodyBalls() { _bodyBall[b].isCollidable = true; _bodyBall[b].jointTightness = BODY_SPRING_DEFAULT_TIGHTNESS; } + + // specify the parent joint of each ball + _bodyBall[ BODY_BALL_PELVIS ].radius = 0.07; + _bodyBall[ BODY_BALL_TORSO ].radius = 0.065; + _bodyBall[ BODY_BALL_CHEST ].radius = 0.08; + _bodyBall[ BODY_BALL_NECK_BASE ].radius = 0.03; + _bodyBall[ BODY_BALL_HEAD_BASE ].radius = 0.07; - // specify the radii of the balls - _bodyBall[ AVATAR_JOINT_PELVIS ].radius = 0.07; - _bodyBall[ AVATAR_JOINT_TORSO ].radius = 0.065; - _bodyBall[ AVATAR_JOINT_CHEST ].radius = 0.08; - _bodyBall[ AVATAR_JOINT_NECK_BASE ].radius = 0.03; - _bodyBall[ AVATAR_JOINT_HEAD_BASE ].radius = 0.07; + _bodyBall[ BODY_BALL_LEFT_COLLAR ].radius = 0.04; + _bodyBall[ BODY_BALL_LEFT_SHOULDER ].radius = 0.03; + _bodyBall[ BODY_BALL_LEFT_ELBOW ].radius = 0.02; + _bodyBall[ BODY_BALL_LEFT_WRIST ].radius = 0.02; + _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].radius = 0.01; - _bodyBall[ AVATAR_JOINT_LEFT_COLLAR ].radius = 0.04; - _bodyBall[ AVATAR_JOINT_LEFT_SHOULDER ].radius = 0.03; - _bodyBall[ AVATAR_JOINT_LEFT_ELBOW ].radius = 0.02; - _bodyBall[ AVATAR_JOINT_LEFT_WRIST ].radius = 0.02; - _bodyBall[ AVATAR_JOINT_LEFT_FINGERTIPS ].radius = 0.01; + _bodyBall[ BODY_BALL_RIGHT_COLLAR ].radius = 0.04; + _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].radius = 0.03; + _bodyBall[ BODY_BALL_RIGHT_ELBOW ].radius = 0.02; + _bodyBall[ BODY_BALL_RIGHT_WRIST ].radius = 0.02; + _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].radius = 0.01; - _bodyBall[ AVATAR_JOINT_RIGHT_COLLAR ].radius = 0.04; - _bodyBall[ AVATAR_JOINT_RIGHT_SHOULDER ].radius = 0.03; - _bodyBall[ AVATAR_JOINT_RIGHT_ELBOW ].radius = 0.02; - _bodyBall[ AVATAR_JOINT_RIGHT_WRIST ].radius = 0.02; - _bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].radius = 0.01; + _bodyBall[ BODY_BALL_LEFT_HIP ].radius = 0.04; + _bodyBall[ BODY_BALL_LEFT_KNEE ].radius = 0.025; + _bodyBall[ BODY_BALL_LEFT_HEEL ].radius = 0.025; + _bodyBall[ BODY_BALL_LEFT_TOES ].radius = 0.025; - _bodyBall[ AVATAR_JOINT_LEFT_HIP ].radius = 0.04; - _bodyBall[ AVATAR_JOINT_LEFT_KNEE ].radius = 0.025; - _bodyBall[ AVATAR_JOINT_LEFT_HEEL ].radius = 0.025; - _bodyBall[ AVATAR_JOINT_LEFT_TOES ].radius = 0.025; - - _bodyBall[ AVATAR_JOINT_RIGHT_HIP ].radius = 0.04; - _bodyBall[ AVATAR_JOINT_RIGHT_KNEE ].radius = 0.025; - _bodyBall[ AVATAR_JOINT_RIGHT_HEEL ].radius = 0.025; - _bodyBall[ AVATAR_JOINT_RIGHT_TOES ].radius = 0.025; + _bodyBall[ BODY_BALL_RIGHT_HIP ].radius = 0.04; + _bodyBall[ BODY_BALL_RIGHT_KNEE ].radius = 0.025; + _bodyBall[ BODY_BALL_RIGHT_HEEL ].radius = 0.025; + _bodyBall[ BODY_BALL_RIGHT_TOES ].radius = 0.025; + // specify the parent joint for each ball + _bodyBall[ BODY_BALL_PELVIS ].parentJoint = AVATAR_JOINT_NULL; + _bodyBall[ BODY_BALL_TORSO ].parentJoint = AVATAR_JOINT_PELVIS; + _bodyBall[ BODY_BALL_CHEST ].parentJoint = AVATAR_JOINT_TORSO; + _bodyBall[ BODY_BALL_NECK_BASE ].parentJoint = AVATAR_JOINT_CHEST; + _bodyBall[ BODY_BALL_HEAD_BASE ].parentJoint = AVATAR_JOINT_NECK_BASE; + _bodyBall[ BODY_BALL_HEAD_TOP ].parentJoint = AVATAR_JOINT_HEAD_BASE; + _bodyBall[ BODY_BALL_LEFT_COLLAR ].parentJoint = AVATAR_JOINT_CHEST; + _bodyBall[ BODY_BALL_LEFT_SHOULDER ].parentJoint = AVATAR_JOINT_LEFT_COLLAR; + _bodyBall[ BODY_BALL_LEFT_ELBOW ].parentJoint = AVATAR_JOINT_LEFT_SHOULDER; + _bodyBall[ BODY_BALL_LEFT_WRIST ].parentJoint = AVATAR_JOINT_LEFT_ELBOW; + _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].parentJoint = AVATAR_JOINT_LEFT_WRIST; + _bodyBall[ BODY_BALL_RIGHT_COLLAR ].parentJoint = AVATAR_JOINT_CHEST; + _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].parentJoint = AVATAR_JOINT_RIGHT_COLLAR; + _bodyBall[ BODY_BALL_RIGHT_ELBOW ].parentJoint = AVATAR_JOINT_RIGHT_SHOULDER; + _bodyBall[ BODY_BALL_RIGHT_WRIST ].parentJoint = AVATAR_JOINT_RIGHT_ELBOW; + _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].parentJoint = AVATAR_JOINT_RIGHT_WRIST; + _bodyBall[ BODY_BALL_LEFT_HIP ].parentJoint = AVATAR_JOINT_PELVIS; + _bodyBall[ BODY_BALL_LEFT_KNEE ].parentJoint = AVATAR_JOINT_LEFT_HIP; + _bodyBall[ BODY_BALL_LEFT_HEEL ].parentJoint = AVATAR_JOINT_LEFT_KNEE; + _bodyBall[ BODY_BALL_LEFT_TOES ].parentJoint = AVATAR_JOINT_LEFT_HEEL; + _bodyBall[ BODY_BALL_RIGHT_HIP ].parentJoint = AVATAR_JOINT_PELVIS; + _bodyBall[ BODY_BALL_RIGHT_KNEE ].parentJoint = AVATAR_JOINT_RIGHT_HIP; + _bodyBall[ BODY_BALL_RIGHT_HEEL ].parentJoint = AVATAR_JOINT_RIGHT_KNEE; + _bodyBall[ BODY_BALL_RIGHT_TOES ].parentJoint = AVATAR_JOINT_RIGHT_HEEL; + /* // to aid in hand-shaking and hand-holding, the right hand is not collidable - _bodyBall[ AVATAR_JOINT_RIGHT_ELBOW ].isCollidable = false; - _bodyBall[ AVATAR_JOINT_RIGHT_WRIST ].isCollidable = false; - _bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS].isCollidable = false; + _bodyBall[ BODY_BALL_RIGHT_ELBOW ].isCollidable = false; + _bodyBall[ BODY_BALL_RIGHT_WRIST ].isCollidable = false; + _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS].isCollidable = false; */ } @@ -458,22 +484,22 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { right * _head.getLeanSideways() + front * _head.getLeanForward(); - _bodyBall[ AVATAR_JOINT_TORSO ].position += headLean * 0.1f; - _bodyBall[ AVATAR_JOINT_CHEST ].position += headLean * 0.4f; - _bodyBall[ AVATAR_JOINT_NECK_BASE ].position += headLean * 0.7f; - _bodyBall[ AVATAR_JOINT_HEAD_BASE ].position += headLean * 1.0f; + _bodyBall[ BODY_BALL_TORSO ].position += headLean * 0.1f; + _bodyBall[ BODY_BALL_CHEST ].position += headLean * 0.4f; + _bodyBall[ BODY_BALL_NECK_BASE ].position += headLean * 0.7f; + _bodyBall[ BODY_BALL_HEAD_BASE ].position += headLean * 1.0f; - _bodyBall[ AVATAR_JOINT_LEFT_COLLAR ].position += headLean * 0.6f; - _bodyBall[ AVATAR_JOINT_LEFT_SHOULDER ].position += headLean * 0.6f; - _bodyBall[ AVATAR_JOINT_LEFT_ELBOW ].position += headLean * 0.2f; - _bodyBall[ AVATAR_JOINT_LEFT_WRIST ].position += headLean * 0.1f; - _bodyBall[ AVATAR_JOINT_LEFT_FINGERTIPS ].position += headLean * 0.0f; + _bodyBall[ BODY_BALL_LEFT_COLLAR ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_LEFT_SHOULDER ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_LEFT_ELBOW ].position += headLean * 0.2f; + _bodyBall[ BODY_BALL_LEFT_WRIST ].position += headLean * 0.1f; + _bodyBall[ BODY_BALL_LEFT_FINGERTIPS ].position += headLean * 0.0f; - _bodyBall[ AVATAR_JOINT_RIGHT_COLLAR ].position += headLean * 0.6f; - _bodyBall[ AVATAR_JOINT_RIGHT_SHOULDER ].position += headLean * 0.6f; - _bodyBall[ AVATAR_JOINT_RIGHT_ELBOW ].position += headLean * 0.2f; - _bodyBall[ AVATAR_JOINT_RIGHT_WRIST ].position += headLean * 0.1f; - _bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position += headLean * 0.0f; + _bodyBall[ BODY_BALL_RIGHT_COLLAR ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_RIGHT_SHOULDER ].position += headLean * 0.6f; + _bodyBall[ BODY_BALL_RIGHT_ELBOW ].position += headLean * 0.2f; + _bodyBall[ BODY_BALL_RIGHT_WRIST ].position += headLean * 0.1f; + _bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position += headLean * 0.0f; } } @@ -487,8 +513,8 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { } _head.setBodyRotation (glm::vec3(_bodyPitch, _bodyYaw, _bodyRoll)); - _head.setPosition(_bodyBall[ AVATAR_JOINT_HEAD_BASE ].position); - _head.setScale (_bodyBall[ AVATAR_JOINT_HEAD_BASE ].radius); + _head.setPosition(_bodyBall[ BODY_BALL_HEAD_BASE ].position); + _head.setScale (_bodyBall[ BODY_BALL_HEAD_BASE ].radius); _head.setSkinColor(glm::vec3(SKIN_COLOR[0], SKIN_COLOR[1], SKIN_COLOR[2])); _head.simulate(deltaTime, !_owningAgent); @@ -581,7 +607,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { _avatarTouch.setHasInteractingOther(true); _avatarTouch.setYourBodyPosition(_interactingOther->_position); - _avatarTouch.setYourHandPosition(_interactingOther->_bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); + _avatarTouch.setYourHandPosition(_interactingOther->_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position); _avatarTouch.setYourOrientation (_interactingOther->getOrientation()); _avatarTouch.setYourHandState (_interactingOther->_handState); @@ -652,7 +678,7 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { } _avatarTouch.setMyHandState(_handState); - _avatarTouch.setMyHandPosition(_bodyBall[ AVATAR_JOINT_RIGHT_FINGERTIPS ].position); + _avatarTouch.setMyHandPosition(_bodyBall[ BODY_BALL_RIGHT_FINGERTIPS ].position); } } @@ -856,7 +882,7 @@ void Avatar::render(bool lookingInMirror) { } glPushMatrix(); - glm::vec3 chatPosition = _bodyBall[AVATAR_JOINT_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight; + glm::vec3 chatPosition = _bodyBall[BODY_BALL_HEAD_BASE].position + getBodyUpDirection() * chatMessageHeight; glTranslatef(chatPosition.x, chatPosition.y, chatPosition.z); glm::quat chatRotation = Application::getInstance()->getCamera()->getRotation(); glm::vec3 chatAxis = glm::axis(chatRotation); @@ -901,13 +927,13 @@ void Avatar::resetBodyBalls() { void Avatar::updateBodyBalls(float deltaTime) { // Check for a large repositioning, and re-initialize balls if this has happened const float BEYOND_BODY_SPRING_RANGE = 2.f; - if (glm::length(_position - _bodyBall[AVATAR_JOINT_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { + if (glm::length(_position - _bodyBall[BODY_BALL_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { resetBodyBalls(); } for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { glm::vec3 springVector(_bodyBall[b].position); - if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL) { + if (b == BODY_BALL_PELVIS) { springVector -= _position; } else { @@ -1020,18 +1046,18 @@ void Avatar::renderBody(bool lookingInMirror) { } // Always render other people, and render myself when beyond threshold distance - if (b == AVATAR_JOINT_HEAD_BASE) { // the head is rendered as a special + if (b == BODY_BALL_HEAD_BASE) { // the head is rendered as a special if (lookingInMirror || _owningAgent || distanceToCamera > RENDER_OPAQUE_BEYOND * 0.5) { _head.render(lookingInMirror, _cameraPosition, alpha); } } else if (_owningAgent || distanceToCamera > RENDER_TRANSLUCENT_BEYOND - || b == AVATAR_JOINT_RIGHT_ELBOW - || b == AVATAR_JOINT_RIGHT_WRIST - || b == AVATAR_JOINT_RIGHT_FINGERTIPS ) { + || b == BODY_BALL_RIGHT_ELBOW + || b == BODY_BALL_RIGHT_WRIST + || b == BODY_BALL_RIGHT_FINGERTIPS ) { // Render the body ball sphere - if (_owningAgent || b == AVATAR_JOINT_RIGHT_ELBOW - || b == AVATAR_JOINT_RIGHT_WRIST - || b == AVATAR_JOINT_RIGHT_FINGERTIPS ) { + if (_owningAgent || b == BODY_BALL_RIGHT_ELBOW + || b == BODY_BALL_RIGHT_WRIST + || b == BODY_BALL_RIGHT_FINGERTIPS ) { glColor3f(SKIN_COLOR[0] + _bodyBall[b].touchForce * 0.3f, SKIN_COLOR[1] - _bodyBall[b].touchForce * 0.2f, SKIN_COLOR[2] - _bodyBall[b].touchForce * 0.1f); @@ -1042,8 +1068,8 @@ void Avatar::renderBody(bool lookingInMirror) { alpha); } - if ((b != AVATAR_JOINT_HEAD_TOP ) - && (b != AVATAR_JOINT_HEAD_BASE )) { + if ((b != BODY_BALL_HEAD_TOP ) + && (b != BODY_BALL_HEAD_BASE )) { glPushMatrix(); glTranslatef(_bodyBall[b].position.x, _bodyBall[b].position.y, _bodyBall[b].position.z); glutSolidSphere(_bodyBall[b].radius, 20.0f, 20.0f); @@ -1052,20 +1078,20 @@ void Avatar::renderBody(bool lookingInMirror) { // Render the cone connecting this ball to its parent if (_skeleton.joint[b].parent != AVATAR_JOINT_NULL) { - if ((b != AVATAR_JOINT_HEAD_TOP ) - && (b != AVATAR_JOINT_HEAD_BASE ) - && (b != AVATAR_JOINT_PELVIS ) - && (b != AVATAR_JOINT_TORSO ) - && (b != AVATAR_JOINT_CHEST ) - && (b != AVATAR_JOINT_LEFT_COLLAR ) - && (b != AVATAR_JOINT_LEFT_SHOULDER ) - && (b != AVATAR_JOINT_RIGHT_COLLAR ) - && (b != AVATAR_JOINT_RIGHT_SHOULDER)) { + if ((b != BODY_BALL_HEAD_TOP ) + && (b != BODY_BALL_HEAD_BASE ) + && (b != BODY_BALL_PELVIS ) + && (b != BODY_BALL_TORSO ) + && (b != BODY_BALL_CHEST ) + && (b != BODY_BALL_LEFT_COLLAR ) + && (b != BODY_BALL_LEFT_SHOULDER ) + && (b != BODY_BALL_RIGHT_COLLAR ) + && (b != BODY_BALL_RIGHT_SHOULDER)) { glColor3fv(DARK_SKIN_COLOR); float r1 = _bodyBall[_skeleton.joint[b].parent ].radius * 0.8; float r2 = _bodyBall[b ].radius * 0.8; - if (b == AVATAR_JOINT_HEAD_BASE) { + if (b == BODY_BALL_HEAD_BASE) { r1 *= 0.5f; } renderJointConnectingCone From 73f8fca2afaa182d93d9a11e9510d6d8141e5891 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Mon, 3 Jun 2013 13:00:54 -0700 Subject: [PATCH 25/73] More work on voxeltars; added rotations. --- interface/src/Avatar.cpp | 8 +++- interface/src/AvatarVoxelSystem.cpp | 9 ++-- interface/src/Skeleton.cpp | 65 +++++++++++++-------------- interface/src/Skeleton.h | 68 +++++++++++++++-------------- interface/src/Util.cpp | 21 +++++++++ interface/src/Util.h | 2 + 6 files changed, 103 insertions(+), 70 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 2250bda751..fa193d3a70 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -909,6 +909,8 @@ void Avatar::updateBodyBalls(float deltaTime) { if (glm::length(_position - _bodyBall[AVATAR_JOINT_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { resetBodyBalls(); } + glm::quat orientation = getOrientation(); + glm::vec3 jointDirection = orientation * JOINT_DIRECTION; for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { glm::vec3 springVector(_bodyBall[b].position); @@ -955,7 +957,11 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; // update rotation - _bodyBall[b].rotation = _skeleton.joint[b].rotation; + if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < 0.1f) { + _bodyBall[b].rotation = orientation * _skeleton.joint[b].absoluteBindPoseRotation; + } else { + _bodyBall[b].rotation = rotationBetween(jointDirection, springVector) * orientation; + } } } diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index d6b51bec82..9e441c148c 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -144,10 +144,11 @@ void AvatarVoxelSystem::applyScaleAndBindProgram(bool texture) { glm::vec3 position; glm::quat orientation; _avatar->getBodyBallTransform((AvatarJointID)i, position, orientation); - boneMatrices[i].translate(position.x, position.y, position.z); + boneMatrices[i].translate(position.x, position.y, position.z); + orientation = orientation * glm::inverse(_avatar->getSkeleton().joint[i].absoluteBindPoseRotation); 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); + const glm::vec3& bindPosition = _avatar->getSkeleton().joint[i].absoluteBindPosePosition; + boneMatrices[i].translate(-bindPosition.x, -bindPosition.y, -bindPosition.z); boneMatrices[i] *= baseMatrix; } _skinProgram->setUniformValueArray(_boneMatricesLocation, boneMatrices, NUM_AVATAR_JOINTS); @@ -182,7 +183,7 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo // 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); + float distance = glm::distance(jointVertex, _avatar->getSkeleton().joint[i].absoluteBindPosePosition); for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { if (distance < nearest[j].distance) { // move the rest of the indices down diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index ae31810d8e..136cb6f619 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -5,6 +5,7 @@ // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. #include "Skeleton.h" +#include "Util.h" const float BODY_SPRING_DEFAULT_TIGHTNESS = 1000.0f; const float FLOATING_HEIGHT = 0.13f; @@ -17,7 +18,7 @@ void Skeleton::initialize() { for (int b=0; b 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); + if (axisLength < EPSILON) { // parallel to x; y will work + axis = glm::normalize(glm::cross(v1, glm::vec3(0.0f, 1.0f, 0.0f))); + } else { + axis /= axisLength; + } + } else { + axis = glm::normalize(glm::cross(v1, v2)); + } + return glm::angleAxis(angle, axis); +} + // Safe version of glm::eulerAngles; uses the factorization method described in David Eberly's // http://www.geometrictools.com/Documentation/EulerAngles.pdf (via Clyde, // https://github.com/threerings/clyde/blob/master/src/main/java/com/threerings/math/Quaternion.java) diff --git a/interface/src/Util.h b/interface/src/Util.h index 0823ac405b..0187d93da5 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -45,6 +45,8 @@ void drawVector(glm::vec3* vector); float angleBetween(const glm::vec3& v1, const glm::vec3& v2); +glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2); + glm::vec3 safeEulerAngles(const glm::quat& q); glm::quat safeMix(const glm::quat& q1, const glm::quat& q2, float alpha); From c4b3b568e7e551f5716642b29f7aaefa21f9b253 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 13:13:52 -0700 Subject: [PATCH 26/73] make import and export properly rebase --- interface/src/Application.cpp | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ab335dce97..73a0190267 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1343,12 +1343,22 @@ void Application::exportVoxels() { QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + printf("exportVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + + if (selectedNode) { - selectedNode->printDebugDetails("selected voxel"); + //selectedNode->printDebugDetails("selected voxel"); + + VoxelTree exportTree; + + // then copy onto it + _voxels.copySubTreeIntoNewTree(selectedNode, &exportTree, true); + + exportTree.writeToFileV2(fileName); } - _voxels.writeToFileV2(fileName,selectedNode); + } void Application::importVoxels() { @@ -1377,10 +1387,10 @@ void Application::importVoxels() { // voxel size/position details. if (selectedNode) { //selectedNode->printDebugDetails("selected voxel"); - args.newBaseOctCode = NULL; // selectedNode->getOctalCode(); + args.newBaseOctCode = selectedNode->getOctalCode(); } else { printf("importVoxels() no voxel at current location, calculate octCode... \n"); - args.newBaseOctCode = NULL; // = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); + args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } importVoxels.recurseTreeWithOperation(sendVoxelsOperataion, &args); @@ -1520,7 +1530,7 @@ void Application::initMenu() { "Select Voxel Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_S))->setCheckable(true); _voxelModeActions->addAction(_selectVoxelMode); (_eyedropperMode = voxelMenu->addAction( - "Eyedropper Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_E))->setCheckable(true); + "Get Color Mode", this, SLOT(updateVoxelModeActions()), Qt::CTRL | Qt::Key_G))->setCheckable(true); _voxelModeActions->addAction(_eyedropperMode); voxelMenu->addAction("Place New Voxel", this, SLOT(addVoxelInFrontOfAvatar()), Qt::CTRL | Qt::Key_N); @@ -1529,7 +1539,6 @@ void Application::initMenu() { _voxelPaintColor = voxelMenu->addAction("Voxel Paint Color", this, SLOT(chooseVoxelPaintColor()), Qt::META | Qt::Key_C); - voxelMenu->addAction("Use Voxel Color", this, SLOT(useVoxelPaintColor()), Qt::CTRL | Qt::Key_U); QColor paintColor(128, 128, 128); _voxelPaintColor->setData(paintColor); _voxelPaintColor->setIcon(createSwatchIcon(paintColor)); From ea965f22902c4e81105bf2f4a9b33de7f0c2103d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 13:46:21 -0700 Subject: [PATCH 27/73] fixed issue with sendVoxelsOperataion, some other cleanup --- interface/src/Application.cpp | 26 ++++++++++---------------- libraries/voxels/src/VoxelTree.cpp | 9 --------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 73a0190267..ec51855c49 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1297,7 +1297,6 @@ bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { SendVoxelsOperataionArgs* args = (SendVoxelsOperataionArgs*)extraData; if (node->isColored()) { unsigned char* nodeOctalCode = node->getOctalCode(); - printOctalCode(nodeOctalCode); unsigned char* codeColorBuffer = NULL; int codeLength = 0; @@ -1307,7 +1306,6 @@ bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { // If the newBase is NULL, then don't rebase if (args->newBaseOctCode) { codeColorBuffer = rebaseOctalCode(nodeOctalCode, args->newBaseOctCode, true); - printOctalCode(codeColorBuffer); codeLength = numberOfThreeBitSectionsInCode(codeColorBuffer); bytesInCode = bytesRequiredForCodeLength(codeLength); codeAndColorLength = bytesInCode + SIZE_OF_COLOR_DATA; @@ -1327,7 +1325,7 @@ bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { // if we have room don't have room in the buffer, then send the previously generated message first if (args->bufferInUse + codeAndColorLength > MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE) { AgentList::getInstance()->broadcastToAgents(args->messageBuffer, args->bufferInUse, &AGENT_TYPE_VOXEL, 1); - args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(int); // reset to command + sequence + args->bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // reset } // copy this node's code color details into our buffer. @@ -1359,6 +1357,8 @@ void Application::exportVoxels() { exportTree.writeToFileV2(fileName); } + // restore the main window's active state + _window->activateWindow(); } void Application::importVoxels() { @@ -1394,9 +1394,9 @@ void Application::importVoxels() { } importVoxels.recurseTreeWithOperation(sendVoxelsOperataion, &args); - + // If we have voxels left in the packet, then send the packet - if (args.bufferInUse > 1) { + if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); } @@ -1404,29 +1404,24 @@ void Application::importVoxels() { delete calculatedOctCode; } + // restore the main window's active state + _window->activateWindow(); } void Application::copyVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - printf("copyVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { - //selectedNode->printDebugDetails("selected voxel"); - // clear the clipboard first... _clipboardTree.eraseAllVoxels(); // then copy onto it _voxels.copySubTreeIntoNewTree(selectedNode, &_clipboardTree, true); - - // debug tree - //_clipboardTree.printTreeForDebugging(_clipboardTree.rootNode); } } void Application::pasteVoxels() { unsigned char* calculatedOctCode = NULL; VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - printf("pasteVoxels() _mouseVoxel: %f,%f,%f-%f \n", _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to // the server as an set voxel message, this will also rebase the voxels to the new location @@ -1437,19 +1432,18 @@ void Application::pasteVoxels() { args.bufferInUse = sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int); // set to command + sequence // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the - // voxel size/position details. + // voxel size/position details. If we don't have an actual selectedNode then use the mouseVoxel to create a + // target octalCode for where the user is pointing. if (selectedNode) { - //selectedNode->printDebugDetails("selected voxel"); args.newBaseOctCode = selectedNode->getOctalCode(); } else { - printf("pasteVoxels() no voxel at current location, calculate octCode... \n"); args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } _clipboardTree.recurseTreeWithOperation(sendVoxelsOperataion, &args); // If we have voxels left in the packet, then send the packet - if (args.bufferInUse > 1) { + if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { AgentList::getInstance()->broadcastToAgents(args.messageBuffer, args.bufferInUse, &AGENT_TYPE_VOXEL, 1); } diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 704c15e4db..af6b435512 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1185,18 +1185,11 @@ bool VoxelTree::countVoxelsOperation(VoxelNode* node, void* extraData) { } void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinationTree, bool rebaseToRoot) { - - printLog("copySubTreeIntoNewTree()...\n"); - VoxelNodeBag nodeBag; - // If we were given a specific node, start from there, otherwise start from root nodeBag.insert(startNode); - int chopLevels = 0; - if (rebaseToRoot) { chopLevels = numberOfThreeBitSectionsInCode(startNode->getOctalCode()); - printLog("copySubTreeIntoNewTree()...rebaseToRoot=true, chopLevels=%d\n", chopLevels); } static unsigned char outputBuffer[MAX_VOXEL_PACKET_SIZE - 1]; // save on allocs by making this static @@ -1215,8 +1208,6 @@ void VoxelTree::copySubTreeIntoNewTree(VoxelNode* startNode, VoxelTree* destinat } void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destinationNode) { - printLog("copyFromTreeIntoSubTree()...\n"); - VoxelNodeBag nodeBag; // If we were given a specific node, start from there, otherwise start from root nodeBag.insert(sourceTree->rootNode); From 0f2b73613091eb8f6b40684a8250d000d2812205 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 13:50:42 -0700 Subject: [PATCH 28/73] cleanup --- interface/src/Application.cpp | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ec51855c49..9b1b97be19 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1341,19 +1341,9 @@ void Application::exportVoxels() { QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - - printf("exportVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, - _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - - if (selectedNode) { - //selectedNode->printDebugDetails("selected voxel"); - VoxelTree exportTree; - - // then copy onto it _voxels.copySubTreeIntoNewTree(selectedNode, &exportTree, true); - exportTree.writeToFileV2(fileName); } @@ -1371,8 +1361,6 @@ void Application::importVoxels() { importVoxels.readFromFileV2(fileName); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); - printf("importVoxels() fileName: %s _mouseVoxel: %f,%f,%f-%f \n", fileName, - _mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); // Recurse the Import Voxels tree, where everything is root relative, and send all the colored voxels to // the server as an set voxel message, this will also rebase the voxels to the new location @@ -1386,10 +1374,8 @@ void Application::importVoxels() { // we only need the selected voxel to get the newBaseOctCode, which we can actually calculate from the // voxel size/position details. if (selectedNode) { - //selectedNode->printDebugDetails("selected voxel"); args.newBaseOctCode = selectedNode->getOctalCode(); } else { - printf("importVoxels() no voxel at current location, calculate octCode... \n"); args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } @@ -1744,17 +1730,6 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { glm::vec3 up = rotation * AVATAR_UP; glm::vec3 right = rotation * AVATAR_RIGHT; - /* - printf("position.x=%f, position.y=%f, position.z=%f\n", position.x, position.y, position.z); - printf("yaw=%f, pitch=%f, roll=%f\n", yaw,pitch,roll); - printf("direction.x=%f, direction.y=%f, direction.z=%f\n", direction.x, direction.y, direction.z); - printf("up.x=%f, up.y=%f, up.z=%f\n", up.x, up.y, up.z); - printf("right.x=%f, right.y=%f, right.z=%f\n", right.x, right.y, right.z); - printf("fov=%f\n", fov); - printf("nearClip=%f\n", nearClip); - printf("farClip=%f\n", farClip); - */ - // Set the viewFrustum up with the correct position and orientation of the camera viewFrustum.setPosition(position); viewFrustum.setOrientation(direction,up,right); @@ -2355,7 +2330,6 @@ void Application::maybeEditVoxelUnderCursor() { //_myAvatar.getPosition() voxelInjector->setBearing(-1 * _myAvatar.getAbsoluteHeadYaw()); voxelInjector->setVolume (16 * pow (_mouseVoxel.s, 2) / .0000001); //255 is max, and also default value - // printf("mousevoxelscale is %f\n", _mouseVoxel.s); /* for (int i = 0; i < 22050; i++) { From c55b6a20d77de398351e6d3d0982f5f4b92b4295 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Mon, 3 Jun 2013 15:38:12 -0700 Subject: [PATCH 29/73] parse the desired cube side length for injected audio source --- injector/src/main.cpp | 15 +++++++++++++-- libraries/audio/src/AudioInjector.cpp | 13 ++++++++++++- libraries/audio/src/AudioInjector.h | 4 ++++ libraries/audio/src/AudioRingBuffer.cpp | 11 +++++++++++ libraries/audio/src/AudioRingBuffer.h | 4 ++++ 5 files changed, 44 insertions(+), 3 deletions(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 32a8442d8f..512882c374 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -32,10 +32,11 @@ bool loopAudio = true; float sleepIntervalMin = 1.00; float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; -const char *allowedParameters = ":rb::t::c::a::f::d:"; +const char *allowedParameters = ":rb::t::c::a::f::d::s:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; unsigned char volume = DEFAULT_INJECTOR_VOLUME; -float triggerDistance = 0; +float triggerDistance = 0.0f; +float cubeSideLength = 0.0f; void usage(void) { std::cout << "High Fidelity - Interface audio injector" << std::endl; @@ -46,6 +47,7 @@ void usage(void) { 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 << " -s FLOAT Length of side of cube audio source. If not specified injected audio is point source" << std::endl; } bool processParameters(int parameterCount, char* parameterData[]) { @@ -92,6 +94,10 @@ bool processParameters(int parameterCount, char* parameterData[]) { ::triggerDistance = atof(optarg); std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl; break; + case 's': + ::cubeSideLength = atof(optarg); + std::cout << "[DEBUG] Cube side length: " << optarg << std::endl; + break; default: usage(); return false; @@ -163,6 +169,11 @@ int main(int argc, char* argv[]) { injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2])); injector.setBearing(*(::floatArguments + 3)); injector.setVolume(::volume); + + if (::cubeSideLength > 0) { + // if we were passed a cube side length, give that to the injector + injector.setCubeSideLength(::cubeSideLength); + } // register the callback for agent data creation agentList->linkedDataCreateCallback = createAvatarDataForAgent; diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index 8e540c9735..e1de27ef6d 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -19,6 +19,7 @@ const int MAX_INJECTOR_VOLUME = 0xFF; AudioInjector::AudioInjector(const char* filename) : _position(), + _cubeSideLength(0.0f), _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), @@ -48,6 +49,7 @@ AudioInjector::AudioInjector(const char* filename) : AudioInjector::AudioInjector(int maxNumSamples) : _numTotalSamples(maxNumSamples), _position(), + _cubeSideLength(0.0f), _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), @@ -75,7 +77,9 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; - unsigned char *currentPacketPtr = dataPacket + 1; + // add the correct command for point source or cube of sound + dataPacket[1] = (_cubeSideLength > 0) ? INJECT_AUDIO_AT_CUBE_COMMAND : INJECT_AUDIO_AT_POINT_COMMAND; + unsigned char *currentPacketPtr = dataPacket + sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND); // copy the identifier for this injector memcpy(currentPacketPtr, &_streamIdentifier, sizeof(_streamIdentifier)); @@ -84,6 +88,13 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination memcpy(currentPacketPtr, &_position, sizeof(_position)); currentPacketPtr += sizeof(_position); + if (_cubeSideLength > 0) { + // if we have a cube half height we need to send it here + // this tells the mixer how much volume the injected audio will occupy + memcpy(currentPacketPtr, &_cubeSideLength, sizeof(_cubeSideLength)); + currentPacketPtr += sizeof(_cubeSideLength); + } + *currentPacketPtr = _volume; currentPacketPtr++; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 7db9398fc9..0269931568 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -39,6 +39,9 @@ public: float getBearing() const { return _bearing; } void setBearing(float bearing) { _bearing = bearing; } + float getCubeSideLength() const { return _cubeSideLength; } + void setCubeSideLength(float cubeSideLength) { _cubeSideLength = cubeSideLength; } + void addSample(const int16_t sample); void addSamples(int16_t* sampleBuffer, int numSamples); private: @@ -46,6 +49,7 @@ private: int16_t* _audioSampleArray; int _numTotalSamples; glm::vec3 _position; + float _cubeSideLength; float _bearing; unsigned char _volume; int _indexOfNextSlot; diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 006dd825bf..39cdc43287 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -17,6 +17,7 @@ AudioRingBuffer::AudioRingBuffer(int ringSamples, int bufferSamples) : AgentData(NULL), _ringBufferLengthSamples(ringSamples), _bufferLengthSamples(bufferSamples), + _cubeSideLength(0.0f), _endOfLastWrite(NULL), _started(false), _shouldBeAddedToMix(false), @@ -46,11 +47,21 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { // we've got a stream identifier to pull from the packet memcpy(&_streamIdentifier, dataBuffer, sizeof(_streamIdentifier)); dataBuffer += sizeof(_streamIdentifier); + + // push past the injection command + dataBuffer += sizeof(INJECT_AUDIO_AT_POINT_COMMAND); } memcpy(&_position, dataBuffer, sizeof(_position)); dataBuffer += (sizeof(_position)); + if (sourceBuffer[0] == PACKET_HEADER_INJECT_AUDIO && sourceBuffer[1] == INJECT_AUDIO_AT_CUBE_COMMAND) { + // this is audio that needs to be injected as a volume (cube) + // parse out the cubeHalfHeight sent by the client + memcpy(&_cubeSideLength, dataBuffer, sizeof(_cubeSideLength)); + dataBuffer += (sizeof(_cubeSideLength)); + } + unsigned int attenuationByte = *(dataBuffer++); _attenuationRatio = attenuationByte / 255.0f; diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index b448f93cee..3554e13d46 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -17,6 +17,9 @@ const int STREAM_IDENTIFIER_NUM_BYTES = 8; +const char INJECT_AUDIO_AT_POINT_COMMAND = 'P'; +const char INJECT_AUDIO_AT_CUBE_COMMAND = 'C'; + class AudioRingBuffer : public AgentData { public: AudioRingBuffer(int ringSamples, int bufferSamples); @@ -53,6 +56,7 @@ private: int _ringBufferLengthSamples; int _bufferLengthSamples; glm::vec3 _position; + float _cubeSideLength; float _attenuationRatio; float _bearing; int16_t* _nextOutput; From 26bbb9917b7b9ab096e3238048a4a800f510b6e2 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 16:23:55 -0700 Subject: [PATCH 30/73] more work on avatar touch --- interface/src/Application.cpp | 2 +- interface/src/Avatar.cpp | 242 +++++++++++++++++++++++----------- interface/src/Avatar.h | 23 ++-- interface/src/Skeleton.cpp | 1 + interface/src/Skeleton.h | 1 + 5 files changed, 185 insertions(+), 84 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 130bd5e7fe..1480b81050 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -50,7 +50,7 @@ using namespace std; -const bool TESTING_AVATAR_TOUCH = false; +const bool TESTING_AVATAR_TOUCH = true; // Starfield information static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 4fb2846a0f..99ddd65853 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -44,7 +44,7 @@ const float HEAD_MAX_YAW = 85; const float HEAD_MIN_YAW = -85; const float PERIPERSONAL_RADIUS = 1.0f; const float AVATAR_BRAKING_STRENGTH = 40.0f; -const float JOINT_TOUCH_RANGE = 0.01f; +const float MOUSE_RAY_TOUCH_RANGE = 0.01f; const float FLOATING_HEIGHT = 0.13f; const bool USING_HEAD_LEAN = false; const float LEAN_SENSITIVITY = 0.15; @@ -64,7 +64,8 @@ float chatMessageHeight = 0.20; Avatar::Avatar(Agent* owningAgent) : AvatarData(owningAgent), _head(this), - _TEST_bigSphereRadius(0.4f), + _ballSpringsInitialized(false), + _TEST_bigSphereRadius(0.5f), _TEST_bigSpherePosition(5.0f, _TEST_bigSphereRadius, 5.0f), _mousePressed(false), _bodyPitchDelta(0.0f), @@ -118,6 +119,8 @@ Avatar::Avatar(Agent* owningAgent) : void Avatar::initializeBodyBalls() { + _ballSpringsInitialized = false; //this gets set to true on the first update pass... + for (int b=0; b (1.0f - range)) { _bodyBall[b].touchForce = (dot - (1.0f - range)) / range; @@ -585,11 +670,6 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { Avatar *otherAvatar = (Avatar *)agent->getLinkedData(); - //Test: Show angle between your fwd vector and nearest avatar - //glm::vec3 vectorBetweenUs = otherAvatar->getJointPosition(AVATAR_JOINT_PELVIS) - - // getJointPosition(AVATAR_JOINT_PELVIS); - //printLog("Angle between: %f\n", angleBetween(vectorBetweenUs, getBodyFrontDirection())); - // test whether shoulders are close enough to allow for reaching to touch hands glm::vec3 v(_position - otherAvatar->_position); float distance = glm::length(v); @@ -689,16 +769,16 @@ void Avatar::updateCollisionWithSphere(glm::vec3 position, float radius, float d float distanceToBigSphere = glm::length(vectorFromMyBodyToBigSphere); if (distanceToBigSphere < myBodyApproximateBoundingRadius + radius) { for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { - glm::vec3 vectorFromJointToBigSphereCenter(_bodyBall[b].position - position); - float distanceToBigSphereCenter = glm::length(vectorFromJointToBigSphereCenter); + glm::vec3 vectorFromBallToBigSphereCenter(_bodyBall[b].position - position); + float distanceToBigSphereCenter = glm::length(vectorFromBallToBigSphereCenter); float combinedRadius = _bodyBall[b].radius + radius; if (distanceToBigSphereCenter < combinedRadius) { if (distanceToBigSphereCenter > 0.0) { - glm::vec3 directionVector = vectorFromJointToBigSphereCenter / distanceToBigSphereCenter; + glm::vec3 directionVector = vectorFromBallToBigSphereCenter / distanceToBigSphereCenter; float penetration = 1.0 - (distanceToBigSphereCenter / combinedRadius); - glm::vec3 collisionForce = vectorFromJointToBigSphereCenter * penetration; + glm::vec3 collisionForce = vectorFromBallToBigSphereCenter * penetration; _velocity += collisionForce * 40.0f * deltaTime; _bodyBall[b].position = position + directionVector * combinedRadius; @@ -792,18 +872,18 @@ void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime for (int o=b+1; o_bodyBall[o].isCollidable) { - glm::vec3 vectorBetweenJoints(_bodyBall[b].position - otherAvatar->_bodyBall[o].position); - float distanceBetweenJoints = glm::length(vectorBetweenJoints); + glm::vec3 vectorBetweenBalls(_bodyBall[b].position - otherAvatar->_bodyBall[o].position); + float distanceBetweenBalls = glm::length(vectorBetweenBalls); - if (distanceBetweenJoints > 0.0) { // to avoid divide by zero + if (distanceBetweenBalls > 0.0) { // to avoid divide by zero float combinedRadius = _bodyBall[b].radius + otherAvatar->_bodyBall[o].radius; // check for collision - if (distanceBetweenJoints < combinedRadius * COLLISION_RADIUS_SCALAR) { - glm::vec3 directionVector = vectorBetweenJoints / distanceBetweenJoints; + if (distanceBetweenBalls < combinedRadius * COLLISION_RADIUS_SCALAR) { + glm::vec3 directionVector = vectorBetweenBalls / distanceBetweenBalls; // push balls away from each other and apply friction - float penetration = 1.0f - (distanceBetweenJoints / (combinedRadius * COLLISION_RADIUS_SCALAR)); + float penetration = 1.0f - (distanceBetweenBalls / (combinedRadius * COLLISION_RADIUS_SCALAR)); glm::vec3 ballPushForce = directionVector * COLLISION_BALL_FORCE * penetration * deltaTime; bodyPushForce += directionVector * COLLISION_BODY_FORCE * penetration * deltaTime; @@ -919,7 +999,12 @@ void Avatar::render(bool lookingInMirror) { void Avatar::resetBodyBalls() { for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { - _bodyBall[b].position = _skeleton.joint[b].position; // put balls on joints + + glm::vec3 targetPosition + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + + _bodyBall[b].position = targetPosition; // put ball on target position _bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } } @@ -931,30 +1016,39 @@ void Avatar::updateBodyBalls(float deltaTime) { resetBodyBalls(); } for (int b = 0; b < NUM_AVATAR_BODY_BALLS; b++) { - glm::vec3 springVector(_bodyBall[b].position); - - if (b == BODY_BALL_PELVIS) { - springVector -= _position; - } - else { - springVector -= _bodyBall[ _skeleton.joint[b].parent ].position; - } - - float length = glm::length(springVector); - - if (length > 0.0f) { // to avoid divide by zero - glm::vec3 springDirection = springVector / length; - - float force = (length - _skeleton.joint[b].length) * BODY_SPRING_FORCE * deltaTime; - _bodyBall[b].velocity -= springDirection * force; + + if (_ballSpringsInitialized) { + + //apply spring forces + glm::vec3 springVector(_bodyBall[b].position); - if (_skeleton.joint[b].parent != AVATAR_JOINT_NULL) { - _bodyBall[_skeleton.joint[b].parent].velocity += springDirection * force; + if (b == BODY_BALL_PELVIS) { + springVector -= _position; } + else { + springVector -= _bodyBall[_bodyBall[b].parentBall].position; + } + + float length = glm::length(springVector); + + if (length > 0.0f) { // to avoid divide by zero + glm::vec3 springDirection = springVector / length; + + float force = (length - _skeleton.joint[b].length) * BODY_SPRING_FORCE * deltaTime; + _bodyBall[b].velocity -= springDirection * force; + + if (_bodyBall[b].parentBall != BODY_BALL_NULL) { + _bodyBall[_bodyBall[b].parentBall].velocity += springDirection * force; + } + } } // apply tightness force - (causing ball position to be close to skeleton joint position) - _bodyBall[b].velocity += (_skeleton.joint[b].position - _bodyBall[b].position) * _bodyBall[b].jointTightness * deltaTime; + glm::vec3 targetPosition + = _skeleton.joint[_bodyBall[b].parentJoint].position + + _skeleton.joint[_bodyBall[b].parentJoint].rotation * _bodyBall[b].parentOffset; + + _bodyBall[b].velocity += (targetPosition - _bodyBall[b].position) * _bodyBall[b].jointTightness * deltaTime; // apply decay float decay = 1.0 - BODY_SPRING_DECAY * deltaTime; @@ -1077,7 +1171,7 @@ void Avatar::renderBody(bool lookingInMirror) { } // Render the cone connecting this ball to its parent - if (_skeleton.joint[b].parent != AVATAR_JOINT_NULL) { + if (_bodyBall[b].parentBall != BODY_BALL_NULL) { if ((b != BODY_BALL_HEAD_TOP ) && (b != BODY_BALL_HEAD_BASE ) && (b != BODY_BALL_PELVIS ) @@ -1089,15 +1183,15 @@ void Avatar::renderBody(bool lookingInMirror) { && (b != BODY_BALL_RIGHT_SHOULDER)) { glColor3fv(DARK_SKIN_COLOR); - float r1 = _bodyBall[_skeleton.joint[b].parent ].radius * 0.8; - float r2 = _bodyBall[b ].radius * 0.8; + float r1 = _bodyBall[_bodyBall[b].parentBall ].radius * 0.8; + float r2 = _bodyBall[b].radius * 0.8; if (b == BODY_BALL_HEAD_BASE) { r1 *= 0.5f; } renderJointConnectingCone ( - _bodyBall[_skeleton.joint[b].parent ].position, - _bodyBall[b ].position, r2, r2 + _bodyBall[_bodyBall[b].parentBall].position, + _bodyBall[b].position, r2, r2 ); } } diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 8b5a67c7fb..3809678cd5 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -48,6 +48,9 @@ enum AvatarBodyBallID BODY_BALL_RIGHT_KNEE, BODY_BALL_RIGHT_HEEL, BODY_BALL_RIGHT_TOES, + +//TEST! +//BODY_BALL_LEFT_MID_THIGH, NUM_AVATAR_BODY_BALLS }; @@ -132,18 +135,21 @@ private: struct AvatarBall { - AvatarJointID parentJoint; - glm::vec3 parentOffset; - glm::vec3 position; - glm::vec3 velocity; - float jointTightness; - float radius; - bool isCollidable; - float touchForce; + AvatarJointID parentJoint; // the skeletal joint that serves as a reference for determining the position + glm::vec3 parentOffset; // a 3D vector in the frame of reference of the parent skeletal joint + AvatarBodyBallID parentBall; // the ball to which this ball is constrained for spring forces + glm::vec3 position; // the actual dynamic position of the ball at any given time + glm::vec3 velocity; // the velocity of the ball + float springLength; // the ideal length of the spring between this ball and its parentBall + float jointTightness; // how tightly the ball position attempts to stay at its ideal position (determined by parentOffset) + float radius; // the radius of the ball + bool isCollidable; // whether or not the ball responds to collisions + float touchForce; // a scalar determining the amount that the cursor (or hand) is penetrating the ball }; Head _head; Skeleton _skeleton; + bool _ballSpringsInitialized; float _TEST_bigSphereRadius; glm::vec3 _TEST_bigSpherePosition; bool _mousePressed; @@ -151,7 +157,6 @@ private: float _bodyYawDelta; float _bodyRollDelta; glm::vec3 _movedHandOffset; - glm::quat _rotation; // the rotation of the avatar body as a whole expressed as a quaternion AvatarBall _bodyBall[ NUM_AVATAR_BODY_BALLS ]; AvatarMode _mode; glm::vec3 _cameraPosition; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 64a8645247..e360b0f97f 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -101,6 +101,7 @@ void Skeleton::update(float deltaTime, const glm::quat& orientation, glm::vec3 p } } + float Skeleton::getArmLength() { return joint[ AVATAR_JOINT_RIGHT_ELBOW ].length + joint[ AVATAR_JOINT_RIGHT_WRIST ].length diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index 28d3a6e81e..5b979b47f3 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -55,6 +55,7 @@ public: float getHeight(); float getPelvisStandingHeight(); float getPelvisFloatingHeight(); + //glm::vec3 getJointVectorFromParent(AvatarJointID jointID) {return joint[jointID].position - joint[joint[jointID].parent].position; } struct AvatarJoint { From b73eb66492a6654347efde52e598d83b47d46244 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 16:31:39 -0700 Subject: [PATCH 31/73] temp test --- interface/src/Avatar.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 99ddd65853..91feb88681 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -43,7 +43,10 @@ const float HEAD_MIN_PITCH = -45; const float HEAD_MAX_YAW = 85; const float HEAD_MIN_YAW = -85; const float PERIPERSONAL_RADIUS = 1.0f; -const float AVATAR_BRAKING_STRENGTH = 40.0f; + +//const float AVATAR_BRAKING_STRENGTH = 40.0f; +const float AVATAR_BRAKING_STRENGTH = 0.0f; + const float MOUSE_RAY_TOUCH_RANGE = 0.01f; const float FLOATING_HEIGHT = 0.13f; const bool USING_HEAD_LEAN = false; From 3ff11d0eb88b586812c5816b5cf741261d182985 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 16:42:27 -0700 Subject: [PATCH 32/73] test --- interface/src/Avatar.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 91feb88681..f4a2627e41 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -35,7 +35,10 @@ const float BODY_SPRING_FORCE = 300.0f; const float BODY_SPRING_DECAY = 16.0f; const float COLLISION_RADIUS_SCALAR = 1.2; //pertains to avatar-to-avatar collisions const float COLLISION_BALL_FORCE = 200.0; //pertains to avatar-to-avatar collisions -const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions + +//const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions +const float COLLISION_BODY_FORCE = 0.0; //pertains to avatar-to-avatar collisions + const float HEAD_ROTATION_SCALE = 0.70; const float HEAD_ROLL_SCALE = 0.40; const float HEAD_MAX_PITCH = 45; From da09dd3259ca59f53bbb9aaa6f2cb2fe44950180 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 17:16:52 -0700 Subject: [PATCH 33/73] test --- interface/src/Avatar.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index f4a2627e41..99ddd65853 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -35,10 +35,7 @@ const float BODY_SPRING_FORCE = 300.0f; const float BODY_SPRING_DECAY = 16.0f; const float COLLISION_RADIUS_SCALAR = 1.2; //pertains to avatar-to-avatar collisions const float COLLISION_BALL_FORCE = 200.0; //pertains to avatar-to-avatar collisions - -//const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions -const float COLLISION_BODY_FORCE = 0.0; //pertains to avatar-to-avatar collisions - +const float COLLISION_BODY_FORCE = 30.0; //pertains to avatar-to-avatar collisions const float HEAD_ROTATION_SCALE = 0.70; const float HEAD_ROLL_SCALE = 0.40; const float HEAD_MAX_PITCH = 45; @@ -46,10 +43,7 @@ const float HEAD_MIN_PITCH = -45; const float HEAD_MAX_YAW = 85; const float HEAD_MIN_YAW = -85; const float PERIPERSONAL_RADIUS = 1.0f; - -//const float AVATAR_BRAKING_STRENGTH = 40.0f; -const float AVATAR_BRAKING_STRENGTH = 0.0f; - +const float AVATAR_BRAKING_STRENGTH = 40.0f; const float MOUSE_RAY_TOUCH_RANGE = 0.01f; const float FLOATING_HEIGHT = 0.13f; const bool USING_HEAD_LEAN = false; From cee22443643174d2493a12435f730e975553abb0 Mon Sep 17 00:00:00 2001 From: Jeffrey Ventrella Date: Mon, 3 Jun 2013 17:55:48 -0700 Subject: [PATCH 34/73] fixed formatting things --- interface/src/Application.cpp | 6 ++---- interface/src/Avatar.cpp | 32 +++++++++++++++----------------- interface/src/Skeleton.cpp | 2 +- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 1480b81050..36ff4075d5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -50,7 +50,7 @@ using namespace std; -const bool TESTING_AVATAR_TOUCH = true; +const bool TESTING_AVATAR_TOUCH = false; // Starfield information static char STAR_FILE[] = "https://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; @@ -1093,14 +1093,12 @@ void Application::idle() { _myCamera.setModeShiftRate(1.0f); } } else { - if (_myAvatar.getIsNearInteractingOther()) { if (_myCamera.getMode() != CAMERA_MODE_FIRST_PERSON) { _myCamera.setMode(CAMERA_MODE_FIRST_PERSON); _myCamera.setModeShiftRate(1.0f); } - } - else { + } else { if (_myCamera.getMode() != CAMERA_MODE_THIRD_PERSON) { _myCamera.setMode(CAMERA_MODE_THIRD_PERSON); _myCamera.setModeShiftRate(1.0f); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 99ddd65853..3949120737 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -121,7 +121,7 @@ void Avatar::initializeBodyBalls() { _ballSpringsInitialized = false; //this gets set to true on the first update pass... - for (int b=0; b::max(); - //loop through all the other avatars for potential interactions... + // loop through all the other avatars for potential interactions... AgentList* agentList = AgentList::getInstance(); for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { @@ -844,7 +844,7 @@ void Avatar::updateAvatarCollisions(float deltaTime) { glm::vec3 vectorBetweenBoundingSpheres(_position - otherAvatar->_position); if (glm::length(vectorBetweenBoundingSpheres) < _height * ONE_HALF + otherAvatar->_height * ONE_HALF) { - //apply forces from collision + // apply forces from collision applyCollisionWithOtherAvatar(otherAvatar, deltaTime); } @@ -860,16 +860,16 @@ void Avatar::updateAvatarCollisions(float deltaTime) { } } -//detect collisions with other avatars and respond +// detect collisions with other avatars and respond void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime) { glm::vec3 bodyPushForce = glm::vec3(0.0f, 0.0f, 0.0f); // loop through the body balls of each avatar to check for every possible collision - for (int b=1; b_bodyBall[o].isCollidable) { glm::vec3 vectorBetweenBalls(_bodyBall[b].position - otherAvatar->_bodyBall[o].position); @@ -898,7 +898,7 @@ void Avatar::applyCollisionWithOtherAvatar(Avatar * otherAvatar, float deltaTime } // b loop } // collidable - //apply force on the whole body + // apply force on the whole body _velocity += bodyPushForce; } @@ -938,7 +938,7 @@ void Avatar::render(bool lookingInMirror) { // render a simple round on the ground projected down from the avatar's position renderDiskShadow(_position, glm::vec3(0.0f, 1.0f, 0.0f), 0.1f, 0.2f); - //render body + // render body renderBody(lookingInMirror); // if this is my avatar, then render my interactions with the other avatar @@ -1010,7 +1010,7 @@ void Avatar::resetBodyBalls() { } void Avatar::updateBodyBalls(float deltaTime) { - // Check for a large repositioning, and re-initialize balls if this has happened + // Check for a large repositioning, and re-initialize balls if this has happened const float BEYOND_BODY_SPRING_RANGE = 2.f; if (glm::length(_position - _bodyBall[BODY_BALL_PELVIS].position) > BEYOND_BODY_SPRING_RANGE) { resetBodyBalls(); @@ -1019,13 +1019,12 @@ void Avatar::updateBodyBalls(float deltaTime) { if (_ballSpringsInitialized) { - //apply spring forces + // apply spring forces glm::vec3 springVector(_bodyBall[b].position); if (b == BODY_BALL_PELVIS) { springVector -= _position; - } - else { + } else { springVector -= _bodyBall[_bodyBall[b].parentBall].position; } @@ -1054,19 +1053,18 @@ void Avatar::updateBodyBalls(float deltaTime) { float decay = 1.0 - BODY_SPRING_DECAY * deltaTime; if (decay > 0.0) { _bodyBall[b].velocity *= decay; - } - else { + } else { _bodyBall[b].velocity = glm::vec3(0.0f, 0.0f, 0.0f); } /* - //apply forces from touch... + // apply forces from touch... if (_bodyBall[b].touchForce > 0.0) { _bodyBall[b].velocity += _mouseRayDirection * _bodyBall[b].touchForce * 0.7f; } */ - //update position by velocity... + // update position by velocity... _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; } } @@ -1229,7 +1227,7 @@ void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity _head.setYaw (angles.x); _head.setPitch(angles.y); _head.setRoll (angles.z); - //printLog("Y/P/R: %3.1f, %3.1f, %3.1f\n", angles.x, angles.y, angles.z); + // printLog("Y/P/R: %3.1f, %3.1f, %3.1f\n", angles.x, angles.y, angles.z); } } diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index e360b0f97f..55c6210068 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -14,7 +14,7 @@ Skeleton::Skeleton() { void Skeleton::initialize() { - for (int b=0; b Date: Mon, 3 Jun 2013 18:08:11 -0700 Subject: [PATCH 35/73] copy and paste working --- interface/src/Application.cpp | 2 +- libraries/shared/src/OctalCode.cpp | 33 ++++++++++++++++----------- libraries/shared/src/OctalCode.h | 8 +++++++ libraries/voxels/src/VoxelConstants.h | 7 +----- 4 files changed, 30 insertions(+), 20 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b2bd7b22e6..8cc313b4bb 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2397,7 +2397,7 @@ void Application::deleteVoxelUnderCursor() { for (int i = 0; i < 5000; i++) { voxelInjector->addSample(10000 * sin((i * 2 * PIE) / (500 * sin((i + 1) / 500.0)))); //FM 3 resonant pulse - // voxelInjector->addSample(20000 * sin((i) /((4 / _mouseVoxel.s) * sin((i)/(20 * _mouseVoxel.s / .001))))); //FM 2 comb filter + //voxelInjector->addSample(20000 * sin((i) /((4 / _mouseVoxel.s) * sin((i)/(20 * _mouseVoxel.s / .001))))); //FM 2 comb filter } AudioInjectionManager::threadInjector(voxelInjector); diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index 150789bec8..d51f058459 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -170,22 +170,21 @@ OctalCodeComparison compareOctalCodes(unsigned char* codeA, unsigned char* codeB char getOctalCodeSectionValue(unsigned char* octalCode, int section) { - int startAtByte = 1 + (3 * section / 8); - char startIndexInByte = (3 * section) % 8; + int startAtByte = 1 + (BITS_IN_OCTAL * section / BITS_IN_BYTE); + char startIndexInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE; unsigned char* startByte = octalCode + startAtByte; return sectionValue(startByte, startIndexInByte); } void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectionValue) { - unsigned char* byteAt = octalCode + 1 + (3 * section / 8); - char bitInByte = (3 * section) % 8; - char shiftBy = 8 - bitInByte - 3; + int byteForSection = (BITS_IN_OCTAL * section / BITS_IN_BYTE); + unsigned char* byteAt = octalCode + 1 + byteForSection; + char bitInByte = (BITS_IN_OCTAL * section) % BITS_IN_BYTE; + char shiftBy = BITS_IN_BYTE - bitInByte - BITS_IN_OCTAL; const unsigned char UNSHIFTED_MASK = 0x07; unsigned char shiftedMask; unsigned char shiftedValue; - - if (shiftBy >=0) { shiftedMask = UNSHIFTED_MASK << shiftBy; shiftedValue = sectionValue << shiftBy; @@ -193,15 +192,24 @@ void setOctalCodeSectionValue(unsigned char* octalCode, int section, char sectio shiftedMask = UNSHIFTED_MASK >> -shiftBy; shiftedValue = sectionValue >> -shiftBy; } - unsigned char oldValue = *byteAt & ~shiftedMask; unsigned char newValue = oldValue | shiftedValue; *byteAt = newValue; - if (bitInByte >= 6) { - shiftBy = bitInByte + 1; + + // If the requested section is partially in the byte, then we + // need to also set the portion of the section value in the next byte + // there's only two cases where this happens, if the bit in byte is + // 6, then it means that 1 extra bit lives in the next byte. If the + // bit in this byte is 7 then 2 extra bits live in the next byte. + const int FIRST_PARTIAL_BIT = 6; + if (bitInByte >= FIRST_PARTIAL_BIT) { + int bitsInFirstByte = BITS_IN_BYTE - bitInByte; + int bitsInSecondByte = BITS_IN_OCTAL - bitsInFirstByte; + shiftBy = BITS_IN_BYTE - bitsInSecondByte; + shiftedMask = UNSHIFTED_MASK << shiftBy; shiftedValue = sectionValue << shiftBy; - + oldValue = byteAt[1] & ~shiftedMask; newValue = oldValue | shiftedValue; byteAt[1] = newValue; @@ -228,8 +236,7 @@ unsigned char* rebaseOctalCode(unsigned char* originalOctalCode, unsigned char* int oldCodeLength = numberOfThreeBitSectionsInCode(originalOctalCode); int newParentCodeLength = numberOfThreeBitSectionsInCode(newParentOctalCode); int newCodeLength = newParentCodeLength + oldCodeLength; - const int COLOR_SPACE = 3; - int bufferLength = newCodeLength + (includeColorSpace ? COLOR_SPACE : 0); + int bufferLength = newCodeLength + (includeColorSpace ? SIZE_OF_COLOR_DATA : 0); unsigned char* newCode = new unsigned char[bufferLength]; *newCode = newCodeLength; // set the length byte diff --git a/libraries/shared/src/OctalCode.h b/libraries/shared/src/OctalCode.h index bfed24a87c..761eac1953 100644 --- a/libraries/shared/src/OctalCode.h +++ b/libraries/shared/src/OctalCode.h @@ -11,6 +11,14 @@ #include +const int BITS_IN_BYTE = 8; +const int BITS_IN_OCTAL = 3; +const int NUMBER_OF_COLORS = 3; // RGB! +const int SIZE_OF_COLOR_DATA = NUMBER_OF_COLORS * sizeof(unsigned char); // size in bytes +const int RED_INDEX = 0; +const int GREEN_INDEX = 1; +const int BLUE_INDEX = 2; + void printOctalCode(unsigned char * octalCode); int bytesRequiredForCodeLength(unsigned char threeBitCodes); bool isDirectParentOfChild(unsigned char *parentOctalCode, unsigned char * childOctalCode); diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index b18315402a..5bf1345d73 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -13,6 +13,7 @@ #define __hifi_VoxelConstants_h__ #include +#include const int TREE_SCALE = 128; @@ -23,12 +24,6 @@ const int MAX_VOXELS_PER_SYSTEM = 200000; const int VERTICES_PER_VOXEL = 24; const int VERTEX_POINTS_PER_VOXEL = 3 * VERTICES_PER_VOXEL; const int INDICES_PER_VOXEL = 3 * 12; - -const int NUMBER_OF_COLORS = 3; // RGB! -const int SIZE_OF_COLOR_DATA = NUMBER_OF_COLORS * sizeof(unsigned char); // size in bytes -const int RED_INDEX = 0; -const int GREEN_INDEX = 1; -const int BLUE_INDEX = 2; const int COLOR_VALUES_PER_VOXEL = NUMBER_OF_COLORS * VERTICES_PER_VOXEL; typedef unsigned long int glBufferIndex; From 03f79f5cab8d566373e7be82d4b762e6f5fbb4d0 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 21:04:42 -0700 Subject: [PATCH 36/73] fixed delete voxel --- libraries/voxels/src/VoxelTree.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index af6b435512..5bf9844fc1 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -286,9 +286,9 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage, b } } - // If we're not a colored leaf, and we have no children, then delete ourselves - // This will collapse the empty tree above us. - if (collapseEmptyTrees && parentNode->getChildCount() == 0 && !parentNode->isColored()) { + // If we're in collpaseEmptryTrees mode, and we're the last child of this parent, then delete the parent. + // This will collapse the empty tree above us. + if (collapseEmptyTrees && parentNode->getChildCount() == 0) { // Can't delete the root this way. if (parentNode != rootNode) { deleteVoxelCodeFromTree(parentNode->getOctalCode(), stage, collapseEmptyTrees); From eef06366555ae3d72d40c6c6092f36a36277a05a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 21:53:06 -0700 Subject: [PATCH 37/73] some cleanup --- interface/src/Application.cpp | 16 +---- interface/src/Avatar.cpp | 1 - libraries/avatars/src/AvatarData.cpp | 100 +-------------------------- libraries/avatars/src/AvatarData.h | 4 -- 4 files changed, 2 insertions(+), 119 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 9abe3d4510..d48935ae27 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1560,24 +1560,10 @@ void Application::loadViewFrustum(Camera& camera, ViewFrustum& viewFrustum) { float farClip = camera.getFarClip(); glm::quat rotation = camera.getRotation(); - glm::vec3 direction = rotation * AVATAR_FRONT; - glm::vec3 up = rotation * AVATAR_UP; - glm::vec3 right = rotation * AVATAR_RIGHT; - /* - printf("position.x=%f, position.y=%f, position.z=%f\n", position.x, position.y, position.z); - printf("yaw=%f, pitch=%f, roll=%f\n", yaw,pitch,roll); - printf("direction.x=%f, direction.y=%f, direction.z=%f\n", direction.x, direction.y, direction.z); - printf("up.x=%f, up.y=%f, up.z=%f\n", up.x, up.y, up.z); - printf("right.x=%f, right.y=%f, right.z=%f\n", right.x, right.y, right.z); - printf("fov=%f\n", fov); - printf("nearClip=%f\n", nearClip); - printf("farClip=%f\n", farClip); - */ - // Set the viewFrustum up with the correct position and orientation of the camera viewFrustum.setPosition(position); - viewFrustum.setOrientation(o.getQuat()); + viewFrustum.setOrientation(rotation); // Also make sure it's got the correct lens details from the camera viewFrustum.setFieldOfView(fov); diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index b1a56f723f..3949120737 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -72,7 +72,6 @@ Avatar::Avatar(Agent* owningAgent) : _bodyYawDelta(0.0f), _bodyRollDelta(0.0f), _movedHandOffset(0.0f, 0.0f, 0.0f), - _rotation(0.0f, 0.0f, 0.0f, 0.0f), _mode(AVATAR_MODE_STANDING), _cameraPosition(0.0f, 0.0f, 0.0f), _handHoldingPosition(0.0f, 0.0f, 0.0f), diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 41812f8d3a..6ff6967b61 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -78,13 +78,6 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) { // Hand Position - is relative to body position glm::vec3 handPositionRelative = _handPosition - _position; memcpy(destinationBuffer, &handPositionRelative, sizeof(float) * 3); - - printf("handPositionRelative=%f,%f,%f\n",handPositionRelative.x, handPositionRelative.y, handPositionRelative.z); - printf("_handPosition=%f,%f,%f\n",_handPosition.x, _handPosition.y, _handPosition.z); - printf("_position=%f,%f,%f\n",_position.x, _position.y, _position.z); - -packVec3ToBytes(NULL, handPositionRelative, -1.0f , 1.0f, 4); - destinationBuffer += sizeof(float) * 3; // Lookat Position @@ -92,12 +85,9 @@ packVec3ToBytes(NULL, handPositionRelative, -1.0f , 1.0f, 4); destinationBuffer += sizeof(_headData->_lookAtPosition); // Instantaneous audio loudness (used to drive facial animation) -<<<<<<< HEAD - destinationBuffer += packFloatToByte(destinationBuffer, std::min(MAX_AUDIO_LOUDNESS, _audioLoudness), MAX_AUDIO_LOUDNESS); -======= + //destinationBuffer += packFloatToByte(destinationBuffer, std::min(MAX_AUDIO_LOUDNESS, _audioLoudness), MAX_AUDIO_LOUDNESS); memcpy(destinationBuffer, &_headData->_audioLoudness, sizeof(float)); destinationBuffer += sizeof(float); ->>>>>>> c7921c4be90dc45a82793845a9a55b77a3fb5a3f // camera details memcpy(destinationBuffer, &_cameraPosition, sizeof(_cameraPosition)); @@ -174,9 +164,6 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { memcpy(&handPositionRelative, sourceBuffer, sizeof(float) * 3); _handPosition = _position + handPositionRelative; sourceBuffer += sizeof(float) * 3; - printf("handPositionRelative=%f,%f,%f\n",handPositionRelative.x, handPositionRelative.y, handPositionRelative.z); - printf("_handPosition=%f,%f,%f\n",_handPosition.x, _handPosition.y, _handPosition.z); - printf("_position=%f,%f,%f\n",_position.x, _position.y, _position.z); // Lookat Position memcpy(&_headData->_lookAtPosition, sourceBuffer, sizeof(_headData->_lookAtPosition)); @@ -341,88 +328,3 @@ int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy) { return sizeof(holder); } -int packVec3ToBytes(unsigned char* buffer, const glm::vec3& vec, float min, float max, int bytes) { - const int ITEMS_IN_VEC3 = 3; - const int BITS_IN_BYTE = 8; - const int BYTE_MASK = 0xff; - assert(bytes < sizeof(double) * ITEMS_IN_VEC3); - unsigned char holder[bytes]; - memset(&holder, 0, bytes); - - int bitsTotal = bytes * BITS_IN_BYTE; - int bitsPerItem = floor(bitsTotal / ITEMS_IN_VEC3); - long maxEncodedPerItem = powf(2, bitsPerItem) - 1; // must be a better way to get this - float scaleBy = (max - min); - float conversionRatio = (maxEncodedPerItem / scaleBy); - -printf("bitsTotal=%d\n", bitsTotal); -printf("bitsPerItem=%d\n", bitsPerItem); -printf("maxEncodedPerItem=%ld\n", maxEncodedPerItem); -printf("scaleBy=%f\n", scaleBy); -printf("conversionRatio=%f\n", conversionRatio); - - int bitInByte = 0; - int byteInHolder = 0; - long encodedItem = 0; - int leftShiftThisByte = 0; - - for (int i = 0; i < ITEMS_IN_VEC3; i++) { - -printf(">>> item=%d\n", i); -printf("vec[item]=%f\n", vec[i]); - - long encodedItemMask = maxEncodedPerItem; - encodedItem = floorf((vec[i] - min) * conversionRatio); - -printf("encodedItem=%ld\n", encodedItem); -printf("encodedItemMask=%ld\n", encodedItemMask); -printf("leftShiftThisByte=%d\n", leftShiftThisByte); - - for (int bitsInThisItem = 0; bitsInThisItem < bitsPerItem; ) { - -printf(">>> bitsInThisItem=%d\n", bitsInThisItem); - - unsigned char thisBytePortion = (encodedItemMask << leftShiftThisByte) & BYTE_MASK; - -printf("thisBytePortion=%d\n", (int)thisBytePortion); - - unsigned char thisByteValue = (encodedItem << leftShiftThisByte) & thisBytePortion; - -printf("thisByteValue=%d\n", (int)thisByteValue); - - holder[byteInHolder] |= thisByteValue; - -printf("after byte %d: ", byteInHolder); -outputBufferBits((unsigned char*)&holder, bytes); - - -///////not handling this correctly... second portion of second item is not moving to 3rd byte... - - leftShiftThisByte = 0; // reset after first time; - int numberOfBitsInThisByte = numberOfOnes(thisBytePortion); - bitsInThisItem += numberOfBitsInThisByte; - if (numberOfBitsInThisByte == 8) { - byteInHolder++; - encodedItemMask = encodedItemMask >> numberOfBitsInThisByte; - encodedItem = encodedItem >> numberOfBitsInThisByte; - } else { - leftShiftThisByte = numberOfBitsInThisByte; - } -printf("numberOfBitsInThisByte=%d\n", numberOfBitsInThisByte); -printf("AFTER bitsInThisItem=%d\n", bitsInThisItem); -printf("AFTER encodedItem=%ld\n", encodedItem); -printf("AFTER encodedItemMask=%ld\n", encodedItemMask); - } - } - - printf("done: "); - outputBufferBits((unsigned char*)&holder, bytes); - - //memcpy(buffer, &holder, sizeof(holder)); - return sizeof(holder); -} - -int unpackVec3FromBytes(unsigned char* buffer, glm::vec3& vec, float min, float max, int bytes) { - unsigned char holder[bytes]; - return sizeof(holder); -} diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 7bf4be1382..d728ff53d8 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -164,8 +164,4 @@ int unpackClipValueFromTwoByte(unsigned char* buffer, float& clipValue); int packFloatToByte(unsigned char* buffer, float value, float scaleBy); int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy); -int unpackVec3FromBytes(unsigned char* buffer, glm::vec3& vec, float min, float max, int bytes); -int packVec3ToBytes(unsigned char* buffer, const glm::vec3& vec, float min, float max, int bytes); - - #endif /* defined(__hifi__AvatarData__) */ From ceb15d407df6a5ee5f43506ffb14679e2fbe344c Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 3 Jun 2013 22:08:19 -0700 Subject: [PATCH 38/73] removed assert --- 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 10967ea3e7..08b84e2b7e 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -106,7 +106,7 @@ int getSemiNibbleAt(unsigned char& byte, int bitIndex) { } void setSemiNibbleAt(unsigned char& byte, int bitIndex, int value) { - assert(value <= 3 && value >= 0); + //assert(value <= 3 && value >= 0); byte += ((value & 3) << (7 - bitIndex)); // semi-nibbles store 00, 01, 10, or 11 } From 435791f28c0d08fa144881f773e7a46a303fc9b3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:02:10 -0700 Subject: [PATCH 39/73] CR feedback --- interface/src/Application.cpp | 14 +++++++------- interface/src/Application.h | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 05bd0f3d5a..d8eed95ea7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1293,15 +1293,15 @@ void Application::chooseVoxelPaintColor() { } const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500; -struct SendVoxelsOperataionArgs { +struct SendVoxelsOperationArgs { unsigned char* newBaseOctCode; unsigned char messageBuffer[MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE]; int bufferInUse; }; -bool Application::sendVoxelsOperataion(VoxelNode* node, void* extraData) { - SendVoxelsOperataionArgs* args = (SendVoxelsOperataionArgs*)extraData; +bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { + SendVoxelsOperationArgs* args = (SendVoxelsOperationArgs*)extraData; if (node->isColored()) { unsigned char* nodeOctalCode = node->getOctalCode(); @@ -1372,7 +1372,7 @@ void Application::importVoxels() { // Recurse the Import Voxels tree, where everything is root relative, and send all the colored voxels to // the server as an set voxel message, this will also rebase the voxels to the new location unsigned char* calculatedOctCode = NULL; - SendVoxelsOperataionArgs args; + SendVoxelsOperationArgs args; args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; *sequenceAt = 0; @@ -1386,7 +1386,7 @@ void Application::importVoxels() { args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } - importVoxels.recurseTreeWithOperation(sendVoxelsOperataion, &args); + importVoxels.recurseTreeWithOperation(sendVoxelsOperation, &args); // If we have voxels left in the packet, then send the packet if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { @@ -1418,7 +1418,7 @@ void Application::pasteVoxels() { // Recurse the clipboard tree, where everything is root relative, and send all the colored voxels to // the server as an set voxel message, this will also rebase the voxels to the new location - SendVoxelsOperataionArgs args; + SendVoxelsOperationArgs args; args.messageBuffer[0] = PACKET_HEADER_SET_VOXEL_DESTRUCTIVE; unsigned short int* sequenceAt = (unsigned short int*)&args.messageBuffer[sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE)]; *sequenceAt = 0; @@ -1433,7 +1433,7 @@ void Application::pasteVoxels() { args.newBaseOctCode = calculatedOctCode = pointToVoxel(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); } - _clipboardTree.recurseTreeWithOperation(sendVoxelsOperataion, &args); + _clipboardTree.recurseTreeWithOperation(sendVoxelsOperation, &args); // If we have voxels left in the packet, then send the packet if (args.bufferInUse > (sizeof(PACKET_HEADER_SET_VOXEL_DESTRUCTIVE) + sizeof(unsigned short int))) { diff --git a/interface/src/Application.h b/interface/src/Application.h index ee48307910..edcc1d6b82 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -161,7 +161,7 @@ private slots: private: - static bool sendVoxelsOperataion(VoxelNode* node, void* extraData); + static bool sendVoxelsOperation(VoxelNode* node, void* extraData); void initMenu(); void updateFrustumRenderModeAction(); From 1f3de3e12b64621a4d125942a6b7b93d46ffc18f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:03:26 -0700 Subject: [PATCH 40/73] CR feedback --- 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 5bf9844fc1..de6bafef3d 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -286,7 +286,7 @@ void VoxelTree::deleteVoxelCodeFromTree(unsigned char* codeBuffer, bool stage, b } } - // If we're in collpaseEmptryTrees mode, and we're the last child of this parent, then delete the parent. + // If we're in collapseEmptyTrees mode, and we're the last child of this parent, then delete the parent. // This will collapse the empty tree above us. if (collapseEmptyTrees && parentNode->getChildCount() == 0) { // Can't delete the root this way. From 0a9b3bf5ce87e1045d4aaf21f323330db6d44159 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:07:18 -0700 Subject: [PATCH 41/73] changed file name and exention to Sparse Voxel Octree and svo --- interface/src/Application.cpp | 7 ++++--- voxel-edit/src/main.cpp | 2 +- voxel-server/src/main.cpp | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d8eed95ea7..00772e7fec 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1343,8 +1343,8 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { } void Application::exportVoxels() { - QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), "~/voxels.hio2", - tr("High Fidelity Voxel Files (*.hio2)")); + QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), "~/voxels.svo", + tr("Sparse Voxel Octree Files (*.svo)")); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); @@ -1359,7 +1359,8 @@ void Application::exportVoxels() { } void Application::importVoxels() { - QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), "~", tr("High Fidelity Voxel Files (*.hio2)")); + QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), "~", + tr("Sparse Voxel Octree Files (*.svo)")); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index 222bf3f15b..d2c88812ca 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -92,7 +92,7 @@ int main(int argc, const char * argv[]) unsigned long nodeCount = myTree.getVoxelCount(); printf("Nodes after adding scenes: %ld nodes\n", nodeCount); - myTree.writeToFileV2("voxels.hio2"); + myTree.writeToFileV2("voxels.svo"); } return 0; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 70f7ab8752..4d06f60f0c 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -30,8 +30,8 @@ #include #endif -const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.hio2"; -const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.hio2"; +const char* LOCAL_VOXELS_PERSIST_FILE = "resources/voxels.svo"; +const char* VOXELS_PERSIST_FILE = "/etc/highfidelity/voxel-server/resources/voxels.svo"; const double VOXEL_PERSIST_INTERVAL = 1000.0 * 30; // every 30 seconds const int VOXEL_LISTEN_PORT = 40106; From 37cc436b2b9c4a082f6e252f38a4d91f70e41a11 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:08:18 -0700 Subject: [PATCH 42/73] CR feedback --- 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 de6bafef3d..96c9320edd 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1223,7 +1223,7 @@ void VoxelTree::copyFromTreeIntoSubTree(VoxelTree* sourceTree, VoxelNode* destin MAX_VOXEL_PACKET_SIZE - 1, nodeBag, IGNORE_VIEW_FRUSTUM, WANT_COLOR, NO_EXISTS_BITS); // ask destination tree to read the bitstream - readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS,destinationNode); + readBitstreamToTree(&outputBuffer[0], bytesWritten, WANT_COLOR, NO_EXISTS_BITS, destinationNode); } } From 4f3872c18fb696863cfbe20c71a4f84e2c0a49ad Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:13:58 -0700 Subject: [PATCH 43/73] CR feedback --- interface/src/Application.cpp | 4 ++-- interface/src/VoxelSystem.cpp | 8 ++++---- interface/src/VoxelSystem.h | 4 ++-- libraries/voxels/src/VoxelTree.cpp | 4 ++-- libraries/voxels/src/VoxelTree.h | 4 ++-- voxel-edit/src/main.cpp | 2 +- voxel-server/src/main.cpp | 8 ++++---- 7 files changed, 17 insertions(+), 17 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 00772e7fec..4610d889ed 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1351,7 +1351,7 @@ void Application::exportVoxels() { if (selectedNode) { VoxelTree exportTree; _voxels.copySubTreeIntoNewTree(selectedNode, &exportTree, true); - exportTree.writeToFileV2(fileName); + exportTree.writeToSVOFile(fileName); } // restore the main window's active state @@ -1366,7 +1366,7 @@ void Application::importVoxels() { // Read the file into a tree VoxelTree importVoxels; - importVoxels.readFromFileV2(fileName); + importVoxels.readFromSVOFile(fileName); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); diff --git a/interface/src/VoxelSystem.cpp b/interface/src/VoxelSystem.cpp index b99519e845..11c274119b 100644 --- a/interface/src/VoxelSystem.cpp +++ b/interface/src/VoxelSystem.cpp @@ -70,12 +70,12 @@ void VoxelSystem::loadVoxelsFile(const char* fileName, bool wantColorRandomizer) setupNewVoxelsForDrawing(); } -void VoxelSystem::writeToFileV2(const char* filename, VoxelNode* node) const { - _tree->writeToFileV2(filename, node); +void VoxelSystem::writeToSVOFile(const char* filename, VoxelNode* node) const { + _tree->writeToSVOFile(filename, node); } -bool VoxelSystem::readFromFileV2(const char* filename, VoxelNode* node) { - bool result = _tree->readFromFileV2(filename, node); +bool VoxelSystem::readFromSVOFile(const char* filename) { + bool result = _tree->readFromSVOFile(filename); if (result) { setupNewVoxelsForDrawing(); } diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index c15ba53ba0..ee63801f92 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -44,8 +44,8 @@ public: void setViewerAvatar(Avatar *newViewerAvatar) { _viewerAvatar = newViewerAvatar; }; void setCamera(Camera* newCamera) { _camera = newCamera; }; void loadVoxelsFile(const char* fileName,bool wantColorRandomizer); - void writeToFileV2(const char* filename, VoxelNode* node) const; - bool readFromFileV2(const char* filename, VoxelNode* node); + void writeToSVOFile(const char* filename, VoxelNode* node) const; + bool readFromSVOFile(const char* filename); long int getVoxelsCreated(); long int getVoxelsColored(); diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 96c9320edd..49d79141de 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -1123,7 +1123,7 @@ int VoxelTree::encodeTreeBitstreamRecursion(int maxEncodeLevel, int& currentEnco return bytesAtThisLevel; } -bool VoxelTree::readFromFileV2(const char* fileName, VoxelNode* node) { +bool VoxelTree::readFromSVOFile(const char* fileName) { std::ifstream file(fileName, std::ios::in|std::ios::binary|std::ios::ate); if(file.is_open()) { printLog("loading file %s...\n", fileName); @@ -1144,7 +1144,7 @@ bool VoxelTree::readFromFileV2(const char* fileName, VoxelNode* node) { return false; } -void VoxelTree::writeToFileV2(const char* fileName, VoxelNode* node) const { +void VoxelTree::writeToSVOFile(const char* fileName, VoxelNode* node) const { std::ofstream file(fileName, std::ios::out|std::ios::binary); diff --git a/libraries/voxels/src/VoxelTree.h b/libraries/voxels/src/VoxelTree.h index a2302f6cc7..b63e6eb738 100644 --- a/libraries/voxels/src/VoxelTree.h +++ b/libraries/voxels/src/VoxelTree.h @@ -92,8 +92,8 @@ public: void loadVoxelsFile(const char* fileName, bool wantColorRandomizer); // these will read/write files that match the wireformat, excluding the 'V' leading - void writeToFileV2(const char* filename, VoxelNode* node = NULL) const; - bool readFromFileV2(const char* filename, VoxelNode* node = NULL); + void writeToSVOFile(const char* filename, VoxelNode* node = NULL) const; + bool readFromSVOFile(const char* filename); unsigned long getVoxelCount(); diff --git a/voxel-edit/src/main.cpp b/voxel-edit/src/main.cpp index d2c88812ca..9571e4adf5 100644 --- a/voxel-edit/src/main.cpp +++ b/voxel-edit/src/main.cpp @@ -92,7 +92,7 @@ int main(int argc, const char * argv[]) unsigned long nodeCount = myTree.getVoxelCount(); printf("Nodes after adding scenes: %ld nodes\n", nodeCount); - myTree.writeToFileV2("voxels.svo"); + myTree.writeToSVOFile("voxels.svo"); } return 0; diff --git a/voxel-server/src/main.cpp b/voxel-server/src/main.cpp index 4d06f60f0c..9bf4a1dcc4 100644 --- a/voxel-server/src/main.cpp +++ b/voxel-server/src/main.cpp @@ -399,10 +399,10 @@ void persistVoxelsWhenDirty() { { PerformanceWarning warn(::shouldShowAnimationDebug, - "persistVoxelsWhenDirty() - writeToFileV2()", ::shouldShowAnimationDebug); + "persistVoxelsWhenDirty() - writeToSVOFile()", ::shouldShowAnimationDebug); printf("saving voxels to file...\n"); - randomTree.writeToFileV2(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); + randomTree.writeToSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); randomTree.clearDirtyBit(); // tree is clean after saving printf("DONE saving voxels to file...\n"); } @@ -505,7 +505,7 @@ int main(int argc, const char * argv[]) { bool persistantFileRead = false; if (::wantVoxelPersist) { printf("loading voxels from file...\n"); - persistantFileRead = ::randomTree.readFromFileV2(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); + persistantFileRead = ::randomTree.readFromSVOFile(::wantLocalDomain ? LOCAL_VOXELS_PERSIST_FILE : VOXELS_PERSIST_FILE); ::randomTree.clearDirtyBit(); // the tree is clean since we just loaded it printf("DONE loading voxels from file... fileRead=%s\n", debug::valueOf(persistantFileRead)); unsigned long nodeCount = ::randomTree.getVoxelCount(); @@ -517,7 +517,7 @@ int main(int argc, const char * argv[]) { const char* INPUT_FILE = "-i"; const char* voxelsFilename = getCmdOption(argc, argv, INPUT_FILE); if (voxelsFilename) { - randomTree.readFromFileV2(voxelsFilename); + randomTree.readFromSVOFile(voxelsFilename); } // Check to see if the user passed in a command line option for setting packet send rate From 743e1a433c00e80c388f3d61d34967d53e6ce5d4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 01:24:35 -0700 Subject: [PATCH 44/73] make import/export default to desktop --- interface/src/Application.cpp | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4610d889ed..56f1604e97 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -1343,8 +1344,11 @@ bool Application::sendVoxelsOperation(VoxelNode* node, void* extraData) { } void Application::exportVoxels() { - QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), "~/voxels.svo", - tr("Sparse Voxel Octree Files (*.svo)")); + QString desktopLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); + QString suggestedName = desktopLocation.append("/voxels.svo"); + + QString fileNameString = QFileDialog::getSaveFileName(_glWidget, tr("Export Voxels"), suggestedName, + tr("Sparse Voxel Octree Files (*.svo)")); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); @@ -1359,7 +1363,8 @@ void Application::exportVoxels() { } void Application::importVoxels() { - QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), "~", + QString desktopLocation = QDesktopServices::storageLocation(QDesktopServices::DesktopLocation); + QString fileNameString = QFileDialog::getOpenFileName(_glWidget, tr("Import Voxels"), desktopLocation, tr("Sparse Voxel Octree Files (*.svo)")); QByteArray fileNameAscii = fileNameString.toAscii(); const char* fileName = fileNameAscii.data(); From 626874f9ecbf210722b8211c971fc41497e27f24 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 08:47:57 -0700 Subject: [PATCH 45/73] add delete key support while in select mode --- interface/src/Application.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 56f1604e97..26d7f92533 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -617,6 +617,12 @@ void Application::keyPressEvent(QKeyEvent* event) { } resizeGL(_glWidget->width(), _glWidget->height()); break; + case Qt::Key_Backspace: + case Qt::Key_Delete: + if (_selectVoxelMode->isChecked()) { + deleteVoxelUnderCursor(); + } + break; default: event->ignore(); From ce499f925a3d16b1e21c610b78cc20b774d6e8b3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 09:02:34 -0700 Subject: [PATCH 46/73] add cut voxels --- interface/src/Application.cpp | 6 ++++++ interface/src/Application.h | 1 + 2 files changed, 7 insertions(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 26d7f92533..6ef5d0d5bc 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1413,6 +1413,11 @@ void Application::importVoxels() { _window->activateWindow(); } +void Application::cutVoxels() { + copyVoxels(); + deleteVoxelUnderCursor(); +} + void Application::copyVoxels() { VoxelNode* selectedNode = _voxels.getVoxelAt(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z, _mouseVoxel.s); if (selectedNode) { @@ -1545,6 +1550,7 @@ void Application::initMenu() { voxelMenu->addAction("Export Voxels", this, SLOT(exportVoxels()), Qt::CTRL | Qt::Key_E); voxelMenu->addAction("Import Voxels", this, SLOT(importVoxels()), Qt::CTRL | Qt::Key_I); + voxelMenu->addAction("Cut Voxels", this, SLOT(cutVoxels()), Qt::CTRL | Qt::Key_X); voxelMenu->addAction("Copy Voxels", this, SLOT(copyVoxels()), Qt::CTRL | Qt::Key_C); voxelMenu->addAction("Paste Voxels", this, SLOT(pasteVoxels()), Qt::CTRL | Qt::Key_V); diff --git a/interface/src/Application.h b/interface/src/Application.h index edcc1d6b82..017759277c 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -156,6 +156,7 @@ private slots: void chooseVoxelPaintColor(); void exportVoxels(); void importVoxels(); + void cutVoxels(); void copyVoxels(); void pasteVoxels(); From edf6e767f02bed6c75dea1279e8ba360dab4d913 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 09:35:38 -0700 Subject: [PATCH 47/73] removed unused variable --- interface/src/Head.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index bbf773a8a9..21df933416 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -595,7 +595,7 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi void Head::updateHairPhysics(float deltaTime) { glm::quat orientation = getOrientation(); - glm::vec3 right = orientation * AVATAR_RIGHT; + //glm::vec3 right = orientation * AVATAR_RIGHT; // not used for now glm::vec3 up = orientation * AVATAR_UP; glm::vec3 front = orientation * AVATAR_FRONT; From c199190666fed9badc449b60a514a0f64c06e963 Mon Sep 17 00:00:00 2001 From: atlante45 Date: Tue, 4 Jun 2013 19:00:38 +0200 Subject: [PATCH 48/73] Fixes asked by ZappoMan on QSettings' commit. --- interface/src/Application.cpp | 50 +++++++++++++++++------------------ interface/src/Application.h | 14 +++++----- interface/src/Avatar.cpp | 8 +++--- interface/src/Avatar.h | 4 +-- 4 files changed, 37 insertions(+), 39 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d4ef038487..3d57fc341b 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -2201,38 +2202,38 @@ void* Application::networkReceive(void* args) { return NULL; } -void Application::scanMenuBar(settingsAction f, QSettings *set) { - if (NULL == _window->menuBar()) { +void Application::scanMenuBar(settingsAction modifySetting, QSettings* set) { + if (!_window->menuBar()) { return; } - QList menus = _window->menuBar()->findChildren(); + QList menus = _window->menuBar()->findChildren(); for (QList::const_iterator it = menus.begin(); menus.end() != it; ++it) { - scanMenu(*it, f, set); + scanMenu(*it, modifySetting, set); } } -void Application::scanMenu(QMenu *menu, settingsAction f, QSettings *set) { - QList actions = menu->actions(); +void Application::scanMenu(QMenu* menu, settingsAction modifySetting, QSettings* set) { + QList actions = menu->actions(); set->beginGroup(menu->title()); for (QList::const_iterator it = actions.begin(); actions.end() != it; ++it) { if ((*it)->menu()) { - scanMenu((*it)->menu(), f, set); + scanMenu((*it)->menu(), modifySetting, set); } if ((*it)->isCheckable()) { - f(set, *it); + modifySetting(set, *it); } } set->endGroup(); } -void Application::loadAction(QSettings *set, QAction *action) { +void Application::loadAction(QSettings* set, QAction* action) { action->setChecked(set->value(action->text(), action->isChecked()).toBool()); - } +} -void Application::saveAction(QSettings *set, QAction *action) { +void Application::saveAction(QSettings* set, QAction* action) { set->setValue(action->text(), action->isChecked()); } @@ -2240,44 +2241,41 @@ void Application::setAutosave(bool wantsAutosave) { _autosave = wantsAutosave; } -void Application::loadSettings(QSettings *set) { - if (!set) set = this->getSettings(); +void Application::loadSettings(QSettings* set) { + if (!set) set = getSettings(); scanMenuBar(&Application::loadAction, set); - getAvatar()->getData(set); + getAvatar()->loadData(set); } -void Application::saveSettings(QSettings *set) { - if (!set) set = this->getSettings(); +void Application::saveSettings(QSettings* set) { + if (!set) set = getSettings(); scanMenuBar(&Application::saveAction, set); - getAvatar()->setData(set); + getAvatar()->saveData(set); } void Application::importSettings() { - QString fileName = QFileDialog::getOpenFileName(this->_window, + QString locationDir(QDesktopServices::displayName(QDesktopServices::DesktopLocation)); + QString fileName = QFileDialog::getOpenFileName(_window, tr("Open .ini config file"), - "", + locationDir, tr("Text files (*.ini)")); - if (fileName != "") { QSettings tmp(fileName, QSettings::IniFormat); - loadSettings(&tmp); } } void Application::exportSettings() { - QString fileName = QFileDialog::getSaveFileName(this->_window, + QString locationDir(QDesktopServices::displayName(QDesktopServices::DesktopLocation)); + QString fileName = QFileDialog::getSaveFileName(_window, tr("Save .ini config file"), - "", + locationDir, tr("Text files (*.ini)")); - if (fileName != "") { QSettings tmp(fileName, QSettings::IniFormat); - saveSettings(&tmp); - tmp.sync(); } } diff --git a/interface/src/Application.h b/interface/src/Application.h index 4a5cb04622..b1f1307b35 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -108,8 +108,8 @@ private slots: void chooseVoxelPaintColor(); void setAutosave(bool wantsAutosave); - void loadSettings(QSettings *set = NULL); - void saveSettings(QSettings *set = NULL); + void loadSettings(QSettings* set = NULL); + void saveSettings(QSettings* set = NULL); void importSettings(); void exportSettings(); @@ -148,11 +148,11 @@ private: static void* networkReceive(void* args); // methodes handling menu settings - typedef void(*settingsAction)(QSettings *, QAction *); - static void loadAction(QSettings *set, QAction *action); - static void saveAction(QSettings *set, QAction *action); - void scanMenuBar(settingsAction, QSettings *set); - void scanMenu(QMenu *menu, settingsAction f, QSettings *set); + typedef void(*settingsAction)(QSettings*, QAction*); + static void loadAction(QSettings* set, QAction* action); + static void saveAction(QSettings* set, QAction* action); + void scanMenuBar(settingsAction modifySetting, QSettings* set); + void scanMenu(QMenu* menu, settingsAction modifySetting, QSettings* set); QMainWindow* _window; QGLWidget* _glWidget; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 7d2aa9784d..57f2523248 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -1114,10 +1114,10 @@ void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity } } -void Avatar::getData(QSettings *set) { +void Avatar::loadData(QSettings* set) { set->beginGroup("Avatar"); - _bodyYaw = set->value("bodyYawn", _bodyYaw).toFloat(); + _bodyYaw = set->value("bodyYaw", _bodyYaw).toFloat(); _bodyPitch = set->value("bodyPitch", _bodyPitch).toFloat(); _bodyRoll = set->value("bodyRoll", _bodyRoll).toFloat(); @@ -1128,10 +1128,10 @@ void Avatar::getData(QSettings *set) { set->endGroup(); } -void Avatar::setData(QSettings *set) { +void Avatar::saveData(QSettings* set) { set->beginGroup("Avatar"); - set->setValue("bodyYawn", _bodyYaw); + set->setValue("bodyYaw", _bodyYaw); set->setValue("bodyPitch", _bodyPitch); set->setValue("bodyRoll", _bodyRoll); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 3b18ed1c1e..5ff38215b9 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -97,8 +97,8 @@ public: glm::vec3 getThrust() { return _thrust; }; // get/set avatar data - void setData(QSettings *set); - void getData(QSettings *set); + void saveData(QSettings* set); + void loadData(QSettings* set); private: // privatize copy constructor and assignment operator to avoid copying From bc8eadd526b70b4e0ca624b8d541e9ae21efd140 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 10:22:58 -0700 Subject: [PATCH 49/73] More work on voxeltars; separated default pose from bind pose. --- interface/CMakeLists.txt | 4 +- interface/src/Application.cpp | 44 ++++++++++++++++++-- interface/src/Application.h | 9 +++++ interface/src/Avatar.h | 2 + interface/src/AvatarVoxelSystem.cpp | 63 ++++++++++++++++++++++------- interface/src/AvatarVoxelSystem.h | 23 +++++++++-- interface/src/Skeleton.cpp | 61 ++++++++++++++++++++-------- interface/src/Skeleton.h | 1 + interface/src/VoxelSystem.h | 4 +- 9 files changed, 171 insertions(+), 40 deletions(-) diff --git a/interface/CMakeLists.txt b/interface/CMakeLists.txt index d5da2073fb..b2984b35bb 100644 --- a/interface/CMakeLists.txt +++ b/interface/CMakeLists.txt @@ -63,12 +63,12 @@ if (APPLE) endif (APPLE) -find_package(Qt4 REQUIRED QtCore QtGui QtOpenGL) +find_package(Qt4 REQUIRED QtCore QtGui QtNetwork QtOpenGL) include(${QT_USE_FILE}) SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -isystem ${QT_QTGUI_INCLUDE_DIR}") # run qt moc on qt-enabled headers -qt4_wrap_cpp(INTERFACE_SRCS src/Application.h) +qt4_wrap_cpp(INTERFACE_SRCS src/Application.h src/AvatarVoxelSystem.h) # create the executable, make it a bundle on OS X add_executable(${TARGET_NAME} MACOSX_BUNDLE ${INTERFACE_SRCS}) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index e8aaaf9856..57f1b89969 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -21,16 +21,23 @@ #include #include +#include #include +#include #include +#include #include #include +#include #include #include #include +#include #include +#include #include #include +#include #include #include @@ -1122,6 +1129,31 @@ void Application::terminate() { } } +void Application::editPreferences() { + QDialog dialog(_glWidget); + dialog.setWindowTitle("Interface Preferences"); + QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom); + dialog.setLayout(layout); + + QFormLayout* form = new QFormLayout(); + layout->addLayout(form, 1); + + QLineEdit* avatarURL = new QLineEdit(_settings->value("avatarURL").toString()); + form->addRow("Avatar URL:", avatarURL); + + QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept())); + dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject())); + layout->addWidget(buttons); + + if (dialog.exec() != QDialog::Accepted) { + return; + } + QUrl url(avatarURL->text()); + _settings->setValue("avatarURL", url); + _myAvatar.getVoxels()->loadVoxelsFromURL(url); +} + void Application::pair() { PairingHandler::sendPairRequest(); } @@ -1285,6 +1317,9 @@ void Application::initMenu() { QMenu* fileMenu = menuBar->addMenu("File"); fileMenu->addAction("Quit", this, SLOT(quit()), Qt::CTRL | Qt::Key_Q); + QMenu* editMenu = menuBar->addMenu("Edit"); + editMenu->addAction("Preferences...", this, SLOT(editPreferences())); + QMenu* pairMenu = menuBar->addMenu("Pair"); pairMenu->addAction("Pair", this, SLOT(pair())); @@ -1325,9 +1360,7 @@ void Application::initMenu() { renderMenu->addAction("First Person", this, SLOT(setRenderFirstPerson(bool)), Qt::Key_P)->setCheckable(true); QMenu* toolsMenu = menuBar->addMenu("Tools"); - (_renderStatsOn = toolsMenu->addAction("Stats"))->setCheckable(true); - _renderStatsOn->setShortcut(Qt::Key_Slash); (_logOn = toolsMenu->addAction("Log"))->setCheckable(true); _logOn->setChecked(false); @@ -1381,6 +1414,9 @@ 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); + + _networkAccessManager = new QNetworkAccessManager(this); + _settings = new QSettings("High Fidelity", "Interface", this); } void Application::updateFrustumRenderModeAction() { @@ -1431,6 +1467,8 @@ void Application::init() { _myCamera.setModeShiftRate(1.0f); _myAvatar.setDisplayingLookatVectors(false); + _myAvatar.getVoxels()->loadVoxelsFromURL(_settings->value("avatarURL").toUrl()); + QCursor::setPos(_headMouseX, _headMouseY); OculusManager::connect(); @@ -1727,7 +1765,7 @@ void Application::displayOculus(Camera& whichCamera) { glPopMatrix(); } - + void Application::displaySide(Camera& whichCamera) { // transform by eye offset diff --git a/interface/src/Application.h b/interface/src/Application.h index c2918f1add..1ed24683ae 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -37,6 +37,8 @@ class QGLWidget; class QKeyEvent; class QMainWindow; class QMouseEvent; +class QNetworkAccessManager; +class QSettings; class QWheelEvent; class Agent; @@ -70,6 +72,8 @@ public: Environment* getEnvironment() { return &_environment; } bool shouldEchoAudio() { return _echoAudioMode->isChecked(); } + QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } + /*! @fn getSettingBool @brief A function for getting boolean settings from the settings file. @@ -127,6 +131,8 @@ private slots: void idle(); void terminate(); + void editPreferences(); + void pair(); void setHead(bool head); @@ -227,6 +233,9 @@ private: QAction* _fullScreenMode; // whether we are in full screen mode QAction* _frustumRenderModeAction; + QNetworkAccessManager* _networkAccessManager; + QSettings* _settings; + SerialInterface _serialPort; bool _displayLevels; diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index c7561d3986..475fc0bc59 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -89,6 +89,8 @@ public: glm::quat getOrientation () const; glm::quat getWorldAlignedOrientation() const; + AvatarVoxelSystem* getVoxels() { return &_voxels; } + // Set what driving keys are being pressed to control thrust levels void setDriveKeys(int key, bool val) { _driveKeys[key] = val; }; bool getDriveKeys(int key) { return _driveKeys[key]; }; diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 9e441c148c..5fdf974f71 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -7,6 +7,12 @@ #include +#include +#include + +#include + +#include "Application.h" #include "Avatar.h" #include "AvatarVoxelSystem.h" #include "renderer/ProgramObject.h" @@ -17,7 +23,7 @@ const int BONE_ELEMENTS_PER_VOXEL = BONE_ELEMENTS_PER_VERTEX * VERTICES_PER_VOXE AvatarVoxelSystem::AvatarVoxelSystem(Avatar* avatar) : VoxelSystem(AVATAR_TREE_SCALE, MAX_VOXELS_PER_AVATAR), - _avatar(avatar) { + _avatar(avatar), _voxelReply(0) { } AvatarVoxelSystem::~AvatarVoxelSystem() { @@ -52,16 +58,6 @@ void AvatarVoxelSystem::init() { glBindBuffer(GL_ARRAY_BUFFER, _vboBoneWeightsID); 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) { return; @@ -75,8 +71,25 @@ void AvatarVoxelSystem::init() { _boneWeightsLocation = _skinProgram->attributeLocation("boneWeights"); } -void AvatarVoxelSystem::render(bool texture) { - VoxelSystem::render(texture); +void AvatarVoxelSystem::removeOutOfView() { + // no-op for now +} + +void AvatarVoxelSystem::loadVoxelsFromURL(const QUrl& url) { + // cancel any current download + if (_voxelReply != 0) { + delete _voxelReply; + } + + killLocalVoxels(); + + // load the URL data asynchronously + if (!url.isValid()) { + return; + } + _voxelReply = Application::getInstance()->getNetworkAccessManager()->get(QNetworkRequest(url)); + connect(_voxelReply, SIGNAL(readyRead()), SLOT(readVoxelDataFromReply())); + connect(_voxelReply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleVoxelReplyError())); } void AvatarVoxelSystem::updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, @@ -168,6 +181,25 @@ void AvatarVoxelSystem::removeScaleAndReleaseProgram(bool texture) { _skinProgram->disableAttributeArray(_boneWeightsLocation); } +void AvatarVoxelSystem::readVoxelDataFromReply() { + // for now, just wait until we have the full business + if (!_voxelReply->isFinished()) { + return; + } + QByteArray entirety = _voxelReply->readAll(); + _voxelReply->deleteLater(); + _voxelReply = 0; + _tree->readBitstreamToTree((unsigned char*)entirety.data(), entirety.size(), WANT_COLOR, NO_EXISTS_BITS); + setupNewVoxelsForDrawing(); +} + +void AvatarVoxelSystem::handleVoxelReplyError() { + printLog("%s\n", _voxelReply->errorString().toAscii().constData()); + + _voxelReply->deleteLater(); + _voxelReply = 0; +} + class IndexDistance { public: IndexDistance(GLubyte index = 0, float distance = FLT_MAX) : index(index), distance(distance) { } @@ -183,7 +215,10 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo // 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].absoluteBindPosePosition); + AvatarJointID parent = _avatar->getSkeleton().joint[i].parent; + float distance = glm::length(computeVectorFromPointToSegment(jointVertex, + _avatar->getSkeleton().joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, + _avatar->getSkeleton().joint[i].absoluteBindPosePosition)); for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { if (distance < nearest[j].distance) { // move the rest of the indices down diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index e3a80c3817..edeeadb17c 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -9,22 +9,32 @@ #ifndef __interface__AvatarVoxelSystem__ #define __interface__AvatarVoxelSystem__ +#include + #include "VoxelSystem.h" const int BONE_ELEMENTS_PER_VERTEX = 4; typedef GLubyte BoneIndices[BONE_ELEMENTS_PER_VERTEX]; +class QNetworkReply; +class QUrl; + class Avatar; -class AvatarVoxelSystem : public VoxelSystem { +class AvatarVoxelSystem : public QObject, public VoxelSystem { + Q_OBJECT + public: - + AvatarVoxelSystem(Avatar* avatar); virtual ~AvatarVoxelSystem(); virtual void init(); - virtual void render(bool texture); + virtual void removeOutOfView(); + + void loadVoxelsFromURL(const QUrl& url); + protected: virtual void updateNodeInArrays(glBufferIndex nodeIndex, const glm::vec3& startVertex, @@ -33,6 +43,11 @@ protected: virtual void updateVBOSegment(glBufferIndex segmentStart, glBufferIndex segmentEnd); virtual void applyScaleAndBindProgram(bool texture); virtual void removeScaleAndReleaseProgram(bool texture); + +private slots: + + void readVoxelDataFromReply(); + void handleVoxelReplyError(); private: @@ -48,6 +63,8 @@ private: GLuint _vboBoneIndicesID; GLuint _vboBoneWeightsID; + QNetworkReply* _voxelReply; + static ProgramObject* _skinProgram; static int _boneMatricesLocation; static int _boneIndicesLocation; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 136cb6f619..a694b4032d 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -49,7 +49,7 @@ void Skeleton::initialize() { joint[ AVATAR_JOINT_RIGHT_HEEL ].parent = AVATAR_JOINT_RIGHT_KNEE; joint[ AVATAR_JOINT_RIGHT_TOES ].parent = AVATAR_JOINT_RIGHT_HEEL; - // specify the default pose position + // specify the bind pose position joint[ AVATAR_JOINT_PELVIS ].bindPosePosition = glm::vec3( 0.0, 0.0, 0.0 ); joint[ AVATAR_JOINT_TORSO ].bindPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); joint[ AVATAR_JOINT_CHEST ].bindPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); @@ -58,29 +58,58 @@ void Skeleton::initialize() { joint[ AVATAR_JOINT_LEFT_COLLAR ].bindPosePosition = glm::vec3( -0.06, 0.04, 0.01 ); joint[ AVATAR_JOINT_LEFT_SHOULDER ].bindPosePosition = glm::vec3( -0.05, 0.0, 0.01 ); - joint[ AVATAR_JOINT_LEFT_ELBOW ].bindPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); - joint[ AVATAR_JOINT_LEFT_WRIST ].bindPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); - joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].bindPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + joint[ AVATAR_JOINT_LEFT_ELBOW ].bindPosePosition = glm::vec3( -0.16, 0.0, 0.0 ); + joint[ AVATAR_JOINT_LEFT_WRIST ].bindPosePosition = glm::vec3( -0.12, 0.0, 0.0 ); + joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].bindPosePosition = glm::vec3( -0.1, 0.0, 0.0 ); joint[ AVATAR_JOINT_RIGHT_COLLAR ].bindPosePosition = glm::vec3( 0.06, 0.04, 0.01 ); joint[ AVATAR_JOINT_RIGHT_SHOULDER ].bindPosePosition = glm::vec3( 0.05, 0.0, 0.01 ); - joint[ AVATAR_JOINT_RIGHT_ELBOW ].bindPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); - joint[ AVATAR_JOINT_RIGHT_WRIST ].bindPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); - joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].bindPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_ELBOW ].bindPosePosition = glm::vec3( 0.16, 0.0, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_WRIST ].bindPosePosition = glm::vec3( 0.12, 0.0, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].bindPosePosition = glm::vec3( 0.1, 0.0, 0.0 ); joint[ AVATAR_JOINT_LEFT_HIP ].bindPosePosition = glm::vec3( -0.05, 0.0, 0.02 ); - joint[ AVATAR_JOINT_LEFT_KNEE ].bindPosePosition = glm::vec3( 0.01, -0.25, -0.03 ); - joint[ AVATAR_JOINT_LEFT_HEEL ].bindPosePosition = glm::vec3( 0.01, -0.22, 0.08 ); - joint[ AVATAR_JOINT_LEFT_TOES ].bindPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); + joint[ AVATAR_JOINT_LEFT_KNEE ].bindPosePosition = glm::vec3( 0.00, -0.25, 0.00 ); + joint[ AVATAR_JOINT_LEFT_HEEL ].bindPosePosition = glm::vec3( 0.00, -0.23, 0.00 ); + joint[ AVATAR_JOINT_LEFT_TOES ].bindPosePosition = glm::vec3( 0.00, 0.00, -0.06 ); joint[ AVATAR_JOINT_RIGHT_HIP ].bindPosePosition = glm::vec3( 0.05, 0.0, 0.02 ); - joint[ AVATAR_JOINT_RIGHT_KNEE ].bindPosePosition = glm::vec3( -0.01, -0.25, -0.03 ); - joint[ AVATAR_JOINT_RIGHT_HEEL ].bindPosePosition = glm::vec3( -0.01, -0.22, 0.08 ); - joint[ AVATAR_JOINT_RIGHT_TOES ].bindPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); + joint[ AVATAR_JOINT_RIGHT_KNEE ].bindPosePosition = glm::vec3( 0.00, -0.25, 0.00 ); + joint[ AVATAR_JOINT_RIGHT_HEEL ].bindPosePosition = glm::vec3( 0.00, -0.23, 0.00 ); + joint[ AVATAR_JOINT_RIGHT_TOES ].bindPosePosition = glm::vec3( 0.00, 0.00, -0.06 ); + + // specify the default pose position + joint[ AVATAR_JOINT_PELVIS ].defaultPosePosition = glm::vec3( 0.0, 0.0, 0.0 ); + joint[ AVATAR_JOINT_TORSO ].defaultPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); + joint[ AVATAR_JOINT_CHEST ].defaultPosePosition = glm::vec3( 0.0, 0.09, -0.01 ); + joint[ AVATAR_JOINT_NECK_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.14, 0.01 ); + joint[ AVATAR_JOINT_HEAD_BASE ].defaultPosePosition = glm::vec3( 0.0, 0.04, 0.00 ); + + joint[ AVATAR_JOINT_LEFT_COLLAR ].defaultPosePosition = glm::vec3( -0.06, 0.04, 0.01 ); + joint[ AVATAR_JOINT_LEFT_SHOULDER ].defaultPosePosition = glm::vec3( -0.05, 0.0, 0.01 ); + joint[ AVATAR_JOINT_LEFT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); + joint[ AVATAR_JOINT_LEFT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); + joint[ AVATAR_JOINT_LEFT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + + joint[ AVATAR_JOINT_RIGHT_COLLAR ].defaultPosePosition = glm::vec3( 0.06, 0.04, 0.01 ); + joint[ AVATAR_JOINT_RIGHT_SHOULDER ].defaultPosePosition = glm::vec3( 0.05, 0.0, 0.01 ); + joint[ AVATAR_JOINT_RIGHT_ELBOW ].defaultPosePosition = glm::vec3( 0.0, -0.16, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_WRIST ].defaultPosePosition = glm::vec3( 0.0, -0.117, 0.0 ); + joint[ AVATAR_JOINT_RIGHT_FINGERTIPS ].defaultPosePosition = glm::vec3( 0.0, -0.1, 0.0 ); + + joint[ AVATAR_JOINT_LEFT_HIP ].defaultPosePosition = glm::vec3( -0.05, 0.0, 0.02 ); + joint[ AVATAR_JOINT_LEFT_KNEE ].defaultPosePosition = glm::vec3( 0.01, -0.25, -0.03 ); + joint[ AVATAR_JOINT_LEFT_HEEL ].defaultPosePosition = glm::vec3( 0.01, -0.22, 0.08 ); + joint[ AVATAR_JOINT_LEFT_TOES ].defaultPosePosition = glm::vec3( 0.00, -0.03, -0.05 ); + + joint[ AVATAR_JOINT_RIGHT_HIP ].defaultPosePosition = glm::vec3( 0.05, 0.0, 0.02 ); + joint[ AVATAR_JOINT_RIGHT_KNEE ].defaultPosePosition = glm::vec3( -0.01, -0.25, -0.03 ); + 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, absolute positions/rotations + // calculate bone length, absolute bind positions/rotations for (int b = 0; b < NUM_AVATAR_JOINTS; b++) { - joint[b].length = glm::length(joint[b].bindPosePosition); + joint[b].length = glm::length(joint[b].defaultPosePosition); if (joint[b].parent == AVATAR_JOINT_NULL) { joint[b].absoluteBindPosePosition = joint[b].bindPosePosition; @@ -106,7 +135,7 @@ void Skeleton::update(float deltaTime, const glm::quat& orientation, glm::vec3 p joint[b].position = joint[ joint[b].parent ].position; } - glm::vec3 rotatedJointVector = joint[b].rotation * joint[b].bindPosePosition; + glm::vec3 rotatedJointVector = joint[b].rotation * joint[b].defaultPosePosition; joint[b].position += rotatedJointVector; } } diff --git a/interface/src/Skeleton.h b/interface/src/Skeleton.h index 78405b39ac..dd55c5fa68 100644 --- a/interface/src/Skeleton.h +++ b/interface/src/Skeleton.h @@ -61,6 +61,7 @@ public: { 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 default pose glm::vec3 bindPosePosition; // the parent relative position when the avatar is in the "T-pose" glm::vec3 absoluteBindPosePosition; // the absolute position when the avatar is in the "T-pose" glm::quat absoluteBindPoseRotation; // the absolute rotation when the avatar is in the "T-pose" diff --git a/interface/src/VoxelSystem.h b/interface/src/VoxelSystem.h index 3a46e19517..e310fdaf7c 100644 --- a/interface/src/VoxelSystem.h +++ b/interface/src/VoxelSystem.h @@ -33,7 +33,7 @@ public: virtual void init(); void simulate(float deltaTime) { }; - virtual void render(bool texture); + void render(bool texture); unsigned long getVoxelsUpdated() const {return _voxelsUpdated;}; unsigned long getVoxelsRendered() const {return _voxelsInReadArrays;}; @@ -59,7 +59,7 @@ public: void setRenderPipelineWarnings(bool on) { _renderWarningsOn = on; }; bool getRenderPipelineWarnings() const { return _renderWarningsOn; }; - void removeOutOfView(); + virtual void removeOutOfView(); bool hasViewChanged(); bool isViewChanging(); From 90a53bc5181ad246035fd812fc1d8cb95ca43a04 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 10:40:08 -0700 Subject: [PATCH 50/73] Only bind vertices within an adjustable radius. --- interface/src/Avatar.cpp | 2 +- interface/src/AvatarVoxelSystem.cpp | 29 ++++++++++++++++++++++------- interface/src/Skeleton.cpp | 3 ++- interface/src/Skeleton.h | 1 + 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index fa193d3a70..a563ff6fff 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -957,7 +957,7 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; // update rotation - if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < 0.1f) { + if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < EPSILON) { _bodyBall[b].rotation = orientation * _skeleton.joint[b].absoluteBindPoseRotation; } else { _bodyBall[b].rotation = rotationBetween(jointDirection, springVector) * orientation; diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 5fdf974f71..2500c9b2d4 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -202,7 +202,7 @@ void AvatarVoxelSystem::handleVoxelReplyError() { class IndexDistance { public: - IndexDistance(GLubyte index = 0, float distance = FLT_MAX) : index(index), distance(distance) { } + IndexDistance(GLubyte index = AVATAR_JOINT_PELVIS, float distance = FLT_MAX) : index(index), distance(distance) { } GLubyte index; float distance; @@ -214,11 +214,15 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo // 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]; + const Skeleton& skeleton = _avatar->getSkeleton(); for (int i = 0; i < NUM_AVATAR_JOINTS; i++) { - AvatarJointID parent = _avatar->getSkeleton().joint[i].parent; + AvatarJointID parent = skeleton.joint[i].parent; float distance = glm::length(computeVectorFromPointToSegment(jointVertex, - _avatar->getSkeleton().joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, - _avatar->getSkeleton().joint[i].absoluteBindPosePosition)); + skeleton.joint[parent == AVATAR_JOINT_NULL ? i : parent].absoluteBindPosePosition, + skeleton.joint[i].absoluteBindPosePosition)); + if (distance > skeleton.joint[i].bindRadius) { + continue; + } for (int j = 0; j < BONE_ELEMENTS_PER_VERTEX; j++) { if (distance < nearest[j].distance) { // move the rest of the indices down @@ -235,11 +239,22 @@ void AvatarVoxelSystem::computeBoneIndicesAndWeights(const glm::vec3& vertex, Bo float totalWeight = 0.0f; for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { indices[i] = nearest[i].index; - weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); - totalWeight += weights[i]; + if (nearest[i].distance != FLT_MAX) { + weights[i] = 1.0f / glm::max(nearest[i].distance, EPSILON); + totalWeight += weights[i]; + + } else { + weights[i] = 0.0f; + } } - // normalize the weights + // if it's not attached to anything, consider it attached to the hip + if (totalWeight == 0.0f) { + weights[0] = 1.0f; + return; + } + + // ortherwise, normalize the weights for (int i = 0; i < BONE_ELEMENTS_PER_VERTEX; i++) { weights[i] /= totalWeight; } diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index a694b4032d..f22953a6c1 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -18,9 +18,10 @@ void Skeleton::initialize() { for (int b=0; b Date: Tue, 4 Jun 2013 10:57:53 -0700 Subject: [PATCH 51/73] change injector from cube to sphere --- audio-mixer/src/main.cpp | 138 +++++++++++++++--------- injector/src/main.cpp | 18 ++-- libraries/audio/src/AudioInjector.cpp | 20 ++-- libraries/audio/src/AudioInjector.h | 6 +- libraries/audio/src/AudioRingBuffer.cpp | 8 +- libraries/audio/src/AudioRingBuffer.h | 4 +- 6 files changed, 117 insertions(+), 77 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 982ebc526c..d94a1d59d6 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -160,68 +160,100 @@ int main(int argc, const char* argv[]) { int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex()); int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex()); + bool insideSphericalInjector = false; + if (distanceCoefficients[lowAgentIndex][highAgentIndex] == 0) { - float distanceToAgent = sqrtf(powf(agentPosition.x - otherAgentPosition.x, 2) + - powf(agentPosition.y - otherAgentPosition.y, 2) + - powf(agentPosition.z - otherAgentPosition.z, 2)); + float distanceToAgent = glm::distance(agentPosition, otherAgentPosition); + + float minCoefficient = 1.0f; + + if (otherAgentBuffer->getRadius() == 0 || distanceToAgent > otherAgentBuffer->getRadius()) { + // this is either not a spherical source, or the listener is outside the sphere + + if (otherAgentBuffer->getRadius() > 0) { + // this is a spherical source - the distance used for the coefficient + // needs to be the closest point on the boundary to the source + + // multiply the normalized vector between the center of the sphere + // and the position of the source by the radius to get the + // closest point on the boundary of the sphere to the source + glm::vec3 difference = agentPosition - otherAgentPosition; + glm::vec3 closestPoint = glm::normalize(difference) * otherAgentBuffer->getRadius(); + + // for the other calculations the agent position is the closest point on the sphere + otherAgentPosition = closestPoint; + + // ovveride the distance to the agent with the distance to the point on the + // boundary of the sphere + distanceToAgent = glm::distance(agentPosition, closestPoint); + } + + // calculate the distance coefficient using the distance to this agent + minCoefficient = std::min(1.0f, + powf(0.3, (logf(DISTANCE_SCALE * distanceToAgent) / + logf(2.5)) - 1)); + } else { + insideSphericalInjector = true; + } + - float minCoefficient = std::min(1.0f, - powf(0.3, - (logf(DISTANCE_SCALE * distanceToAgent) / logf(2.5)) - - 1)); distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient; } - - // get the angle from the right-angle triangle - float triangleAngle = atan2f(fabsf(agentPosition.z - otherAgentPosition.z), - fabsf(agentPosition.x - otherAgentPosition.x)) * (180 / M_PI); - float absoluteAngleToSource = 0; - bearingRelativeAngleToSource = 0; - - // find the angle we need for calculation based on the orientation of the triangle - if (otherAgentPosition.x > agentPosition.x) { - if (otherAgentPosition.z > agentPosition.z) { - absoluteAngleToSource = -90 + triangleAngle; + if (!insideSphericalInjector) { + // off-axis attenuation and spatialization of audio is not performed + // if the listener is inside a spherical injector + + // get the angle from the right-angle triangle + float triangleAngle = atan2f(fabsf(agentPosition.z - otherAgentPosition.z), + fabsf(agentPosition.x - otherAgentPosition.x)) * (180 / M_PI); + float absoluteAngleToSource = 0; + bearingRelativeAngleToSource = 0; + + // find the angle we need for calculation based on the orientation of the triangle + if (otherAgentPosition.x > agentPosition.x) { + if (otherAgentPosition.z > agentPosition.z) { + absoluteAngleToSource = -90 + triangleAngle; + } else { + absoluteAngleToSource = -90 - triangleAngle; + } } else { - absoluteAngleToSource = -90 - triangleAngle; + if (otherAgentPosition.z > agentPosition.z) { + absoluteAngleToSource = 90 - triangleAngle; + } else { + absoluteAngleToSource = 90 + triangleAngle; + } } - } else { - if (otherAgentPosition.z > agentPosition.z) { - absoluteAngleToSource = 90 - triangleAngle; - } else { - absoluteAngleToSource = 90 + triangleAngle; + + bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing(); + + if (bearingRelativeAngleToSource > 180) { + bearingRelativeAngleToSource -= 360; + } else if (bearingRelativeAngleToSource < -180) { + bearingRelativeAngleToSource += 360; } + + float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing(); + + if (angleOfDelivery > 180) { + angleOfDelivery -= 360; + } else if (angleOfDelivery < -180) { + angleOfDelivery += 360; + } + + float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); + + attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex] + * otherAgentBuffer->getAttenuationRatio() + * offAxisCoefficient; + + bearingRelativeAngleToSource *= (M_PI / 180); + + float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); + numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; + weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } - - bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing(); - - if (bearingRelativeAngleToSource > 180) { - bearingRelativeAngleToSource -= 360; - } else if (bearingRelativeAngleToSource < -180) { - bearingRelativeAngleToSource += 360; - } - - float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing(); - - if (angleOfDelivery > 180) { - angleOfDelivery -= 360; - } else if (angleOfDelivery < -180) { - angleOfDelivery += 360; - } - - float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + - (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); - - attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex] - * otherAgentBuffer->getAttenuationRatio() - * offAxisCoefficient; - - bearingRelativeAngleToSource *= (M_PI / 180); - - float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); - numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; - weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 512882c374..18fa1f27df 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -36,25 +36,25 @@ const char *allowedParameters = ":rb::t::c::a::f::d::s:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; unsigned char volume = DEFAULT_INJECTOR_VOLUME; float triggerDistance = 0.0f; -float cubeSideLength = 0.0f; +float radius = 0.0f; void usage(void) { std::cout << "High Fidelity - Interface audio injector" << std::endl; - std::cout << " -r Random sleep mode. If not specified will default to constant loop." << 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 << " -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 << " -s FLOAT Length of side of cube audio source. If not specified injected audio is point source" << std::endl; + std::cout << " -r FLOAT Radius for spherical source. If not specified injected audio is point source" << std::endl; } bool processParameters(int parameterCount, char* parameterData[]) { int p; while ((p = getopt(parameterCount, parameterData, allowedParameters)) != -1) { switch (p) { - case 'r': + case 's': ::loopAudio = false; std::cout << "[DEBUG] Random sleep mode enabled" << std::endl; break; @@ -94,9 +94,9 @@ bool processParameters(int parameterCount, char* parameterData[]) { ::triggerDistance = atof(optarg); std::cout << "[DEBUG] Trigger distance: " << optarg << std::endl; break; - case 's': - ::cubeSideLength = atof(optarg); - std::cout << "[DEBUG] Cube side length: " << optarg << std::endl; + case 'r': + ::radius = atof(optarg); + std::cout << "[DEBUG] Injector radius: " << optarg << std::endl; break; default: usage(); @@ -170,9 +170,9 @@ int main(int argc, char* argv[]) { injector.setBearing(*(::floatArguments + 3)); injector.setVolume(::volume); - if (::cubeSideLength > 0) { + if (::radius > 0) { // if we were passed a cube side length, give that to the injector - injector.setCubeSideLength(::cubeSideLength); + injector.setRadius(::radius); } // register the callback for agent data creation diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index e1de27ef6d..fbb55a84c3 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -19,7 +19,7 @@ const int MAX_INJECTOR_VOLUME = 0xFF; AudioInjector::AudioInjector(const char* filename) : _position(), - _cubeSideLength(0.0f), + _radius(0.0f), _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), @@ -49,7 +49,7 @@ AudioInjector::AudioInjector(const char* filename) : AudioInjector::AudioInjector(int maxNumSamples) : _numTotalSamples(maxNumSamples), _position(), - _cubeSideLength(0.0f), + _radius(0.0f), _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), @@ -72,13 +72,19 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination timeval startTime; // calculate the number of bytes required for additional data - int leadingBytes = sizeof(PACKET_HEADER) + sizeof(_streamIdentifier) + int leadingBytes = sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND) + sizeof(_streamIdentifier) + sizeof(_position) + sizeof(_bearing) + sizeof(_volume); + + if (_radius > 0) { + // we'll need 4 extra bytes if the cube side length is being sent as well + leadingBytes += sizeof(_radius); + } + unsigned char dataPacket[BUFFER_LENGTH_BYTES + leadingBytes]; dataPacket[0] = PACKET_HEADER_INJECT_AUDIO; // add the correct command for point source or cube of sound - dataPacket[1] = (_cubeSideLength > 0) ? INJECT_AUDIO_AT_CUBE_COMMAND : INJECT_AUDIO_AT_POINT_COMMAND; + dataPacket[1] = (_radius > 0) ? INJECT_AUDIO_AT_CUBE_COMMAND : INJECT_AUDIO_AT_POINT_COMMAND; unsigned char *currentPacketPtr = dataPacket + sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND); // copy the identifier for this injector @@ -88,11 +94,11 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination memcpy(currentPacketPtr, &_position, sizeof(_position)); currentPacketPtr += sizeof(_position); - if (_cubeSideLength > 0) { + if (_radius > 0) { // if we have a cube half height we need to send it here // this tells the mixer how much volume the injected audio will occupy - memcpy(currentPacketPtr, &_cubeSideLength, sizeof(_cubeSideLength)); - currentPacketPtr += sizeof(_cubeSideLength); + memcpy(currentPacketPtr, &_radius, sizeof(_radius)); + currentPacketPtr += sizeof(_radius); } *currentPacketPtr = _volume; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index 0269931568..d8b907d368 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -39,8 +39,8 @@ public: float getBearing() const { return _bearing; } void setBearing(float bearing) { _bearing = bearing; } - float getCubeSideLength() const { return _cubeSideLength; } - void setCubeSideLength(float cubeSideLength) { _cubeSideLength = cubeSideLength; } + float getRadius() const { return _radius; } + void setRadius(float radius) { _radius = radius; } void addSample(const int16_t sample); void addSamples(int16_t* sampleBuffer, int numSamples); @@ -49,7 +49,7 @@ private: int16_t* _audioSampleArray; int _numTotalSamples; glm::vec3 _position; - float _cubeSideLength; + float _radius; float _bearing; unsigned char _volume; int _indexOfNextSlot; diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index 39cdc43287..fe93ece47f 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -17,7 +17,7 @@ AudioRingBuffer::AudioRingBuffer(int ringSamples, int bufferSamples) : AgentData(NULL), _ringBufferLengthSamples(ringSamples), _bufferLengthSamples(bufferSamples), - _cubeSideLength(0.0f), + _radius(0.0f), _endOfLastWrite(NULL), _started(false), _shouldBeAddedToMix(false), @@ -53,13 +53,13 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { } memcpy(&_position, dataBuffer, sizeof(_position)); - dataBuffer += (sizeof(_position)); + dataBuffer += sizeof(_position); if (sourceBuffer[0] == PACKET_HEADER_INJECT_AUDIO && sourceBuffer[1] == INJECT_AUDIO_AT_CUBE_COMMAND) { // this is audio that needs to be injected as a volume (cube) // parse out the cubeHalfHeight sent by the client - memcpy(&_cubeSideLength, dataBuffer, sizeof(_cubeSideLength)); - dataBuffer += (sizeof(_cubeSideLength)); + memcpy(&_radius, dataBuffer, sizeof(_radius)); + dataBuffer += sizeof(_radius); } unsigned int attenuationByte = *(dataBuffer++); diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index 3554e13d46..0a2b8ed7db 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -26,6 +26,8 @@ public: ~AudioRingBuffer(); int parseData(unsigned char* sourceBuffer, int numBytes); + + float getRadius() const { return _radius; } int16_t* getNextOutput() const { return _nextOutput; } void setNextOutput(int16_t* nextOutput) { _nextOutput = nextOutput; } @@ -56,7 +58,7 @@ private: int _ringBufferLengthSamples; int _bufferLengthSamples; glm::vec3 _position; - float _cubeSideLength; + float _radius; float _attenuationRatio; float _bearing; int16_t* _nextOutput; From eaaeedab68f04da5af5323f1f1bfa88aebbb3b75 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 11:24:07 -0700 Subject: [PATCH 52/73] refactor calculations for audio --- audio-mixer/src/main.cpp | 109 ++++++++++++++++++--------------------- injector/src/main.cpp | 2 +- 2 files changed, 50 insertions(+), 61 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index d94a1d59d6..bc75ac5698 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -17,6 +17,7 @@ #include #include +#include #include #include #include @@ -55,7 +56,6 @@ const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SA const long MAX_SAMPLE_VALUE = std::numeric_limits::max(); const long MIN_SAMPLE_VALUE = std::numeric_limits::min(); -const float DISTANCE_SCALE = 2.5f; const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5; const int PHASE_DELAY_AT_90 = 20; @@ -128,10 +128,6 @@ int main(int argc, const char* argv[]) { } } - int numAgents = agentList->size(); - float distanceCoefficients[numAgents][numAgents]; - memset(distanceCoefficients, 0, sizeof(distanceCoefficients)); - for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getType() == AGENT_TYPE_AVATAR) { AudioRingBuffer* agentRingBuffer = (AudioRingBuffer*) agent->getLinkedData(); @@ -146,69 +142,60 @@ int main(int argc, const char* argv[]) { if (otherAgentBuffer->shouldBeAddedToMix()) { float bearingRelativeAngleToSource = 0.f; - float attenuationCoefficient = 1.f; + float attenuationCoefficient = 1.0f; int numSamplesDelay = 0; - float weakChannelAmplitudeRatio = 1.f; + float weakChannelAmplitudeRatio = 1.0f; if (otherAgent != agent) { glm::vec3 agentPosition = agentRingBuffer->getPosition(); glm::vec3 otherAgentPosition = otherAgentBuffer->getPosition(); - // calculate the distance to the other agent + float distanceSquareToSource = glm::distance2(agentPosition, otherAgentPosition); - // use the distance to the other agent to calculate the change in volume for this frame - int lowAgentIndex = std::min(agent.getAgentIndex(), otherAgent.getAgentIndex()); - int highAgentIndex = std::max(agent.getAgentIndex(), otherAgent.getAgentIndex()); + float distanceCoefficient = 1.0f; + float offAxisCoefficient = 1.0f; - bool insideSphericalInjector = false; - - if (distanceCoefficients[lowAgentIndex][highAgentIndex] == 0) { - float distanceToAgent = glm::distance(agentPosition, otherAgentPosition); + if (otherAgentBuffer->getRadius() == 0 + || (distanceSquareToSource > (otherAgentBuffer->getRadius() + * otherAgentBuffer->getRadius()))) { + // this is either not a spherical source, or the listener is outside the sphere - float minCoefficient = 1.0f; - - if (otherAgentBuffer->getRadius() == 0 || distanceToAgent > otherAgentBuffer->getRadius()) { - // this is either not a spherical source, or the listener is outside the sphere + if (otherAgentBuffer->getRadius() > 0) { + // this is a spherical source - the distance used for the coefficient + // needs to be the closest point on the boundary to the source - if (otherAgentBuffer->getRadius() > 0) { - // this is a spherical source - the distance used for the coefficient - // needs to be the closest point on the boundary to the source - - // multiply the normalized vector between the center of the sphere - // and the position of the source by the radius to get the - // closest point on the boundary of the sphere to the source - glm::vec3 difference = agentPosition - otherAgentPosition; - glm::vec3 closestPoint = glm::normalize(difference) * otherAgentBuffer->getRadius(); - - // for the other calculations the agent position is the closest point on the sphere - otherAgentPosition = closestPoint; - - // ovveride the distance to the agent with the distance to the point on the - // boundary of the sphere - distanceToAgent = glm::distance(agentPosition, closestPoint); - } + // multiply the normalized vector between the center of the sphere + // and the position of the source by the radius to get the + // closest point on the boundary of the sphere to the source + glm::vec3 difference = agentPosition - otherAgentPosition; + glm::vec3 closestPoint = glm::normalize(difference) * otherAgentBuffer->getRadius(); - // calculate the distance coefficient using the distance to this agent - minCoefficient = std::min(1.0f, - powf(0.3, (logf(DISTANCE_SCALE * distanceToAgent) / - logf(2.5)) - 1)); - } else { - insideSphericalInjector = true; + // for the other calculations the agent position is the closest point on the sphere + otherAgentPosition = closestPoint; + + // ovveride the distance to the agent with the distance to the point on the + // boundary of the sphere + distanceSquareToSource = glm::distance2(agentPosition, closestPoint); } + + const float DISTANCE_SCALE = 2.5f; + const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f; + const float DISTANCE_LOG_BASE = 2.5f; + const float DISTANCE_SCALE_LOG = logf(DISTANCE_SCALE) / logf(DISTANCE_LOG_BASE); - - distanceCoefficients[lowAgentIndex][highAgentIndex] = minCoefficient; - } - - if (!insideSphericalInjector) { - // off-axis attenuation and spatialization of audio is not performed - // if the listener is inside a spherical injector + // calculate the distance coefficient using the distance to this agent + distanceCoefficient = powf(GEOMETRIC_AMPLITUDE_SCALAR, + DISTANCE_SCALE_LOG + + (logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1); + distanceCoefficient = std::min(1.0f, distanceCoefficient); + + // off-axis attenuation and spatialization of audio + // not performed if listener is inside spherical injector // get the angle from the right-angle triangle float triangleAngle = atan2f(fabsf(agentPosition.z - otherAgentPosition.z), fabsf(agentPosition.x - otherAgentPosition.x)) * (180 / M_PI); float absoluteAngleToSource = 0; - bearingRelativeAngleToSource = 0; // find the angle we need for calculation based on the orientation of the triangle if (otherAgentPosition.x > agentPosition.x) { @@ -225,6 +212,8 @@ int main(int argc, const char* argv[]) { } } + printf("AAS: %f, AB: %f\n", absoluteAngleToSource, agentRingBuffer->getBearing()); + bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing(); if (bearingRelativeAngleToSource > 180) { @@ -241,19 +230,19 @@ int main(int argc, const char* argv[]) { angleOfDelivery += 360; } - float offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + - (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); - - attenuationCoefficient = distanceCoefficients[lowAgentIndex][highAgentIndex] - * otherAgentBuffer->getAttenuationRatio() - * offAxisCoefficient; + offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); bearingRelativeAngleToSource *= (M_PI / 180); - - float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); - numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; - weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } + + attenuationCoefficient = distanceCoefficient + * otherAgentBuffer->getAttenuationRatio() + * offAxisCoefficient; + + float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); + numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; + weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 18fa1f27df..8d4ec11859 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -32,7 +32,7 @@ bool loopAudio = true; float sleepIntervalMin = 1.00; float sleepIntervalMax = 2.00; char *sourceAudioFile = NULL; -const char *allowedParameters = ":rb::t::c::a::f::d::s:"; +const char *allowedParameters = ":sb::t::c::a::f::d::r:"; float floatArguments[4] = {0.0f, 0.0f, 0.0f, 0.0f}; unsigned char volume = DEFAULT_INJECTOR_VOLUME; float triggerDistance = 0.0f; From a12353e112081c78c439c7cb5dbb68b3e40d1416 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 11:38:47 -0700 Subject: [PATCH 53/73] hopefully fix unix build buster --- libraries/avatars/src/AvatarData.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index d728ff53d8..0fc1104a0a 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -10,6 +10,7 @@ #define __hifi__AvatarData__ #include +#include #include #include From 7ea9bb4b92a5c6394c110b20235bfa27972a810a Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 12:11:59 -0700 Subject: [PATCH 54/73] remove debug line from previous commit --- 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 bc75ac5698..cac9a1eace 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -212,8 +212,6 @@ int main(int argc, const char* argv[]) { } } - printf("AAS: %f, AB: %f\n", absoluteAngleToSource, agentRingBuffer->getBearing()); - bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing(); if (bearingRelativeAngleToSource > 180) { From 0f70c9c06bbffd2206d5fe1b9b7f2e80c9c379a2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 12:52:09 -0700 Subject: [PATCH 55/73] send full quaternion orientation instead of just bearing to audio-mixer --- interface/src/Audio.cpp | 29 +++++++++-------------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/interface/src/Audio.cpp b/interface/src/Audio.cpp index bf100d733b..16ac7fa4f7 100644 --- a/interface/src/Audio.cpp +++ b/interface/src/Audio.cpp @@ -133,7 +133,10 @@ int audioCallback (const void* inputBuffer, Agent* audioMixer = agentList->soloAgentOfType(AGENT_TYPE_AUDIO_MIXER); if (audioMixer) { - int leadingBytes = 2 + (sizeof(float) * 4); + glm::vec3 headPosition = interfaceAvatar->getHeadJointPosition(); + glm::quat headOrientation = interfaceAvatar->getHead().getOrientation(); + + int leadingBytes = 1 + sizeof(headPosition) + sizeof(headOrientation) + sizeof(unsigned char); // we need the amount of bytes in the buffer + 1 for type // + 12 for 3 floats for position + float for bearing + 1 attenuation byte @@ -143,29 +146,15 @@ int audioCallback (const void* inputBuffer, unsigned char *currentPacketPtr = dataPacket + 1; // memcpy the three float positions - memcpy(currentPacketPtr, &interfaceAvatar->getHeadJointPosition(), sizeof(float) * 3); - currentPacketPtr += (sizeof(float) * 3); + memcpy(currentPacketPtr, &headPosition, sizeof(headPosition)); + currentPacketPtr += (sizeof(headPosition)); // tell the mixer not to add additional attenuation to our source *(currentPacketPtr++) = 255; - // memcpy the corrected render yaw - float correctedYaw = fmodf(-1 * interfaceAvatar->getAbsoluteHeadYaw(), 360); - - if (correctedYaw > 180) { - correctedYaw -= 360; - } else if (correctedYaw < -180) { - correctedYaw += 360; - } - - if (Application::getInstance()->shouldEchoAudio()) { - correctedYaw = correctedYaw > 0 - ? correctedYaw + AGENT_LOOPBACK_MODIFIER - : correctedYaw - AGENT_LOOPBACK_MODIFIER; - } - - memcpy(currentPacketPtr, &correctedYaw, sizeof(float)); - currentPacketPtr += sizeof(float); + // memcpy our orientation + memcpy(currentPacketPtr, &headOrientation, sizeof(headOrientation)); + currentPacketPtr += sizeof(headOrientation); // copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet memcpy(currentPacketPtr, inputLeft, BUFFER_LENGTH_BYTES); From cd79339670d39691a872a69e96e6fdbf152dc92d Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 15:18:05 -0700 Subject: [PATCH 56/73] rework audio-mixer to use orientations sent by clients --- audio-mixer/src/main.cpp | 88 +++++++++---------------- libraries/audio/src/AudioRingBuffer.cpp | 17 ++--- libraries/audio/src/AudioRingBuffer.h | 6 +- 3 files changed, 41 insertions(+), 70 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index cac9a1eace..df38876c31 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -18,6 +18,7 @@ #include #include +#include #include #include #include @@ -147,14 +148,16 @@ int main(int argc, const char* argv[]) { float weakChannelAmplitudeRatio = 1.0f; if (otherAgent != agent) { - glm::vec3 agentPosition = agentRingBuffer->getPosition(); - glm::vec3 otherAgentPosition = otherAgentBuffer->getPosition(); - - float distanceSquareToSource = glm::distance2(agentPosition, otherAgentPosition); - + glm::vec3 listenerPosition = agentRingBuffer->getPosition(); + glm::vec3 relativePosition = otherAgentBuffer->getPosition() - agentRingBuffer->getPosition(); + glm::vec3 rotatedSourcePosition = glm::inverse(agentRingBuffer->getOrientation()) + * relativePosition; + + float distanceSquareToSource = glm::dot(relativePosition, relativePosition); + float distanceCoefficient = 1.0f; float offAxisCoefficient = 1.0f; - + if (otherAgentBuffer->getRadius() == 0 || (distanceSquareToSource > (otherAgentBuffer->getRadius() * otherAgentBuffer->getRadius()))) { @@ -167,17 +170,17 @@ int main(int argc, const char* argv[]) { // multiply the normalized vector between the center of the sphere // and the position of the source by the radius to get the // closest point on the boundary of the sphere to the source - glm::vec3 difference = agentPosition - otherAgentPosition; - glm::vec3 closestPoint = glm::normalize(difference) * otherAgentBuffer->getRadius(); + glm::vec3 closestPoint = glm::normalize(relativePosition) * otherAgentBuffer->getRadius(); + // for the other calculations the agent position is the closest point on the sphere - otherAgentPosition = closestPoint; - + rotatedSourcePosition = closestPoint; + // ovveride the distance to the agent with the distance to the point on the // boundary of the sphere - distanceSquareToSource = glm::distance2(agentPosition, closestPoint); + distanceSquareToSource = glm::distance2(listenerPosition, closestPoint); } - + const float DISTANCE_SCALE = 2.5f; const float GEOMETRIC_AMPLITUDE_SCALAR = 0.3f; const float DISTANCE_LOG_BASE = 2.5f; @@ -188,67 +191,40 @@ int main(int argc, const char* argv[]) { DISTANCE_SCALE_LOG + (logf(distanceSquareToSource) / logf(DISTANCE_LOG_BASE)) - 1); distanceCoefficient = std::min(1.0f, distanceCoefficient); - + // off-axis attenuation and spatialization of audio // not performed if listener is inside spherical injector - // get the angle from the right-angle triangle - float triangleAngle = atan2f(fabsf(agentPosition.z - otherAgentPosition.z), - fabsf(agentPosition.x - otherAgentPosition.x)) * (180 / M_PI); - float absoluteAngleToSource = 0; + // calculate the angle from the source to the listener + bearingRelativeAngleToSource = glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f), + glm::normalize(rotatedSourcePosition), + glm::vec3(0.0f, 1.0f, 0.0f)); - // find the angle we need for calculation based on the orientation of the triangle - if (otherAgentPosition.x > agentPosition.x) { - if (otherAgentPosition.z > agentPosition.z) { - absoluteAngleToSource = -90 + triangleAngle; - } else { - absoluteAngleToSource = -90 - triangleAngle; - } - } else { - if (otherAgentPosition.z > agentPosition.z) { - absoluteAngleToSource = 90 - triangleAngle; - } else { - absoluteAngleToSource = 90 + triangleAngle; - } - } - - bearingRelativeAngleToSource = absoluteAngleToSource - agentRingBuffer->getBearing(); - - if (bearingRelativeAngleToSource > 180) { - bearingRelativeAngleToSource -= 360; - } else if (bearingRelativeAngleToSource < -180) { - bearingRelativeAngleToSource += 360; - } - - float angleOfDelivery = absoluteAngleToSource - otherAgentBuffer->getBearing(); - - if (angleOfDelivery > 180) { - angleOfDelivery -= 360; - } else if (angleOfDelivery < -180) { - angleOfDelivery += 360; - } + // calculate the angle delivery + glm::vec3 rotatedListenerPosition = glm::inverse(otherAgentBuffer->getOrientation()) + * relativePosition; + float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, 1.0f), + glm::normalize(rotatedListenerPosition)); offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); - bearingRelativeAngleToSource *= (M_PI / 180); + float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource))); + numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; + weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } attenuationCoefficient = distanceCoefficient * otherAgentBuffer->getAttenuationRatio() * offAxisCoefficient; - - float sinRatio = fabsf(sinf(bearingRelativeAngleToSource)); - numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; - weakChannelAmplitudeRatio = 1 - (PHASE_AMPLITUDE_RATIO_AT_90 * sinRatio); } int16_t* goodChannel = bearingRelativeAngleToSource > 0.0f - ? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL - : clientSamples; - int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f ? clientSamples : clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL; + int16_t* delayedChannel = bearingRelativeAngleToSource > 0.0f + ? clientSamples + BUFFER_LENGTH_SAMPLES_PER_CHANNEL + : clientSamples; int16_t* delaySamplePointer = otherAgentBuffer->getNextOutput() == otherAgentBuffer->getBuffer() ? otherAgentBuffer->getBuffer() + RING_BUFFER_SAMPLES - numSamplesDelay @@ -307,7 +283,7 @@ int main(int argc, const char* argv[]) { agentList->updateAgentWithData(agentAddress, packetData, receivedBytes); - if (std::isnan(((AudioRingBuffer *)avatarAgent->getLinkedData())->getBearing())) { + if (std::isnan(((AudioRingBuffer *)avatarAgent->getLinkedData())->getOrientation().x)) { // kill off this agent - temporary solution to mixer crash on mac sleep avatarAgent->setAlive(false); } diff --git a/libraries/audio/src/AudioRingBuffer.cpp b/libraries/audio/src/AudioRingBuffer.cpp index fe93ece47f..6bdb7f9aae 100644 --- a/libraries/audio/src/AudioRingBuffer.cpp +++ b/libraries/audio/src/AudioRingBuffer.cpp @@ -65,23 +65,16 @@ int AudioRingBuffer::parseData(unsigned char* sourceBuffer, int numBytes) { unsigned int attenuationByte = *(dataBuffer++); _attenuationRatio = attenuationByte / 255.0f; - memcpy(&_bearing, dataBuffer, sizeof(float)); - dataBuffer += sizeof(_bearing); + memcpy(&_orientation, dataBuffer, sizeof(_orientation)); + dataBuffer += sizeof(_orientation); - // if this agent sent us a NaN bearing then don't consider this good audio and bail - if (std::isnan(_bearing)) { + // if this agent sent us a NaN for first float in orientation then don't consider this good audio and bail + if (std::isnan(_orientation.x)) { _endOfLastWrite = _nextOutput = _buffer; _started = false; return 0; - } else if (_bearing > 180 || _bearing < -180) { - // we were passed an invalid bearing because this agent wants loopback (pressed the H key) - _shouldLoopbackForAgent = true; - - // correct the bearing - _bearing = _bearing > 0 - ? _bearing - AGENT_LOOPBACK_MODIFIER - : _bearing + AGENT_LOOPBACK_MODIFIER; } else { + // currently no possiblity for loopback, need to add once quaternion audio is working again _shouldLoopbackForAgent = false; } } diff --git a/libraries/audio/src/AudioRingBuffer.h b/libraries/audio/src/AudioRingBuffer.h index 0a2b8ed7db..a280be0a7c 100644 --- a/libraries/audio/src/AudioRingBuffer.h +++ b/libraries/audio/src/AudioRingBuffer.h @@ -12,6 +12,7 @@ #include #include +#include #include "AgentData.h" @@ -44,8 +45,9 @@ public: void setShouldBeAddedToMix(bool shouldBeAddedToMix) { _shouldBeAddedToMix = shouldBeAddedToMix; } const glm::vec3& getPosition() const { return _position; } + const glm::quat& getOrientation() const { return _orientation; } float getAttenuationRatio() const { return _attenuationRatio; } - float getBearing() const { return _bearing; } + bool shouldLoopbackForAgent() const { return _shouldLoopbackForAgent; } const unsigned char* getStreamIdentifier() const { return _streamIdentifier; } @@ -58,9 +60,9 @@ private: int _ringBufferLengthSamples; int _bufferLengthSamples; glm::vec3 _position; + glm::quat _orientation; float _radius; float _attenuationRatio; - float _bearing; int16_t* _nextOutput; int16_t* _endOfLastWrite; int16_t* _buffer; From 7d3d8f8b43929237a5cd73b1cc3142a3adbd5e39 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 15:31:11 -0700 Subject: [PATCH 57/73] rewrite the AudioInjector to send an orientation quaternion instead of bearing --- audio-mixer/src/main.cpp | 2 +- interface/src/Application.cpp | 4 ++-- libraries/audio/src/AudioInjector.cpp | 14 +++++++------- libraries/audio/src/AudioInjector.h | 6 +++--- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index df38876c31..4c1ffab1f0 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -207,7 +207,7 @@ int main(int argc, const char* argv[]) { glm::normalize(rotatedListenerPosition)); offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION - + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (fabsf(angleOfDelivery) / 90.0f)); + + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / 90.0f)); float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource))); numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6ef5d0d5bc..3e493b4882 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -2353,7 +2353,7 @@ void Application::maybeEditVoxelUnderCursor() { AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(11025); voxelInjector->setPosition(glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z)); //_myAvatar.getPosition() - voxelInjector->setBearing(-1 * _myAvatar.getAbsoluteHeadYaw()); +// voxelInjector->setBearing(-1 * _myAvatar.getAbsoluteHeadYaw()); voxelInjector->setVolume (16 * pow (_mouseVoxel.s, 2) / .0000001); //255 is max, and also default value /* for (int i = 0; i @@ -2416,7 +2416,7 @@ void Application::deleteVoxelUnderCursor() { sendVoxelEditMessage(PACKET_HEADER_ERASE_VOXEL, _mouseVoxel); AudioInjector* voxelInjector = AudioInjectionManager::injectorWithCapacity(5000); voxelInjector->setPosition(glm::vec3(_mouseVoxel.x, _mouseVoxel.y, _mouseVoxel.z)); - voxelInjector->setBearing(0); //straight down the z axis +// voxelInjector->setBearing(0); //straight down the z axis voxelInjector->setVolume (255); //255 is max, and also default value diff --git a/libraries/audio/src/AudioInjector.cpp b/libraries/audio/src/AudioInjector.cpp index fbb55a84c3..11dec28dfc 100644 --- a/libraries/audio/src/AudioInjector.cpp +++ b/libraries/audio/src/AudioInjector.cpp @@ -18,9 +18,9 @@ const int MAX_INJECTOR_VOLUME = 0xFF; AudioInjector::AudioInjector(const char* filename) : - _position(), + _position(0.0f, 0.0f, 0.0f), + _orientation(0.0f, 0.0f, 0.0f, 0.0f), _radius(0.0f), - _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), _isInjectingAudio(false) @@ -48,9 +48,9 @@ AudioInjector::AudioInjector(const char* filename) : AudioInjector::AudioInjector(int maxNumSamples) : _numTotalSamples(maxNumSamples), - _position(), + _position(0.0f, 0.0f, 0.0f), + _orientation(0.0f, 0.0f, 0.0f, 0.0f), _radius(0.0f), - _bearing(0), _volume(MAX_INJECTOR_VOLUME), _indexOfNextSlot(0), _isInjectingAudio(false) @@ -73,7 +73,7 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination // calculate the number of bytes required for additional data int leadingBytes = sizeof(PACKET_HEADER) + sizeof(INJECT_AUDIO_AT_POINT_COMMAND) + sizeof(_streamIdentifier) - + sizeof(_position) + sizeof(_bearing) + sizeof(_volume); + + sizeof(_position) + sizeof(_orientation) + sizeof(_volume); if (_radius > 0) { // we'll need 4 extra bytes if the cube side length is being sent as well @@ -104,8 +104,8 @@ void AudioInjector::injectAudio(UDPSocket* injectorSocket, sockaddr* destination *currentPacketPtr = _volume; currentPacketPtr++; - memcpy(currentPacketPtr, &_bearing, sizeof(_bearing)); - currentPacketPtr += sizeof(_bearing); + memcpy(currentPacketPtr, &_orientation, sizeof(_orientation)); + currentPacketPtr += sizeof(_orientation); gettimeofday(&startTime, NULL); int nextFrame = 0; diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index d8b907d368..f0a7d1f3f8 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -36,8 +36,8 @@ public: const glm::vec3& getPosition() const { return _position; } void setPosition(const glm::vec3& position) { _position = position; } - float getBearing() const { return _bearing; } - void setBearing(float bearing) { _bearing = bearing; } + const glm::quat& getOrientation() const { return _orientation; } + void setOperation(const glm::quat& orientation) { _orientation = orientation; } float getRadius() const { return _radius; } void setRadius(float radius) { _radius = radius; } @@ -49,8 +49,8 @@ private: int16_t* _audioSampleArray; int _numTotalSamples; glm::vec3 _position; + glm::quat _orientation; float _radius; - float _bearing; unsigned char _volume; int _indexOfNextSlot; bool _isInjectingAudio; From b856af505a688d1c9a1eea8d5afedc6683c02794 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 15:52:39 -0700 Subject: [PATCH 58/73] Adjusted default bind radius, spring vector threshold. --- interface/src/Avatar.cpp | 3 ++- interface/src/Skeleton.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 61112c3403..4a3e8db2bc 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -1076,7 +1076,8 @@ void Avatar::updateBodyBalls(float deltaTime) { _bodyBall[b].position += _bodyBall[b].velocity * deltaTime; // update rotation - if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < EPSILON) { + const float SMALL_SPRING_LENGTH = 0.001f; // too-small springs can change direction rapidly + if (_skeleton.joint[b].parent == AVATAR_JOINT_NULL || length < SMALL_SPRING_LENGTH) { _bodyBall[b].rotation = orientation * _skeleton.joint[_bodyBall[b].parentJoint].absoluteBindPoseRotation; } else { _bodyBall[b].rotation = rotationBetween(jointDirection, springVector) * orientation; diff --git a/interface/src/Skeleton.cpp b/interface/src/Skeleton.cpp index 13092648a3..b3720c8869 100644 --- a/interface/src/Skeleton.cpp +++ b/interface/src/Skeleton.cpp @@ -21,7 +21,7 @@ void Skeleton::initialize() { joint[b].defaultPosePosition = glm::vec3(0.0, 0.0, 0.0); joint[b].rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f); joint[b].length = 0.0; - joint[b].bindRadius = 1.0f / 16; + joint[b].bindRadius = 1.0f / 8; } // specify the parental hierarchy From 93b50f44f5a8ee791bebbba87a0f19aa1bd6a0c4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 15:59:07 -0700 Subject: [PATCH 59/73] Add a reasonable minimum size for the URL field. --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8aba8a613a..6f898ecae7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1158,6 +1158,7 @@ void Application::editPreferences() { layout->addLayout(form, 1); QLineEdit* avatarURL = new QLineEdit(_settings->value("avatarURL").toString()); + avatarURL->setMinimumWidth(400); form->addRow("Avatar URL:", avatarURL); QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); From bfad6c8f6139931d7cde190287277169a3f35d18 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 16:10:20 -0700 Subject: [PATCH 60/73] fix orientation setter in AudioInjector header --- libraries/audio/src/AudioInjector.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioInjector.h b/libraries/audio/src/AudioInjector.h index f0a7d1f3f8..42bc1f1a2c 100644 --- a/libraries/audio/src/AudioInjector.h +++ b/libraries/audio/src/AudioInjector.h @@ -37,7 +37,7 @@ public: void setPosition(const glm::vec3& position) { _position = position; } const glm::quat& getOrientation() const { return _orientation; } - void setOperation(const glm::quat& orientation) { _orientation = orientation; } + void setOrientation(const glm::quat& orientation) { _orientation = orientation; } float getRadius() const { return _radius; } void setRadius(float radius) { _radius = radius; } From 4b208e16783bbe079835c7dc54a6d7439e1971e1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 16:11:11 -0700 Subject: [PATCH 61/73] project source position onto XZ plane of listener --- 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 4c1ffab1f0..3c9d60b50f 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -196,6 +196,11 @@ int main(int argc, const char* argv[]) { // not performed if listener is inside spherical injector // calculate the angle from the source to the listener + + // project the rotated source position vector onto the XZ plane + rotatedSourcePosition.y = 0.0f; + + // produce an oriented angle about the y-axis bearingRelativeAngleToSource = glm::orientedAngle(glm::vec3(0.0f, 0.0f, -1.0f), glm::normalize(rotatedSourcePosition), glm::vec3(0.0f, 1.0f, 0.0f)); @@ -203,6 +208,7 @@ int main(int argc, const char* argv[]) { // calculate the angle delivery glm::vec3 rotatedListenerPosition = glm::inverse(otherAgentBuffer->getOrientation()) * relativePosition; + float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, 1.0f), glm::normalize(rotatedListenerPosition)); From e07c55ec43ac4484a6937d08d0f1412226d2ea09 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 16:11:35 -0700 Subject: [PATCH 62/73] set injector orientation from bearing passed as command line argument --- injector/src/main.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index 8d4ec11859..d8f0df9b1f 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -167,7 +167,7 @@ int main(int argc, char* argv[]) { agentList->startSilentAgentRemovalThread(); injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2])); - injector.setBearing(*(::floatArguments + 3)); + injector.setOrientation(glm::quat(glm::vec3(0.0f, *(::floatArguments + 3), 0.0f))); injector.setVolume(::volume); if (::radius > 0) { From c5d3365f3e9cb4f5a72c20af08dcc625e35f6ac1 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 16:44:01 -0700 Subject: [PATCH 63/73] correct spatialization and off-axis attenuation for a spherical source --- audio-mixer/src/main.cpp | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 3c9d60b50f..6b4790f2ad 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -150,8 +150,8 @@ int main(int argc, const char* argv[]) { if (otherAgent != agent) { glm::vec3 listenerPosition = agentRingBuffer->getPosition(); glm::vec3 relativePosition = otherAgentBuffer->getPosition() - agentRingBuffer->getPosition(); - glm::vec3 rotatedSourcePosition = glm::inverse(agentRingBuffer->getOrientation()) - * relativePosition; + glm::quat inverseOrientation = glm::inverse(agentRingBuffer->getOrientation()); + glm::vec3 rotatedSourcePosition = inverseOrientation * relativePosition; float distanceSquareToSource = glm::dot(relativePosition, relativePosition); @@ -171,14 +171,25 @@ int main(int argc, const char* argv[]) { // and the position of the source by the radius to get the // closest point on the boundary of the sphere to the source - glm::vec3 closestPoint = glm::normalize(relativePosition) * otherAgentBuffer->getRadius(); + glm::vec3 closestPoint = glm::normalize(-relativePosition) * otherAgentBuffer->getRadius(); // for the other calculations the agent position is the closest point on the sphere - rotatedSourcePosition = closestPoint; + rotatedSourcePosition = inverseOrientation * -closestPoint; // ovveride the distance to the agent with the distance to the point on the // boundary of the sphere distanceSquareToSource = glm::distance2(listenerPosition, closestPoint); + + } else { + // calculate the angle delivery + glm::vec3 rotatedListenerPosition = glm::inverse(otherAgentBuffer->getOrientation()) + * relativePosition; + + float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, 1.0f), + glm::normalize(rotatedListenerPosition)); + + offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / 90.0f)); } const float DISTANCE_SCALE = 2.5f; @@ -205,15 +216,6 @@ int main(int argc, const char* argv[]) { glm::normalize(rotatedSourcePosition), glm::vec3(0.0f, 1.0f, 0.0f)); - // calculate the angle delivery - glm::vec3 rotatedListenerPosition = glm::inverse(otherAgentBuffer->getOrientation()) - * relativePosition; - - float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, 1.0f), - glm::normalize(rotatedListenerPosition)); - - offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION - + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / 90.0f)); float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource))); numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; From fa9b897025d4dfbb94d14834693caae9e38a86c7 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 17:00:55 -0700 Subject: [PATCH 64/73] move mixer related constants above related part of mix --- audio-mixer/src/main.cpp | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 6b4790f2ad..023f5db371 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -57,12 +57,6 @@ const float BUFFER_SEND_INTERVAL_USECS = (BUFFER_LENGTH_SAMPLES_PER_CHANNEL / SA const long MAX_SAMPLE_VALUE = std::numeric_limits::max(); const long MIN_SAMPLE_VALUE = std::numeric_limits::min(); -const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5; -const int PHASE_DELAY_AT_90 = 20; - -const float MAX_OFF_AXIS_ATTENUATION = 0.2f; -const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; - void plateauAdditionOfSamples(int16_t &mixSample, int16_t sampleToAdd) { long sumSample = sampleToAdd + mixSample; @@ -171,14 +165,14 @@ int main(int argc, const char* argv[]) { // and the position of the source by the radius to get the // closest point on the boundary of the sphere to the source - glm::vec3 closestPoint = glm::normalize(-relativePosition) * otherAgentBuffer->getRadius(); + glm::vec3 closestPoint = glm::normalize(relativePosition) * otherAgentBuffer->getRadius(); // for the other calculations the agent position is the closest point on the sphere - rotatedSourcePosition = inverseOrientation * -closestPoint; + rotatedSourcePosition = inverseOrientation * closestPoint; // ovveride the distance to the agent with the distance to the point on the // boundary of the sphere - distanceSquareToSource = glm::distance2(listenerPosition, closestPoint); + distanceSquareToSource = glm::distance2(listenerPosition, -closestPoint); } else { // calculate the angle delivery @@ -188,6 +182,9 @@ int main(int argc, const char* argv[]) { float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, 1.0f), glm::normalize(rotatedListenerPosition)); + const float MAX_OFF_AXIS_ATTENUATION = 0.2f; + const float OFF_AXIS_ATTENUATION_FORMULA_STEP = (1 - MAX_OFF_AXIS_ATTENUATION) / 2.0f; + offAxisCoefficient = MAX_OFF_AXIS_ATTENUATION + (OFF_AXIS_ATTENUATION_FORMULA_STEP * (angleOfDelivery / 90.0f)); } @@ -216,6 +213,8 @@ int main(int argc, const char* argv[]) { glm::normalize(rotatedSourcePosition), glm::vec3(0.0f, 1.0f, 0.0f)); + const float PHASE_AMPLITUDE_RATIO_AT_90 = 0.5; + const int PHASE_DELAY_AT_90 = 20; float sinRatio = fabsf(sinf(glm::radians(bearingRelativeAngleToSource))); numSamplesDelay = PHASE_DELAY_AT_90 * sinRatio; From 7f486c351f862c02d050d633c907dcf9c0a8ca6f Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 17:15:58 -0700 Subject: [PATCH 65/73] correct direction of angle of delivery --- audio-mixer/src/main.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audio-mixer/src/main.cpp b/audio-mixer/src/main.cpp index 023f5db371..43c6b3ac50 100644 --- a/audio-mixer/src/main.cpp +++ b/audio-mixer/src/main.cpp @@ -177,9 +177,9 @@ int main(int argc, const char* argv[]) { } else { // calculate the angle delivery glm::vec3 rotatedListenerPosition = glm::inverse(otherAgentBuffer->getOrientation()) - * relativePosition; + * relativePosition; - float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, 1.0f), + float angleOfDelivery = glm::angle(glm::vec3(0.0f, 0.0f, -1.0f), glm::normalize(rotatedListenerPosition)); const float MAX_OFF_AXIS_ATTENUATION = 0.2f; From ad377e6256bde405aea9f93e98b37b5f495c6fe4 Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 17:25:04 -0700 Subject: [PATCH 66/73] We can't initialize avatars from the network thread; they need access to the OpenGL context. --- interface/src/Application.cpp | 10 +++++++--- interface/src/Avatar.cpp | 2 ++ interface/src/Avatar.h | 2 ++ 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 6f898ecae7..2aae2353c5 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1083,6 +1083,9 @@ void Application::idle() { for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getLinkedData() != NULL) { Avatar *avatar = (Avatar *)agent->getLinkedData(); + if (!avatar->isInitialized()) { + avatar->init(); + } avatar->simulate(deltaTime, NULL); avatar->setMouseRay(mouseRayOrigin, mouseRayDirection); } @@ -2061,6 +2064,9 @@ void Application::displaySide(Camera& whichCamera) { for (AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { if (agent->getLinkedData() != NULL && agent->getType() == AGENT_TYPE_AVATAR) { Avatar *avatar = (Avatar *)agent->getLinkedData(); + if (!avatar->isInitialized()) { + avatar->init(); + } avatar->render(false); } } @@ -2534,9 +2540,7 @@ QAction* Application::checkedVoxelModeAction() const { void Application::attachNewHeadToAgent(Agent* newAgent) { if (newAgent->getLinkedData() == NULL) { - Avatar* newAvatar = new Avatar(newAgent); - newAvatar->init(); - newAgent->setLinkedData(newAvatar); + newAgent->setLinkedData(new Avatar(newAgent)); } } diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 4a3e8db2bc..7b2c94d152 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -62,6 +62,7 @@ float chatMessageHeight = 0.20; Avatar::Avatar(Agent* owningAgent) : AvatarData(owningAgent), + _initialized(false), _head(this), _ballSpringsInitialized(false), _TEST_bigSphereRadius(0.5f), @@ -266,6 +267,7 @@ Avatar::~Avatar() { void Avatar::init() { _voxels.init(); + _initialized = true; } void Avatar::reset() { diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 20c431ef82..e27462ee49 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -100,6 +100,7 @@ public: void setOrientation (const glm::quat& orientation); //getters + bool isInitialized () const { return _initialized;} const Skeleton& getSkeleton () const { return _skeleton;} float getHeadYawRate () const { return _head.yawRate;} float getBodyYaw () const { return _bodyYaw;} @@ -156,6 +157,7 @@ private: float touchForce; // a scalar determining the amount that the cursor (or hand) is penetrating the ball }; + bool _initialized; Head _head; Skeleton _skeleton; bool _ballSpringsInitialized; From 4f2af717f29baed7906ff732c0ac9a887d7560e8 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 17:27:40 -0700 Subject: [PATCH 67/73] Fixed merge issue with new orientation vectors, migrated to common identity names --- interface/src/Avatar.cpp | 16 ++++----- interface/src/Avatar.h | 6 ++-- interface/src/Head.cpp | 47 +++++++++++++-------------- interface/src/Head.h | 6 ++-- interface/src/Util.cpp | 8 +++-- libraries/avatars/src/AvatarData.cpp | 4 +-- libraries/avatars/src/AvatarData.h | 5 --- libraries/voxels/src/ViewFrustum.cpp | 17 +++------- libraries/voxels/src/VoxelConstants.h | 5 +++ 9 files changed, 52 insertions(+), 62 deletions(-) diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index 4a3e8db2bc..dde6bca334 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -427,9 +427,9 @@ void Avatar::simulate(float deltaTime, Transmitter* transmitter) { } glm::quat orientation = getOrientation(); - glm::vec3 front = orientation * AVATAR_FRONT; - glm::vec3 right = orientation * AVATAR_RIGHT; - glm::vec3 up = orientation * AVATAR_UP; + glm::vec3 front = orientation * IDENTITY_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 up = orientation * IDENTITY_UP; // driving the avatar around should only apply if this is my avatar (as opposed to an avatar being driven remotely) const float THRUST_MAG = 600.0f; @@ -649,9 +649,9 @@ void Avatar::updateHandMovementAndTouching(float deltaTime) { glm::quat orientation = getOrientation(); // reset hand and arm positions according to hand movement - glm::vec3 right = orientation * AVATAR_RIGHT; - glm::vec3 up = orientation * AVATAR_UP; - glm::vec3 front = orientation * AVATAR_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 front = orientation * IDENTITY_FRONT; glm::vec3 transformedHandMovement = right * _movedHandOffset.x * 2.0f @@ -1123,14 +1123,14 @@ void Avatar::updateArmIKAndConstraints(float deltaTime) { glm::quat Avatar::computeRotationFromBodyToWorldUp(float proportion) const { glm::quat orientation = getOrientation(); - glm::vec3 currentUp = orientation * AVATAR_UP; + glm::vec3 currentUp = orientation * IDENTITY_UP; float angle = glm::degrees(acosf(glm::clamp(glm::dot(currentUp, _worldUpDirection), -1.0f, 1.0f))); if (angle < EPSILON) { return glm::quat(); } glm::vec3 axis; if (angle > 179.99f) { // 180 degree rotation; must use another axis - axis = orientation * AVATAR_RIGHT; + axis = orientation * IDENTITY_RIGHT; } else { axis = glm::normalize(glm::cross(currentUp, _worldUpDirection)); } diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 20c431ef82..58e7127957 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -106,9 +106,9 @@ public: bool getIsNearInteractingOther () const { return _avatarTouch.getAbleToReachOtherAvatar();} const glm::vec3& getHeadJointPosition () const { return _skeleton.joint[ AVATAR_JOINT_HEAD_BASE ].position;} const glm::vec3& getBallPosition (AvatarJointID j) const { return _bodyBall[j].position;} - glm::vec3 getBodyRightDirection () const { return getOrientation() * AVATAR_RIGHT; } - glm::vec3 getBodyUpDirection () const { return getOrientation() * AVATAR_UP; } - glm::vec3 getBodyFrontDirection () const { return getOrientation() * AVATAR_FRONT; } + glm::vec3 getBodyRightDirection () const { return getOrientation() * IDENTITY_RIGHT; } + glm::vec3 getBodyUpDirection () const { return getOrientation() * IDENTITY_UP; } + glm::vec3 getBodyFrontDirection () const { return getOrientation() * IDENTITY_FRONT; } const glm::vec3& getVelocity () const { return _velocity;} float getSpeed () const { return _speed;} float getHeight () const { return _height;} diff --git a/interface/src/Head.cpp b/interface/src/Head.cpp index 21df933416..98e5c57cb1 100644 --- a/interface/src/Head.cpp +++ b/interface/src/Head.cpp @@ -171,9 +171,9 @@ void Head::determineIfLookingAtSomething() { void Head::calculateGeometry() { //generate orientation directions glm::quat orientation = getOrientation(); - glm::vec3 right = orientation * AVATAR_RIGHT; - glm::vec3 up = orientation * AVATAR_UP; - glm::vec3 front = orientation * AVATAR_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 front = orientation * IDENTITY_FRONT; //calculate the eye positions _leftEyePosition = _position @@ -346,9 +346,9 @@ void Head::renderMouth() { float s = sqrt(_averageLoudness); glm::quat orientation = getOrientation(); - glm::vec3 right = orientation * AVATAR_RIGHT; - glm::vec3 up = orientation * AVATAR_UP; - glm::vec3 front = orientation * AVATAR_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 front = orientation * IDENTITY_FRONT; glm::vec3 r = right * _scale * (0.30f + s * 0.0014f ); glm::vec3 u = up * _scale * (0.05f + s * 0.0040f ); @@ -414,9 +414,9 @@ void Head::renderEyeBrows() { glm::vec3 rightBottom = _leftEyePosition; glm::quat orientation = getOrientation(); - glm::vec3 right = orientation * AVATAR_RIGHT; - glm::vec3 up = orientation * AVATAR_UP; - glm::vec3 front = orientation * AVATAR_FRONT; + glm::vec3 right = orientation * IDENTITY_RIGHT; + glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 front = orientation * IDENTITY_FRONT; glm::vec3 r = right * length; glm::vec3 u = up * height; @@ -501,20 +501,20 @@ void Head::renderEyeBalls() { //rotate the eyeball to aim towards the lookat position glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - _leftEyePosition); // the lookat direction - glm::vec3 rotationAxis = glm::cross(targetLookatAxis, AVATAR_UP); - float angle = 180.0f - angleBetween(targetLookatAxis, AVATAR_UP); + 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 } else { //rotate the eyeball to aim straight ahead - glm::vec3 rotationAxisToHeadFront = glm::cross(front, AVATAR_UP); - float angleToHeadFront = 180.0f - angleBetween(front, AVATAR_UP); + glm::vec3 rotationAxisToHeadFront = glm::cross(front, IDENTITY_UP); + float angleToHeadFront = 180.0f - angleBetween(front, IDENTITY_UP); glRotatef(angleToHeadFront, rotationAxisToHeadFront.x, rotationAxisToHeadFront.y, rotationAxisToHeadFront.z); //set the amount of roll (for correction after previous rotations) - float rollRotation = angleBetween(front, AVATAR_FRONT); - float dot = glm::dot(front, -AVATAR_RIGHT); + float rollRotation = angleBetween(front, IDENTITY_FRONT); + float dot = glm::dot(front, -IDENTITY_RIGHT); if ( dot < 0.0f ) { rollRotation = -rollRotation; } glRotatef(rollRotation, 0.0f, 1.0f, 0.0f); //roll the iris or correct roll about the lookat vector } @@ -545,21 +545,21 @@ void Head::renderEyeBalls() { //rotate the eyeball to aim towards the lookat position glm::vec3 targetLookatAxis = glm::normalize(_lookAtPosition - _rightEyePosition); - glm::vec3 rotationAxis = glm::cross(targetLookatAxis, AVATAR_UP); - float angle = 180.0f - angleBetween(targetLookatAxis, AVATAR_UP); + 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 } else { //rotate the eyeball to aim straight ahead - glm::vec3 rotationAxisToHeadFront = glm::cross(front, AVATAR_UP); - float angleToHeadFront = 180.0f - angleBetween(front, AVATAR_UP); + glm::vec3 rotationAxisToHeadFront = glm::cross(front, IDENTITY_UP); + float angleToHeadFront = 180.0f - angleBetween(front, IDENTITY_UP); glRotatef(angleToHeadFront, rotationAxisToHeadFront.x, rotationAxisToHeadFront.y, rotationAxisToHeadFront.z); //set the amount of roll (for correction after previous rotations) - float rollRotation = angleBetween(front, AVATAR_FRONT); - float dot = glm::dot(front, -AVATAR_RIGHT); + float rollRotation = angleBetween(front, IDENTITY_FRONT); + float dot = glm::dot(front, -IDENTITY_RIGHT); if ( dot < 0.0f ) { rollRotation = -rollRotation; } glRotatef(rollRotation, 0.0f, 1.0f, 0.0f); //roll the iris or correct roll about the lookat vector } @@ -595,9 +595,8 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi void Head::updateHairPhysics(float deltaTime) { glm::quat orientation = getOrientation(); - //glm::vec3 right = orientation * AVATAR_RIGHT; // not used for now - glm::vec3 up = orientation * AVATAR_UP; - glm::vec3 front = orientation * AVATAR_FRONT; + glm::vec3 up = orientation * IDENTITY_UP; + glm::vec3 front = orientation * IDENTITY_FRONT; for (int t = 0; t < NUM_HAIR_TUFTS; t ++) { diff --git a/interface/src/Head.h b/interface/src/Head.h index f49e127caf..66ce07d133 100644 --- a/interface/src/Head.h +++ b/interface/src/Head.h @@ -49,9 +49,9 @@ public: glm::quat getOrientation() const; glm::quat getWorldAlignedOrientation () const; - glm::vec3 getRightDirection() const { return getOrientation() * AVATAR_RIGHT; } - glm::vec3 getUpDirection () const { return getOrientation() * AVATAR_UP; } - glm::vec3 getFrontDirection() const { return getOrientation() * AVATAR_FRONT; } + glm::vec3 getRightDirection() const { return getOrientation() * IDENTITY_RIGHT; } + glm::vec3 getUpDirection () const { return getOrientation() * IDENTITY_UP; } + glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; } const bool getReturnToCenter() const { return _returnHeadToCenter; } // Do you want head to try to return to center (depends on interface detected) float getAverageLoudness() {return _averageLoudness;}; diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 08ec6cf011..d16e6d36bb 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -21,6 +21,8 @@ #include "world.h" #include "Util.h" +#include "VoxelConstants.h" + using namespace std; // no clue which versions are affected... @@ -415,9 +417,9 @@ void renderCircle(glm::vec3 position, float radius, glm::vec3 surfaceNormal, int void renderOrientationDirections(glm::vec3 position, const glm::quat& orientation, float size) { - glm::vec3 pRight = position + orientation * AVATAR_RIGHT * size; - glm::vec3 pUp = position + orientation * AVATAR_UP * size; - glm::vec3 pFront = position + orientation * AVATAR_FRONT * size; + glm::vec3 pRight = position + orientation * IDENTITY_RIGHT * size; + glm::vec3 pUp = position + orientation * IDENTITY_UP * size; + glm::vec3 pFront = position + orientation * IDENTITY_FRONT * size; glColor3f(1.0f, 0.0f, 0.0f); glBegin(GL_LINE_STRIP); diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 6ff6967b61..afb43f75ea 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -205,9 +205,7 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { } glm::vec3 AvatarData::calculateCameraDirection() const { - const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f, 1.0f); - glm::mat4 rotationMatrix = glm::mat4_cast(_cameraOrientation); - glm::vec3 direction = glm::vec3(glm::vec4(IDENTITY_FRONT, 0.0f) * rotationMatrix); + glm::vec3 direction = glm::vec3(_cameraOrientation * glm::vec4(IDENTITY_FRONT, 0.0f)); return direction; } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 0fc1104a0a..cf9845ab4c 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -27,11 +27,6 @@ const int HAND_STATE_START_BIT = 5; // 6th and 7th bits const float MAX_AUDIO_LOUDNESS = 1000.0; // close enough for mouth animation -// this is where the coordinate system is represented -const glm::vec3 AVATAR_RIGHT = glm::vec3(1.0f, 0.0f, 0.0f); -const glm::vec3 AVATAR_UP = glm::vec3(0.0f, 1.0f, 0.0f); -const glm::vec3 AVATAR_FRONT = glm::vec3(0.0f, 0.0f, -1.0f); - enum KeyState { NO_KEY_DOWN = 0, diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index 0f10428b23..b3c890ed07 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -13,6 +13,7 @@ #include #include "ViewFrustum.h" +#include "VoxelConstants.h" #include "SharedUtil.h" #include "Log.h" @@ -38,20 +39,10 @@ ViewFrustum::ViewFrustum() : _nearBottomRight(0,0,0) { } void ViewFrustum::setOrientation(const glm::quat& orientationAsQuaternion) { - glm::quat quat; - quat = quat * orientationAsQuaternion; - - // this is where the coordinate system is represented - const glm::vec3 IDENTITY_RIGHT = glm::vec3(-1.0f, 0.0f, 0.0f); - const glm::vec3 IDENTITY_UP = glm::vec3( 0.0f, 1.0f, 0.0f); - const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f, 1.0f); - - glm::mat4 rotationMatrix = glm::mat4_cast(quat); - _orientation = orientationAsQuaternion; - _right = glm::vec3(glm::vec4(IDENTITY_RIGHT, 0.0f) * rotationMatrix); - _up = glm::vec3(glm::vec4(IDENTITY_UP, 0.0f) * rotationMatrix); - _direction = glm::vec3(glm::vec4(IDENTITY_FRONT, 0.0f) * rotationMatrix); + _right = glm::vec3(orientationAsQuaternion * glm::vec4(IDENTITY_RIGHT, 0.0f)); + _up = glm::vec3(orientationAsQuaternion * glm::vec4(IDENTITY_UP, 0.0f)); + _direction = glm::vec3(orientationAsQuaternion * glm::vec4(IDENTITY_FRONT, 0.0f)); } ///////////////////////////////////////////////////////////////////////////////////// diff --git a/libraries/voxels/src/VoxelConstants.h b/libraries/voxels/src/VoxelConstants.h index 5bf1345d73..d0ae6f538a 100644 --- a/libraries/voxels/src/VoxelConstants.h +++ b/libraries/voxels/src/VoxelConstants.h @@ -15,6 +15,11 @@ #include #include +// this is where the coordinate system is represented +const glm::vec3 IDENTITY_RIGHT = glm::vec3( 1.0f, 0.0f, 0.0f); +const glm::vec3 IDENTITY_UP = glm::vec3( 0.0f, 1.0f, 0.0f); +const glm::vec3 IDENTITY_FRONT = glm::vec3( 0.0f, 0.0f,-1.0f); + const int TREE_SCALE = 128; const int NUMBER_OF_CHILDREN = 8; From 6bf6d5a28ef919127fd79e54fa471b426c6a7c8b Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Tue, 4 Jun 2013 17:29:33 -0700 Subject: [PATCH 68/73] cleanup NULL comparisons in AgentList --- libraries/shared/src/AgentList.cpp | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 2b28ac620d..51ef88794b 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -40,7 +40,7 @@ bool pingUnknownAgentThreadStopFlag = false; AgentList* AgentList::_sharedInstance = NULL; AgentList* AgentList::createInstance(char ownerType, unsigned int socketListenPort) { - if (_sharedInstance == NULL) { + if (!_sharedInstance) { _sharedInstance = new AgentList(ownerType, socketListenPort); } else { printLog("AgentList createInstance called with existing instance.\n"); @@ -50,7 +50,7 @@ AgentList* AgentList::createInstance(char ownerType, unsigned int socketListenPo } AgentList* AgentList::getInstance() { - if (_sharedInstance == NULL) { + if (!_sharedInstance) { printLog("AgentList getInstance called before call to createInstance. Returning NULL pointer.\n"); } @@ -150,14 +150,12 @@ int AgentList::updateAgentWithData(sockaddr *senderAddress, unsigned char *packe int AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int dataBytes) { agent->setLastHeardMicrostamp(usecTimestampNow()); - if (agent->getActiveSocket() != NULL) { + if (agent->getActiveSocket()) { agent->recordBytesReceived(dataBytes); } - if (agent->getLinkedData() == NULL) { - if (linkedDataCreateCallback != NULL) { - linkedDataCreateCallback(agent); - } + if (!agent->getLinkedData() && linkedDataCreateCallback) { + linkedDataCreateCallback(agent); } return agent->getLinkedData()->parseData(packetData, dataBytes); @@ -165,7 +163,7 @@ int AgentList::updateAgentWithData(Agent *agent, unsigned char *packetData, int Agent* AgentList::agentWithAddress(sockaddr *senderAddress) { for(AgentList::iterator agent = begin(); agent != end(); agent++) { - if (agent->getActiveSocket() != NULL && socketMatch(agent->getActiveSocket(), senderAddress)) { + if (agent->getActiveSocket() && socketMatch(agent->getActiveSocket(), senderAddress)) { return &(*agent); } } @@ -216,7 +214,7 @@ int AgentList::processDomainServerList(unsigned char *packetData, size_t dataByt Agent* AgentList::addOrUpdateAgent(sockaddr* publicSocket, sockaddr* localSocket, char agentType, uint16_t agentId) { AgentList::iterator agent = end(); - if (publicSocket != NULL) { + if (publicSocket) { for (agent = begin(); agent != end(); agent++) { if (agent->matches(publicSocket, localSocket, agentType)) { // we already have this agent, stop checking @@ -327,8 +325,7 @@ void *pingUnknownAgents(void *args) { for(AgentList::iterator agent = agentList->begin(); agent != agentList->end(); agent++) { - if (agent->getActiveSocket() == NULL - && (agent->getPublicSocket() != NULL && agent->getLocalSocket() != NULL)) { + if (!agent->getActiveSocket() && agent->getPublicSocket() && agent->getLocalSocket()) { // ping both of the sockets for the agent so we can figure out // which socket we can use agentList->getAgentSocket()->send(agent->getPublicSocket(), &PACKET_HEADER_PING, 1); From 726a0cecf22ef9a4bf3585f495328a7ad36fbac7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 17:40:34 -0700 Subject: [PATCH 69/73] fixed build issue --- libraries/avatars/CMakeLists.txt | 5 ++++- libraries/avatars/src/AvatarData.cpp | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/libraries/avatars/CMakeLists.txt b/libraries/avatars/CMakeLists.txt index b1c593a4a6..207057e244 100644 --- a/libraries/avatars/CMakeLists.txt +++ b/libraries/avatars/CMakeLists.txt @@ -15,4 +15,7 @@ include(${MACRO_DIR}/IncludeGLM.cmake) include_glm(${TARGET_NAME} ${ROOT_DIR}) include(${MACRO_DIR}/LinkHifiLibrary.cmake) -link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) \ No newline at end of file +link_hifi_library(shared ${TARGET_NAME} ${ROOT_DIR}) + +# link in the hifi voxels library +link_hifi_library(voxels ${TARGET_NAME} ${ROOT_DIR}) diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index afb43f75ea..d24754b28f 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -14,6 +14,7 @@ #include #include "AvatarData.h" +#include using namespace std; From b30b64c5b567b10f90ff56a4fee94ea2b784ad7a Mon Sep 17 00:00:00 2001 From: Andrzej Kapolka Date: Tue, 4 Jun 2013 17:44:19 -0700 Subject: [PATCH 70/73] Use downloadProgress rather than isFinished (which worked on files, but didn't on HTTP URLs). --- interface/src/AvatarVoxelSystem.cpp | 6 +++--- interface/src/AvatarVoxelSystem.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index 2500c9b2d4..d1d463561b 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -88,7 +88,7 @@ void AvatarVoxelSystem::loadVoxelsFromURL(const QUrl& url) { return; } _voxelReply = Application::getInstance()->getNetworkAccessManager()->get(QNetworkRequest(url)); - connect(_voxelReply, SIGNAL(readyRead()), SLOT(readVoxelDataFromReply())); + connect(_voxelReply, SIGNAL(downloadProgress(qint64,qint64)), SLOT(handleVoxelDownloadProgress(qint64,qint64))); connect(_voxelReply, SIGNAL(error(QNetworkReply::NetworkError)), SLOT(handleVoxelReplyError())); } @@ -181,9 +181,9 @@ void AvatarVoxelSystem::removeScaleAndReleaseProgram(bool texture) { _skinProgram->disableAttributeArray(_boneWeightsLocation); } -void AvatarVoxelSystem::readVoxelDataFromReply() { +void AvatarVoxelSystem::handleVoxelDownloadProgress(qint64 bytesReceived, qint64 bytesTotal) { // for now, just wait until we have the full business - if (!_voxelReply->isFinished()) { + if (bytesReceived < bytesTotal) { return; } QByteArray entirety = _voxelReply->readAll(); diff --git a/interface/src/AvatarVoxelSystem.h b/interface/src/AvatarVoxelSystem.h index edeeadb17c..3894fd75b9 100644 --- a/interface/src/AvatarVoxelSystem.h +++ b/interface/src/AvatarVoxelSystem.h @@ -46,7 +46,7 @@ protected: private slots: - void readVoxelDataFromReply(); + void handleVoxelDownloadProgress(qint64 bytesReceived, qint64 bytesTotal); void handleVoxelReplyError(); private: From b75bd80de7e2eb22ff04c810a4de3efb0afcadd5 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Tue, 4 Jun 2013 17:54:48 -0700 Subject: [PATCH 71/73] fix build busters --- interface/src/Application.cpp | 11 ++---- interface/src/Application.h | 65 ++--------------------------------- interface/src/Avatar.cpp | 10 ++---- interface/src/Avatar.h | 4 +-- 4 files changed, 7 insertions(+), 83 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index f4b63acc5a..ae233e8d8c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -162,8 +162,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) : _packetCount(0), _packetsPerSecond(0), _bytesPerSecond(0), - _bytesCount(0), - _settings("HighFidelity", "Interface") + _bytesCount(0) { _applicationStartupTime = startup_time; _window->setWindowTitle("Interface"); @@ -975,7 +974,7 @@ void Application::terminate() { if (_autosave) { saveSettings(); - _settings.sync(); + _settings->sync(); } if (_enableNetworkThread) { @@ -1166,8 +1165,6 @@ void Application::chooseVoxelPaintColor() { _window->activateWindow(); } -<<<<<<< HEAD -======= const int MAXIMUM_EDIT_VOXEL_MESSAGE_SIZE = 1500; struct SendVoxelsOperationArgs { unsigned char* newBaseOctCode; @@ -1331,7 +1328,6 @@ void Application::pasteVoxels() { } } ->>>>>>> 82c1ee2062577f614cfde096f08adfc9e83e4f0f void Application::initMenu() { QMenuBar* menuBar = new QMenuBar(); _window->setMenuBar(menuBar); @@ -1450,7 +1446,6 @@ 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); -<<<<<<< HEAD QMenu* settingsMenu = menuBar->addMenu("Settings"); (_settingsAutosave = settingsMenu->addAction("Autosave", this, SLOT(setAutosave(bool))))->setCheckable(true); @@ -1459,11 +1454,9 @@ void Application::initMenu() { settingsMenu->addAction("Save settings", this, SLOT(saveSettings())); settingsMenu->addAction("Import settings", this, SLOT(importSettings())); settingsMenu->addAction("Export settings", this, SLOT(exportSettings())); -======= _networkAccessManager = new QNetworkAccessManager(this); _settings = new QSettings("High Fidelity", "Interface", this); ->>>>>>> 82c1ee2062577f614cfde096f08adfc9e83e4f0f } void Application::updateFrustumRenderModeAction() { diff --git a/interface/src/Application.h b/interface/src/Application.h index df30199e25..446efce8a9 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -71,66 +71,12 @@ public: Camera* getCamera() { return &_myCamera; } ViewFrustum* getViewFrustum() { return &_viewFrustum; } VoxelSystem* getVoxels() { return &_voxels; } - QSettings* getSettings() { return &_settings; } + QSettings* getSettings() { return _settings; } Environment* getEnvironment() { return &_environment; } bool shouldEchoAudio() { return _echoAudioMode->isChecked(); } -<<<<<<< HEAD -======= QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; } - /*! - @fn getSettingBool - @brief A function for getting boolean settings from the settings file. - @param settingName The desired setting to get the value for. - @param boolSetting The referenced variable where the setting will be stored. - @param defaultSetting The default setting to assign to boolSetting if this function fails to find the appropriate setting. Defaults to false. - */ - bool getSetting(const char* setting, bool &value, const bool defaultSetting = false) const; - - /*! - @fn getSettingFloat - @brief A function for getting float settings from the settings file. - @param settingName The desired setting to get the value for. - @param floatSetting The referenced variable where the setting will be stored. - @param defaultSetting The default setting to assign to boolSetting if this function fails to find the appropriate setting. Defaults to 0.0f. - */ - bool getSetting(const char* setting, float &value, const float defaultSetting = 0.0f) const; - - /*! - @fn getSettingVec3 - @brief A function for getting boolean settings from the settings file. - @param settingName The desired setting to get the value for. - @param vecSetting The referenced variable where the setting will be stored. - @param defaultSetting The default setting to assign to boolSetting if this function fails to find the appropriate setting. Defaults to <0.0f, 0.0f, 0.0f> - */ - bool getSetting(const char* setting, glm::vec3 &value, const glm::vec3& defaultSetting = glm::vec3(0.0f, 0.0f, 0.0f)) const; - - /*! - @fn setSettingBool - @brief A function for setting boolean setting values when saving the settings file. - @param settingName The desired setting to populate a value for. - @param boolSetting The value to set. - */ - void setSetting(const char* setting, const bool value); - - /*! - @fn setSettingFloat - @brief A function for setting boolean setting values when saving the settings file. - @param settingName The desired setting to populate a value for. - @param floatSetting The value to set. - */ - void setSetting(const char* setting, const float value); - - /*! - @fn setSettingVec3 - @brief A function for setting boolean setting values when saving the settings file. - @param settingName The desired setting to populate a value for. - @param vecSetting The value to set. - */ - void setSetting(const char* setting, const glm::vec3& value); ->>>>>>> 82c1ee2062577f614cfde096f08adfc9e83e4f0f - private slots: void timer(); @@ -167,22 +113,16 @@ private slots: void decreaseVoxelSize(); void increaseVoxelSize(); void chooseVoxelPaintColor(); -<<<<<<< HEAD - void setAutosave(bool wantsAutosave); void loadSettings(QSettings* set = NULL); void saveSettings(QSettings* set = NULL); void importSettings(); void exportSettings(); - -======= void exportVoxels(); void importVoxels(); void cutVoxels(); void copyVoxels(); void pasteVoxels(); - ->>>>>>> 82c1ee2062577f614cfde096f08adfc9e83e4f0f private: static bool sendVoxelsOperation(VoxelNode* node, void* extraData); @@ -260,7 +200,6 @@ private: QAction* _settingsAutosave; // Whether settings are saved automatically QNetworkAccessManager* _networkAccessManager; - QSettings* _settings; SerialInterface _serialPort; bool _displayLevels; @@ -353,7 +292,7 @@ private: int _bytesPerSecond; int _bytesCount; - QSettings _settings; // Contain Menu settings and Avatar data + QSettings* _settings; // Contain Menu settings and Avatar data bool _autosave; // True if the autosave is on. }; diff --git a/interface/src/Avatar.cpp b/interface/src/Avatar.cpp index cff3c718e1..49b83dd670 100644 --- a/interface/src/Avatar.cpp +++ b/interface/src/Avatar.cpp @@ -1252,7 +1252,6 @@ void Avatar::setHeadFromGyros(glm::vec3* eulerAngles, glm::vec3* angularVelocity } } -<<<<<<< HEAD void Avatar::loadData(QSettings* set) { set->beginGroup("Avatar"); @@ -1265,18 +1264,13 @@ void Avatar::loadData(QSettings* set) { _position.z = set->value("position_z", _position.z).toFloat(); set->endGroup(); -======= +} + 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)); ->>>>>>> 82c1ee2062577f614cfde096f08adfc9e83e4f0f -} - void Avatar::saveData(QSettings* set) { set->beginGroup("Avatar"); diff --git a/interface/src/Avatar.h b/interface/src/Avatar.h index 58fe7a34a7..73ab3ddaba 100644 --- a/interface/src/Avatar.h +++ b/interface/src/Avatar.h @@ -131,18 +131,16 @@ public: void addThrust(glm::vec3 newThrust) { _thrust += newThrust; }; glm::vec3 getThrust() { return _thrust; }; -<<<<<<< HEAD // get/set avatar data void saveData(QSettings* set); void loadData(QSettings* set); -======= + // 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(); ->>>>>>> 82c1ee2062577f614cfde096f08adfc9e83e4f0f private: // privatize copy constructor and assignment operator to avoid copying From 3bce3f7a629d2fc230eec5b8e518177119e308b4 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Wed, 5 Jun 2013 00:53:27 -0700 Subject: [PATCH 72/73] support file:// urls for avitar voxles --- interface/src/AvatarVoxelSystem.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/interface/src/AvatarVoxelSystem.cpp b/interface/src/AvatarVoxelSystem.cpp index d1d463561b..46a4212239 100644 --- a/interface/src/AvatarVoxelSystem.cpp +++ b/interface/src/AvatarVoxelSystem.cpp @@ -83,6 +83,15 @@ void AvatarVoxelSystem::loadVoxelsFromURL(const QUrl& url) { killLocalVoxels(); + // handle "file://" urls... + if (url.isLocalFile()) { + QString pathString = url.path(); + QByteArray pathAsAscii = pathString.toAscii(); + const char* path = pathAsAscii.data(); + readFromSVOFile(path); + return; + } + // load the URL data asynchronously if (!url.isValid()) { return; @@ -186,6 +195,15 @@ void AvatarVoxelSystem::handleVoxelDownloadProgress(qint64 bytesReceived, qint64 if (bytesReceived < bytesTotal) { return; } + + // XXXBHG - I don't know why this can happen, but when I was testing this, I used a dropbox URL + // and it resulted in a case where the bytesTotal == bytesReceived, but the _voxelReply was NULL + // which needless to say caused crashes below. I've added this quick guard to protect against + // this case, but it probably should be investigated. + if (!_voxelReply) { + return; + } + QByteArray entirety = _voxelReply->readAll(); _voxelReply->deleteLater(); _voxelReply = 0; From 351828e8e53ef3bd1bc1f71bc64577942cf91885 Mon Sep 17 00:00:00 2001 From: Stephen Birarda Date: Wed, 5 Jun 2013 09:35:43 -0700 Subject: [PATCH 73/73] some magic number removal in injector main --- injector/src/main.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/injector/src/main.cpp b/injector/src/main.cpp index d8f0df9b1f..41e2bc0bbd 100644 --- a/injector/src/main.cpp +++ b/injector/src/main.cpp @@ -27,6 +27,13 @@ const int AVATAR_MIXER_DATA_SEND_INTERVAL_MSECS = 15; const int DEFAULT_INJECTOR_VOLUME = 0xFF; +enum { + INJECTOR_POSITION_X, + INJECTOR_POSITION_Y, + INJECTOR_POSITION_Z, + INJECTOR_YAW +}; + // Command line parameter defaults bool loopAudio = true; float sleepIntervalMin = 1.00; @@ -166,8 +173,10 @@ int main(int argc, char* argv[]) { // start the agent list thread that will kill off agents when they stop talking agentList->startSilentAgentRemovalThread(); - injector.setPosition(glm::vec3(::floatArguments[0], ::floatArguments[1], ::floatArguments[2])); - injector.setOrientation(glm::quat(glm::vec3(0.0f, *(::floatArguments + 3), 0.0f))); + injector.setPosition(glm::vec3(::floatArguments[INJECTOR_POSITION_X], + ::floatArguments[INJECTOR_POSITION_Y], + ::floatArguments[INJECTOR_POSITION_Z])); + injector.setOrientation(glm::quat(glm::vec3(0.0f, ::floatArguments[INJECTOR_YAW], 0.0f))); injector.setVolume(::volume); if (::radius > 0) {