Rave glove demo: Network rave data

Sending glove modes over the network, and fixed ghost-fingers-left-behind issue.
Issues addressed:
  https://basecamp.com/2151194/projects/2058851-avatar/todos/54607028-bug-phantom-leap
  https://basecamp.com/2151194/projects/2058851-avatar/todos/54633674-demo-make
This commit is contained in:
Eric Johnston 2013-08-05 13:25:05 -07:00
parent a6c2683b1a
commit a3a5c3d6d4
7 changed files with 156 additions and 103 deletions

View file

@ -22,9 +22,7 @@ Hand::Hand(Avatar* owningAvatar) :
HandData((AvatarData*)owningAvatar), HandData((AvatarData*)owningAvatar),
_raveGloveClock(0.0f), _raveGloveClock(0.0f),
_raveGloveMode(RAVE_GLOVE_EFFECTS_MODE_THROBBING_COLOR),
_raveGloveInitialized(false), _raveGloveInitialized(false),
_isRaveGloveActive(false),
_owningAvatar(owningAvatar), _owningAvatar(owningAvatar),
_renderAlpha(1.0), _renderAlpha(1.0),
_lookingInMirror(false), _lookingInMirror(false),

View file

@ -23,22 +23,6 @@
class Avatar; class Avatar;
class ProgramObject; class ProgramObject;
enum RaveGloveEffectsMode
{
RAVE_GLOVE_EFFECTS_MODE_NULL = -1,
RAVE_GLOVE_EFFECTS_MODE_THROBBING_COLOR,
RAVE_GLOVE_EFFECTS_MODE_TRAILS,
RAVE_GLOVE_EFFECTS_MODE_FIRE,
RAVE_GLOVE_EFFECTS_MODE_WATER,
RAVE_GLOVE_EFFECTS_MODE_FLASHY,
RAVE_GLOVE_EFFECTS_MODE_BOZO_SPARKLER,
RAVE_GLOVE_EFFECTS_MODE_LONG_SPARKLER,
RAVE_GLOVE_EFFECTS_MODE_SNAKE,
RAVE_GLOVE_EFFECTS_MODE_PULSE,
RAVE_GLOVE_EFFECTS_MODE_THROB,
NUM_RAVE_GLOVE_EFFECTS_MODES
};
class Hand : public HandData { class Hand : public HandData {
public: public:
Hand(Avatar* owningAvatar); Hand(Avatar* owningAvatar);
@ -61,13 +45,11 @@ public:
void setBallColor (glm::vec3 ballColor ) { _ballColor = ballColor; } void setBallColor (glm::vec3 ballColor ) { _ballColor = ballColor; }
void updateRaveGloveParticles(float deltaTime); void updateRaveGloveParticles(float deltaTime);
void updateRaveGloveEmitters(); void updateRaveGloveEmitters();
void setRaveGloveActive(bool active) { _isRaveGloveActive = active; }
void setRaveGloveEffectsMode(QKeyEvent* event); void setRaveGloveEffectsMode(QKeyEvent* event);
// getters // getters
const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;} const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;}
const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;} const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;}
bool isRaveGloveActive() const { return _isRaveGloveActive; }
private: private:
// disallow copies of the Hand, copy of owning Avatar is disallowed too // disallow copies of the Hand, copy of owning Avatar is disallowed too
@ -76,10 +58,8 @@ private:
ParticleSystem _raveGloveParticleSystem; ParticleSystem _raveGloveParticleSystem;
float _raveGloveClock; float _raveGloveClock;
int _raveGloveMode;
bool _raveGloveInitialized; bool _raveGloveInitialized;
int _raveGloveEmitter[NUM_FINGERS]; int _raveGloveEmitter[NUM_FINGERS];
bool _isRaveGloveActive;
Avatar* _owningAvatar; Avatar* _owningAvatar;
float _renderAlpha; float _renderAlpha;
@ -93,7 +73,7 @@ private:
const std::vector<glm::vec3>& handNormals); const std::vector<glm::vec3>& handNormals);
void renderRaveGloveStage(); void renderRaveGloveStage();
void setRaveGloveMode(int mode); virtual void setRaveGloveMode(int mode);
void renderLeapHandSpheres(); void renderLeapHandSpheres();
void renderLeapHands(); void renderLeapHands();
void renderLeapHand(PalmData& hand); void renderLeapHand(PalmData& hand);

View file

@ -129,21 +129,7 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
*destinationBuffer++ = bitItems; *destinationBuffer++ = bitItems;
// leap hand data // leap hand data
std::vector<glm::vec3> fingerVectors; destinationBuffer += _handData->encodeRemoteData(destinationBuffer);
//printf("about to call _handData->encodeRemoteData(fingerVectors);\n");
_handData->encodeRemoteData(fingerVectors);
if (fingerVectors.size() > 255)
fingerVectors.clear(); // safety. We shouldn't ever get over 255, so consider that invalid.
*destinationBuffer++ = (unsigned char)fingerVectors.size();
for (size_t i = 0; i < fingerVectors.size(); ++i) {
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerVectors[i].x, fingerVectorRadix);
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerVectors[i].y, fingerVectorRadix);
destinationBuffer += packFloatScalarToSignedTwoByteFixed(destinationBuffer, fingerVectors[i].z, fingerVectorRadix);
}
// skeleton joints // skeleton joints
*destinationBuffer++ = (unsigned char)_joints.size(); *destinationBuffer++ = (unsigned char)_joints.size();
@ -246,34 +232,10 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
// hand state, stored as a semi-nibble in the bitItems // hand state, stored as a semi-nibble in the bitItems
_handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT); _handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT);
//printf("about to call leap hand data code in AvatarData::parseData...\n");
// leap hand data // leap hand data
if (sourceBuffer - startPosition < numBytes) { if (sourceBuffer - startPosition < numBytes) {
//printf("got inside of 'if (sourceBuffer - startPosition < numBytes)'\n");
// check passed, bytes match // check passed, bytes match
unsigned int numFingerVectors = *sourceBuffer++; sourceBuffer += _handData->decodeRemoteData(sourceBuffer);
//printf("numFingerVectors = %d\n", numFingerVectors);
if (numFingerVectors > 0) {
//printf("ok, we got fingers in AvatarData::parseData\n");
std::vector<glm::vec3> fingerVectors(numFingerVectors);
for (size_t i = 0; i < numFingerVectors; ++i) {
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].x), fingerVectorRadix);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].y), fingerVectorRadix);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(fingerVectors[i].z), fingerVectorRadix);
}
//printf("about to call _handData->decodeRemoteData(fingerVectors);\n");
_handData->decodeRemoteData(fingerVectors);
}
} }
// skeleton joints // skeleton joints
@ -307,6 +269,23 @@ int unpackFloatScalarFromSignedTwoByteFixed(int16_t* byteFixedPointer, float* de
return sizeof(int16_t); return sizeof(int16_t);
} }
int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix) {
const unsigned char* startPosition = destBuffer;
destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.x, radix);
destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.y, radix);
destBuffer += packFloatScalarToSignedTwoByteFixed(destBuffer, srcVector.z, radix);
return destBuffer - startPosition;
}
int unpackFloatVec3FromSignedTwoByteFixed(unsigned char* sourceBuffer, glm::vec3& destination, int radix) {
const unsigned char* startPosition = sourceBuffer;
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.x), radix);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.y), radix);
sourceBuffer += unpackFloatScalarFromSignedTwoByteFixed((int16_t*) sourceBuffer, &(destination.z), radix);
return sourceBuffer - startPosition;
}
int packFloatAngleToTwoByte(unsigned char* buffer, float angle) { int packFloatAngleToTwoByte(unsigned char* buffer, float angle) {
const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.0); const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.0);

View file

@ -184,4 +184,8 @@ int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy);
int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix); int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, int radix);
int unpackFloatScalarFromSignedTwoByteFixed(int16_t* byteFixedPointer, float* destinationPointer, int radix); int unpackFloatScalarFromSignedTwoByteFixed(int16_t* byteFixedPointer, float* destinationPointer, int radix);
// A convenience for sending vec3's as fixed-poimt floats
int packFloatVec3ToSignedTwoByteFixed(unsigned char* destBuffer, const glm::vec3& srcVector, int radix);
int unpackFloatVec3FromSignedTwoByteFixed(unsigned char* sourceBuffer, glm::vec3& destination, int radix);
#endif /* defined(__hifi__AvatarData__) */ #endif /* defined(__hifi__AvatarData__) */

View file

@ -7,11 +7,20 @@
// //
#include "HandData.h" #include "HandData.h"
#include "AvatarData.h"
// Glove flags
#define GLOVE_FLAG_RAVE 0x01
// When converting between fixed and float, use this as the radix.
const int fingerVectorRadix = 4;
HandData::HandData(AvatarData* owningAvatar) : HandData::HandData(AvatarData* owningAvatar) :
_basePosition(0.0f, 0.0f, 0.0f), _basePosition(0.0f, 0.0f, 0.0f),
_baseOrientation(0.0f, 0.0f, 0.0f, 1.0f), _baseOrientation(0.0f, 0.0f, 0.0f, 1.0f),
_owningAvatarData(owningAvatar) _owningAvatarData(owningAvatar),
_isRaveGloveActive(false),
_raveGloveMode(RAVE_GLOVE_EFFECTS_MODE_THROBBING_COLOR)
{ {
// Start with two palms // Start with two palms
addNewPalm(); addNewPalm();
@ -49,53 +58,113 @@ _owningHandData(owningHandData)
setTrailLength(standardTrailLength); setTrailLength(standardTrailLength);
} }
void HandData::encodeRemoteData(std::vector<glm::vec3>& fingerVectors) { int HandData::encodeRemoteData(unsigned char* destinationBuffer) {
fingerVectors.clear(); const unsigned char* startPosition = destinationBuffer;
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i]; unsigned char gloveFlags = 0;
if (!palm.isActive()) { if (isRaveGloveActive())
continue; gloveFlags |= GLOVE_FLAG_RAVE;
*destinationBuffer++ = gloveFlags;
*destinationBuffer++ = getRaveGloveMode();
unsigned int numHands = 0;
for (unsigned int handIndex = 0; handIndex < getNumPalms(); ++handIndex) {
PalmData& palm = getPalms()[handIndex];
if (palm.isActive()) {
numHands++;
} }
fingerVectors.push_back(palm.getRawPosition()); }
fingerVectors.push_back(palm.getRawNormal()); *destinationBuffer++ = numHands;
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
FingerData& finger = palm.getFingers()[f]; for (unsigned int handIndex = 0; handIndex < getNumPalms(); ++handIndex) {
PalmData& palm = getPalms()[handIndex];
if (finger.isActive()) { if (palm.isActive()) {
fingerVectors.push_back(finger.getTipRawPosition()); destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, palm.getRawPosition(), fingerVectorRadix);
fingerVectors.push_back(finger.getRootRawPosition()); destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, palm.getRawNormal(), fingerVectorRadix);
unsigned int numFingers = 0;
for (unsigned int fingerIndex = 0; fingerIndex < palm.getNumFingers(); ++fingerIndex) {
FingerData& finger = palm.getFingers()[fingerIndex];
if (finger.isActive()) {
numFingers++;
}
} }
else { *destinationBuffer++ = numFingers;
fingerVectors.push_back(glm::vec3(0,0,0));
fingerVectors.push_back(glm::vec3(0,0,0)); for (unsigned int fingerIndex = 0; fingerIndex < palm.getNumFingers(); ++fingerIndex) {
FingerData& finger = palm.getFingers()[fingerIndex];
if (finger.isActive()) {
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, finger.getTipRawPosition(), fingerVectorRadix);
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, finger.getRootRawPosition(), fingerVectorRadix);
}
} }
} }
} }
// One byte for error checking safety.
size_t checkLength = destinationBuffer - startPosition;
*destinationBuffer++ = (unsigned char)checkLength;
return destinationBuffer - startPosition;
} }
void HandData::decodeRemoteData(const std::vector<glm::vec3>& fingerVectors) { int HandData::decodeRemoteData(unsigned char* sourceBuffer) {
size_t vectorIndex = 0; const unsigned char* startPosition = sourceBuffer;
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i]; unsigned char gloveFlags = *sourceBuffer++;
// If a palm is active, there will be char effectsMode = *sourceBuffer++;
// 1 vector for its position unsigned int numHands = *sourceBuffer++;
// 1 vector for normal
// 10 vectors for fingers (5 tip/root pairs) for (unsigned int handIndex = 0; handIndex < numHands; ++handIndex) {
bool palmActive = fingerVectors.size() >= i * 12; if (handIndex >= getNumPalms())
palm.setActive(palmActive); addNewPalm();
if (palmActive) { PalmData& palm = getPalms()[handIndex];
palm.setRawPosition(fingerVectors[vectorIndex++]);
palm.setRawNormal(fingerVectors[vectorIndex++]); glm::vec3 handPosition;
for (size_t f = 0; f < NUM_FINGERS_PER_HAND; ++f) { glm::vec3 handNormal;
FingerData& finger = palm.getFingers()[f]; sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, handPosition, fingerVectorRadix);
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, handNormal, fingerVectorRadix);
unsigned int numFingers = *sourceBuffer++;
palm.setRawPosition(handPosition);
palm.setRawNormal(handNormal);
palm.setActive(true);
for (unsigned int fingerIndex = 0; fingerIndex < numFingers; ++fingerIndex) {
if (fingerIndex < palm.getNumFingers()) {
FingerData& finger = palm.getFingers()[fingerIndex];
glm::vec3 tipPosition;
glm::vec3 rootPosition;
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, tipPosition, fingerVectorRadix);
sourceBuffer += unpackFloatVec3FromSignedTwoByteFixed(sourceBuffer, rootPosition, fingerVectorRadix);
finger.setRawTipPosition(tipPosition);
finger.setRawRootPosition(rootPosition);
finger.setActive(true); finger.setActive(true);
finger.setRawTipPosition(fingerVectors[vectorIndex++]);
finger.setRawRootPosition(fingerVectors[vectorIndex++]);
} }
} }
// Turn off any fingers which weren't used.
for (unsigned int fingerIndex = numFingers; fingerIndex < palm.getNumFingers(); ++fingerIndex) {
FingerData& finger = palm.getFingers()[fingerIndex];
finger.setActive(false);
}
} }
// Turn off any hands which weren't used.
for (unsigned int handIndex = numHands; handIndex < getNumPalms(); ++handIndex) {
PalmData& palm = getPalms()[handIndex];
palm.setActive(false);
}
setRaveGloveActive((gloveFlags & GLOVE_FLAG_RAVE) != 0);
setRaveGloveMode(effectsMode);
// One byte for error checking safety.
unsigned char requiredLength = (unsigned char)(sourceBuffer - startPosition);
unsigned char checkLength = *sourceBuffer++;
assert(checkLength == requiredLength);
return sourceBuffer - startPosition;
} }
void HandData::setFingerTrailLength(unsigned int length) { void HandData::setFingerTrailLength(unsigned int length) {

View file

@ -25,6 +25,22 @@ const int NUM_FINGERS = NUM_HANDS * NUM_FINGERS_PER_HAND;
const int LEAPID_INVALID = -1; const int LEAPID_INVALID = -1;
enum RaveGloveEffectsMode
{
RAVE_GLOVE_EFFECTS_MODE_NULL = -1,
RAVE_GLOVE_EFFECTS_MODE_THROBBING_COLOR,
RAVE_GLOVE_EFFECTS_MODE_TRAILS,
RAVE_GLOVE_EFFECTS_MODE_FIRE,
RAVE_GLOVE_EFFECTS_MODE_WATER,
RAVE_GLOVE_EFFECTS_MODE_FLASHY,
RAVE_GLOVE_EFFECTS_MODE_BOZO_SPARKLER,
RAVE_GLOVE_EFFECTS_MODE_LONG_SPARKLER,
RAVE_GLOVE_EFFECTS_MODE_SNAKE,
RAVE_GLOVE_EFFECTS_MODE_PULSE,
RAVE_GLOVE_EFFECTS_MODE_THROB,
NUM_RAVE_GLOVE_EFFECTS_MODES
};
class HandData { class HandData {
public: public:
HandData(AvatarData* owningAvatar); HandData(AvatarData* owningAvatar);
@ -49,15 +65,22 @@ public:
void updateFingerTrails(); void updateFingerTrails();
// Use these for sending and receiving hand data // Use these for sending and receiving hand data
void encodeRemoteData(std::vector<glm::vec3>& fingerVectors); int encodeRemoteData(unsigned char* destinationBuffer);
void decodeRemoteData(const std::vector<glm::vec3>& fingerVectors); int decodeRemoteData(unsigned char* sourceBuffer);
void setRaveGloveActive(bool active) { _isRaveGloveActive = active; }
virtual void setRaveGloveMode(int effectsMode) { _raveGloveMode = effectsMode; }
bool isRaveGloveActive() const { return _isRaveGloveActive; }
int getRaveGloveMode() { return _raveGloveMode; }
friend class AvatarData; friend class AvatarData;
protected: protected:
glm::vec3 _basePosition; // Hands are placed relative to this glm::vec3 _basePosition; // Hands are placed relative to this
glm::quat _baseOrientation; // Hands are placed relative to this glm::quat _baseOrientation; // Hands are placed relative to this
AvatarData* _owningAvatarData; AvatarData* _owningAvatarData;
std::vector<PalmData> _palms; std::vector<PalmData> _palms;
bool _isRaveGloveActive;
int _raveGloveMode;
private: private:
// privatize copy ctor and assignment operator so copies of this object cannot be made // privatize copy ctor and assignment operator so copies of this object cannot be made
HandData(const HandData&); HandData(const HandData&);

View file

@ -20,7 +20,7 @@ PACKET_VERSION versionForPacketType(PACKET_TYPE type) {
return 1; return 1;
case PACKET_TYPE_HEAD_DATA: case PACKET_TYPE_HEAD_DATA:
return 2; return 3;
case PACKET_TYPE_AVATAR_FACE_VIDEO: case PACKET_TYPE_AVATAR_FACE_VIDEO:
return 1; return 1;