From 06e98d2c43f2d78b67f54e279fbd2a1a8563728d Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Mon, 27 May 2013 14:10:51 -0700 Subject: [PATCH] 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);