Merge branch 'master' of https://github.com/worklist/hifi into multiple_voxel_servers

This commit is contained in:
ZappoMan 2013-08-05 14:57:10 -07:00
commit f1a0edb471
21 changed files with 538 additions and 278 deletions

View file

@ -2135,13 +2135,21 @@ void Application::toggleMixedSong() {
QByteArray filenameArray = filename.toLocal8Bit();
_audio.importSongToMixWithMicrophone(filenameArray.data());
_rawAudioMicrophoneMix->setText("Stop Mixing Song");
resetSongMixMenuItem();
} else {
_audio.stopMixingSongWithMicrophone();
_rawAudioMicrophoneMix->setText("Mix RAW Song");
resetSongMixMenuItem();
}
}
void Application::resetSongMixMenuItem() {
if (_audio.getSongFileBytes() == 0) {
_rawAudioMicrophoneMix->setText("Mix RAW Song");
} else {
_rawAudioMicrophoneMix->setText("Stop Mixing Song");
}
}
void Application::updateFrustumRenderModeAction() {
switch (_frustumDrawingMode) {
@ -2251,7 +2259,7 @@ Avatar* Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3
if (node->getLinkedData() != NULL && node->getType() == NODE_TYPE_AGENT) {
Avatar* avatar = (Avatar *) node->getLinkedData();
glm::vec3 headPosition = avatar->getHead().getPosition();
if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition, HEAD_SPHERE_RADIUS)) {
if (rayIntersectsSphere(mouseRayOrigin, mouseRayDirection, headPosition, HEAD_SPHERE_RADIUS * avatar->getScale())) {
eyePosition = avatar->getHead().getEyePosition();
_lookatIndicatorScale = avatar->getScale();
_lookatOtherPosition = headPosition;
@ -2263,6 +2271,16 @@ Avatar* Application::isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3
return NULL;
}
bool Application::isLookingAtMyAvatar(Avatar* avatar) {
glm::vec3 theirLookat = avatar->getHead().getLookAtPosition();
glm::vec3 myHeadPosition = _myAvatar.getHead().getPosition();
if (pointInSphere(theirLookat, myHeadPosition, HEAD_SPHERE_RADIUS * _myAvatar.getScale())) {
return true;
}
return false;
}
void Application::renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera) {
const float DISTANCE_FROM_HEAD_SPHERE = 0.1f * _lookatIndicatorScale;
@ -2954,6 +2972,23 @@ void Application::displaySide(Camera& whichCamera) {
//draw a grid ground plane....
if (_renderGroundPlaneOn->isChecked()) {
// draw grass plane with fog
glEnable(GL_FOG);
const float FOG_COLOR[] = { 1.0f, 1.0f, 1.0f, 1.0f };
glFogfv(GL_FOG_COLOR, FOG_COLOR);
glFogi(GL_FOG_MODE, GL_EXP2);
glFogf(GL_FOG_DENSITY, 0.025f);
glPushMatrix();
const float GRASS_PLANE_SIZE = 256.0f;
glTranslatef(-GRASS_PLANE_SIZE * 0.5f, -0.01f, GRASS_PLANE_SIZE * 0.5f);
glScalef(GRASS_PLANE_SIZE, 1.0f, GRASS_PLANE_SIZE);
glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
glColor3ub(70, 134, 74);
const int GRASS_DIVISIONS = 40;
_geometryCache.renderSquare(GRASS_DIVISIONS, GRASS_DIVISIONS);
glPopMatrix();
glDisable(GL_FOG);
renderGroundPlaneGrid(EDGE_SIZE_GROUND_PLANE, _audio.getCollisionSoundMagnitude());
}
// Draw voxels
@ -2995,6 +3030,9 @@ void Application::displaySide(Camera& whichCamera) {
if (!avatar->isInitialized()) {
avatar->init();
}
if (isLookingAtMyAvatar(avatar)) {
avatar->getHead().setLookAtPosition(_myCamera.getPosition());
}
avatar->render(false, _renderAvatarBalls->isChecked());
avatar->setDisplayingLookatVectors(_renderLookatOn->isChecked());
}

View file

@ -106,12 +106,12 @@ public:
QNetworkAccessManager* getNetworkAccessManager() { return _networkAccessManager; }
GeometryCache* getGeometryCache() { return &_geometryCache; }
void resetSongMixMenuItem();
public slots:
void sendAvatarFaceVideoMessage(int frameCount, const QByteArray& data);
private slots:
void timer();
@ -213,6 +213,7 @@ private:
void update(float deltaTime);
Avatar* isLookingAtOtherAvatar(glm::vec3& mouseRayOrigin, glm::vec3& mouseRayDirection,
glm::vec3& eyePosition, uint16_t& nodeID);
bool isLookingAtMyAvatar(Avatar* avatar);
void renderLookatIndicator(glm::vec3 pointOfInterest, Camera& whichCamera);
void updateAvatar(float deltaTime);

View file

@ -154,7 +154,7 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
currentPacketPtr += sizeof(headOrientation);
// check if we have a song to add to our audio
if (_songFileBytes > 0 && _songFileStream->tellg() <= _songFileBytes) {
if (_songFileBytes > 0 && _songFileStream->tellg() != -1) {
// iterate over BUFFER_LENGTH_SAMPLES_PER_CHANNEL from the song file and add that to our audio
for (int i = 0; i < BUFFER_LENGTH_SAMPLES_PER_CHANNEL; i++) {
int16_t songSample = 0;
@ -180,6 +180,9 @@ inline void Audio::performIO(int16_t* inputLeft, int16_t* outputLeft, int16_t* o
// reset the _songFileBytes back to zero
_songFileBytes = 0;
// call Application stopMixingSong method to fix menu item
Application::getInstance()->resetSongMixMenuItem();
}
// copy the audio data to the last BUFFER_LENGTH_BYTES bytes of the data packet
@ -501,7 +504,6 @@ void Audio::importSongToMixWithMicrophone(const char* filename) {
}
void Audio::stopMixingSongWithMicrophone() {
qDebug("Stop mixing called!");
_songFileBytes = 0;
}

119
interface/src/BendyLine.cpp Normal file
View file

@ -0,0 +1,119 @@
//
// BendyLine.cpp
// interface
//
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
#include "BendyLine.h"
#include "Util.h"
#include "world.h"
const float DEFAULT_BENDY_LINE_SPRING_FORCE = 10.0f;
const float DEFAULT_BENDY_LINE_TORQUE_FORCE = 0.1f;
const float DEFAULT_BENDY_LINE_DRAG = 10.0f;
const float DEFAULT_BENDY_LINE_LENGTH = 0.09f;
const float DEFAULT_BENDY_LINE_THICKNESS = 0.03f;
BendyLine::BendyLine(){
_springForce = DEFAULT_BENDY_LINE_SPRING_FORCE;
_torqueForce = DEFAULT_BENDY_LINE_TORQUE_FORCE;
_drag = DEFAULT_BENDY_LINE_DRAG;
_length = DEFAULT_BENDY_LINE_LENGTH;
_thickness = DEFAULT_BENDY_LINE_THICKNESS;
_gravityForce = glm::vec3(0.0f, 0.0f, 0.0f);
_basePosition = glm::vec3(0.0f, 0.0f, 0.0f);
_baseDirection = glm::vec3(0.0f, 0.0f, 0.0f);
_midPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_endPosition = glm::vec3(0.0f, 0.0f, 0.0f);
_midVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
_endVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
}
void BendyLine::reset() {
_midPosition = _basePosition + _baseDirection * _length * ONE_HALF;
_endPosition = _midPosition + _baseDirection * _length * ONE_HALF;
_midVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
_endVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
}
void BendyLine::update(float deltaTime) {
glm::vec3 midAxis = _midPosition - _basePosition;
glm::vec3 endAxis = _endPosition - _midPosition;
float midLength = glm::length(midAxis);
float endLength = glm::length(endAxis);
glm::vec3 midDirection;
glm::vec3 endDirection;
if (midLength > 0.0f) {
midDirection = midAxis / midLength;
} else {
midDirection = _baseDirection;
}
if (endLength > 0.0f) {
endDirection = endAxis / endLength;
} else {
endDirection = _baseDirection;
}
// add spring force
float midForce = midLength - _length * ONE_HALF;
float endForce = endLength - _length * ONE_HALF;
_midVelocity -= midDirection * midForce * _springForce * deltaTime;
_endVelocity -= endDirection * endForce * _springForce * deltaTime;
// add gravity force
_midVelocity += _gravityForce;
_endVelocity += _gravityForce;
// add torque force
_midVelocity += _baseDirection * _torqueForce * deltaTime;
_endVelocity += midDirection * _torqueForce * deltaTime;
// add drag force
float momentum = 1.0f - (_drag * deltaTime);
if (momentum < 0.0f) {
_midVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
_endVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
} else {
_midVelocity *= momentum;
_endVelocity *= momentum;
}
// update position by velocity
_midPosition += _midVelocity;
_endPosition += _endVelocity;
// clamp lengths
glm::vec3 newMidVector = _midPosition - _basePosition;
glm::vec3 newEndVector = _endPosition - _midPosition;
float newMidLength = glm::length(newMidVector);
float newEndLength = glm::length(newEndVector);
glm::vec3 newMidDirection;
glm::vec3 newEndDirection;
if (newMidLength > 0.0f) {
newMidDirection = newMidVector/newMidLength;
} else {
newMidDirection = _baseDirection;
}
if (newEndLength > 0.0f) {
newEndDirection = newEndVector/newEndLength;
} else {
newEndDirection = _baseDirection;
}
_endPosition = _midPosition + newEndDirection * _length * ONE_HALF;
_midPosition = _basePosition + newMidDirection * _length * ONE_HALF;
}

52
interface/src/BendyLine.h Normal file
View file

@ -0,0 +1,52 @@
//
// BendyLine.h
// interface
//
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
//
#ifndef hifi_bendyLine_h
#define hifi_bendyLine_h
#include <SharedUtil.h>
#include <glm/glm.hpp>
#include <glm/gtc/quaternion.hpp>
class BendyLine {
public:
BendyLine();
void update(float deltaTime);
void reset();
void setLength (float length ) { _length = length; }
void setThickness (float thickness ) { _thickness = thickness; }
void setSpringForce (float springForce ) { _springForce = springForce; }
void setTorqueForce (float torqueForce ) { _torqueForce = torqueForce; }
void setDrag (float drag ) { _drag = drag; }
void setBasePosition (glm::vec3 basePosition ) { _basePosition = basePosition; }
void setBaseDirection(glm::vec3 baseDirection) { _baseDirection = baseDirection;}
void setGravityForce (glm::vec3 gravityForce ) { _gravityForce = gravityForce; }
glm::vec3 getBasePosition() { return _basePosition; }
glm::vec3 getMidPosition () { return _midPosition; }
glm::vec3 getEndPosition () { return _endPosition; }
float getThickness () { return _thickness; }
private:
float _springForce;
float _torqueForce;
float _drag;
float _length;
float _thickness;
glm::vec3 _gravityForce;
glm::vec3 _basePosition;
glm::vec3 _baseDirection;
glm::vec3 _midPosition;
glm::vec3 _endPosition;
glm::vec3 _midVelocity;
glm::vec3 _endVelocity;
};
#endif

View file

@ -322,27 +322,48 @@ void ParticleSystem::updateParticle(int p, float deltaTime) {
// apply color modulation
if (myEmitter.particleAttributes[lifeStage ].modulationAmplitude > 0.0f) {
float modulation = 0.0f;
float redModulation = 0.0f;
float greenModulation = 0.0f;
float bueModulation = 0.0f;
float radian = _timer * myEmitter.particleAttributes[lifeStage ].modulationRate * PI_TIMES_TWO;
if (myEmitter.particleAttributes[lifeStage ].modulationStyle == COLOR_MODULATION_STYLE_LIGHNTESS_PULSE) {
if (sinf(radian) > 0.0f) {
modulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude;
redModulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude;
greenModulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude;
bueModulation = myEmitter.particleAttributes[lifeStage].modulationAmplitude;
}
} else if (myEmitter.particleAttributes[lifeStage].modulationStyle == COLOR_MODULATION_STYLE_LIGHTNESS_WAVE) {
float a = myEmitter.particleAttributes[lifeStage].modulationAmplitude;
modulation = a * ONE_HALF + sinf(radian) * a * ONE_HALF;
float amp = myEmitter.particleAttributes[lifeStage].modulationAmplitude;
float brightness = amp * ONE_HALF + sinf(radian) * amp * ONE_HALF;
redModulation = brightness;
greenModulation = brightness;
bueModulation = brightness;
} else if (myEmitter.particleAttributes[lifeStage].modulationStyle == COLOR_MODULATION_STYLE_RAINBOW_CYCLE) {
float amp = myEmitter.particleAttributes[lifeStage].modulationAmplitude * ONE_HALF;
redModulation = sinf(radian * RAINBOW_CYCLE_RED_RATE ) * amp;
greenModulation = sinf(radian * RAINBOW_CYCLE_GREEN_RATE) * amp;
bueModulation = sinf(radian * RAINBOW_CYCLE_BLUE_RATE ) * amp;
}
_particle[p].color.r += modulation;
_particle[p].color.g += modulation;
_particle[p].color.b += modulation;
_particle[p].color.a += modulation;
_particle[p].color.r += redModulation;
_particle[p].color.g += greenModulation;
_particle[p].color.b += bueModulation;
_particle[p].color.a = 1.0f;
if (_particle[p].color.r > 1.0f) {_particle[p].color.r = 1.0f;}
if (_particle[p].color.g > 1.0f) {_particle[p].color.g = 1.0f;}
if (_particle[p].color.b > 1.0f) {_particle[p].color.b = 1.0f;}
if (_particle[p].color.a > 1.0f) {_particle[p].color.a = 1.0f;}
}
if (_particle[p].color.r < 0.0f) {_particle[p].color.r = 0.0f;}
if (_particle[p].color.g < 0.0f) {_particle[p].color.g = 0.0f;}
if (_particle[p].color.b < 0.0f) {_particle[p].color.b = 0.0f;}
if (_particle[p].color.a < 0.0f) {_particle[p].color.a = 0.0f;}
}
// do this at the end...
_particle[p].age += deltaTime;

View file

@ -15,6 +15,10 @@ const int NULL_PARTICLE = -1;
const int MAX_EMITTERS = 100;
const int MAX_PARTICLES = 5000;
const float RAINBOW_CYCLE_RED_RATE = 0.5f;
const float RAINBOW_CYCLE_GREEN_RATE = 0.7f;
const float RAINBOW_CYCLE_BLUE_RATE = 1.0f;
enum ParticleRenderStyle
{
PARTICLE_RENDER_STYLE_SPHERE = 0,
@ -28,6 +32,7 @@ enum ColorModulationStyle
COLOR_MODULATION_STYLE_NULL = -1,
COLOR_MODULATION_STYLE_LIGHNTESS_PULSE,
COLOR_MODULATION_STYLE_LIGHTNESS_WAVE,
COLOR_MODULATION_STYLE_RAINBOW_CYCLE,
NUM_COLOR_MODULATION_STYLES
};

View file

@ -607,3 +607,12 @@ bool rayIntersectsSphere(glm::vec3& rayStarting, glm::vec3& rayNormalizedDirecti
}
return false;
}
bool pointInSphere(glm::vec3& point, glm::vec3& sphereCenter, double sphereRadius) {
glm::vec3 diff = point - sphereCenter;
double mag = sqrt(glm::dot(diff, diff));
if (mag <= sphereRadius) {
return true;
}
return false;
}

View file

@ -76,4 +76,6 @@ float loadSetting(QSettings* settings, const char* name, float defaultValue);
bool rayIntersectsSphere(glm::vec3& rayStarting, glm::vec3& rayNormalizedDirection, glm::vec3& sphereCenter, double sphereRadius);
bool pointInSphere(glm::vec3& point, glm::vec3& sphereCenter, double sphereRadius);
#endif

View file

@ -22,9 +22,7 @@ Hand::Hand(Avatar* owningAvatar) :
HandData((AvatarData*)owningAvatar),
_raveGloveClock(0.0f),
_raveGloveMode(RAVE_GLOVE_EFFECTS_MODE_THROBBING_COLOR),
_raveGloveInitialized(false),
_isRaveGloveActive(false),
_owningAvatar(owningAvatar),
_renderAlpha(1.0),
_lookingInMirror(false),
@ -345,29 +343,6 @@ void Hand::updateRaveGloveParticles(float deltaTime) {
_raveGloveParticleSystem.setUpDirection(glm::vec3(0.0f, 1.0f, 0.0f));
_raveGloveInitialized = true;
} else {
_raveGloveClock += deltaTime;
// this rave glove effect oscillates though various colors and radii that are meant to show off some effects
if (_raveGloveMode == RAVE_GLOVE_EFFECTS_MODE_THROBBING_COLOR) {
ParticleSystem::ParticleAttributes attributes;
float red = 0.5f + 0.5f * sinf(_raveGloveClock * 2.4f);
float green = 0.5f + 0.5f * cosf(_raveGloveClock * 2.7f);
float blue = 0.5f + 0.5f * sinf(_raveGloveClock * 3.0f);
float alpha = 1.0f;
attributes.color = glm::vec4(red, green, blue, alpha);
attributes.radius = 0.01f + 0.003f * sinf(_raveGloveClock * 50.0f);
attributes.modulationAmplitude = 0.0f;
for ( int f = 0; f< NUM_FINGERS; f ++ ) {
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_0, attributes);
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_1, attributes);
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_2, attributes);
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_3, attributes);
}
}
_raveGloveParticleSystem.simulate(deltaTime);
}
}
@ -397,11 +372,15 @@ void Hand::setRaveGloveMode(int mode) {
_raveGloveParticleSystem.setParticleAttributesToDefault(&attributes);
attributes.radius = 0.02f;
attributes.gravity = 0.0f;
attributes.airFriction = 0.0f;
attributes.jitter = 0.0f;
attributes.bounce = 0.0f;
attributes.modulationAmplitude = 1.0;
attributes.modulationRate = 0.33;
attributes.modulationStyle = COLOR_MODULATION_STYLE_RAINBOW_CYCLE;
attributes.color = glm::vec4( 0.5f, 0.5f, 0.5f, 1.0f);
attributes.radius = 0.02f;
attributes.gravity = 0.0f;
attributes.airFriction = 0.0f;
attributes.jitter = 0.0f;
attributes.bounce = 0.0f;
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_0, attributes);
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_1, attributes);
_raveGloveParticleSystem.setParticleAttributes(_raveGloveEmitter[f], PARTICLE_LIFESTAGE_2, attributes);

View file

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

View file

@ -30,9 +30,9 @@ const float MINIMUM_EYE_ROTATION_DOT = 0.5f; // based on a dot product: 1.0 is
const float EYEBALL_RADIUS = 0.017;
const float EYELID_RADIUS = 0.019;
const float EYEBALL_COLOR[3] = { 0.9f, 0.9f, 0.8f };
const float HAIR_SPRING_FORCE = 10.0f;
const float HAIR_SPRING_FORCE = 7.0f;
const float HAIR_TORQUE_FORCE = 0.1f;
const float HAIR_GRAVITY_FORCE = 0.05f;
const float HAIR_GRAVITY_FORCE = 0.02f;
const float HAIR_DRAG = 10.0f;
const float HAIR_LENGTH = 0.09f;
const float HAIR_THICKNESS = 0.03f;
@ -90,7 +90,7 @@ Head::Head(Avatar* owningAvatar) :
_cameraFollowHeadRate(0.0f),
_face(this)
{
if (USING_PHYSICAL_MOHAWK) {
if (USING_PHYSICAL_MOHAWK) {
resetHairPhysics();
}
}
@ -105,7 +105,7 @@ void Head::init() {
_irisProgram->setUniformValue("texture", 0);
_eyePositionLocation = _irisProgram->uniformLocation("eyePosition");
QImage image = QImage(IRIS_TEXTURE_FILENAME).convertToFormat(QImage::Format_ARGB32);
glGenTextures(1, &_irisTextureID);
@ -127,20 +127,20 @@ void Head::reset() {
}
}
void Head::resetHairPhysics() {
glm::vec3 up = getUpDirection();
//glm::vec3 up = getUpDirection();
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
_hairTuft[t].length = _scale * HAIR_LENGTH;
_hairTuft[t].thickness = _scale * HAIR_THICKNESS;
_hairTuft[t].basePosition = _position + up * _scale * BODY_BALL_RADIUS_HEAD_BASE * 0.9f;
_hairTuft[t].midPosition = _hairTuft[t].basePosition + up * _hairTuft[t].length * ONE_HALF;
_hairTuft[t].endPosition = _hairTuft[t].midPosition + up * _hairTuft[t].length * ONE_HALF;
_hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
_hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
_hairTuft[t].setSpringForce (HAIR_SPRING_FORCE);
_hairTuft[t].setTorqueForce (HAIR_TORQUE_FORCE);
_hairTuft[t].setGravityForce (HAIR_GRAVITY_FORCE * _gravity);
_hairTuft[t].setDrag (HAIR_DRAG);
_hairTuft[t].setLength (_scale * HAIR_LENGTH );
_hairTuft[t].setThickness (_scale * HAIR_THICKNESS);
_hairTuft[t].setBaseDirection(getUpDirection());
_hairTuft[t].reset();
}
}
}
@ -223,6 +223,7 @@ void Head::simulate(float deltaTime, bool isMine) {
// based on the nature of the lookat position, determine if the eyes can look / are looking at it.
if (USING_PHYSICAL_MOHAWK) {
updateHairPhysics(deltaTime);
}
// Update camera pitch and yaw independently from motion of head (for gyro-based interface)
@ -376,17 +377,17 @@ void Head::renderMohawk() {
if (USING_PHYSICAL_MOHAWK) {
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
glm::vec3 baseAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition;
glm::vec3 midAxis = _hairTuft[t].endPosition - _hairTuft[t].midPosition;
glm::vec3 viewVector = _hairTuft[t].basePosition - Application::getInstance()->getCamera()->getPosition();
glm::vec3 baseAxis = _hairTuft[t].getMidPosition() - _hairTuft[t].getBasePosition();
glm::vec3 midAxis = _hairTuft[t].getEndPosition() - _hairTuft[t].getMidPosition();
glm::vec3 viewVector = _hairTuft[t].getBasePosition() - Application::getInstance()->getCamera()->getPosition();
glm::vec3 basePerpendicular = glm::normalize(glm::cross(baseAxis, viewVector));
glm::vec3 midPerpendicular = glm::normalize(glm::cross(midAxis, viewVector));
glm::vec3 base1 = _hairTuft[t].basePosition - basePerpendicular * _hairTuft[t].thickness * ONE_HALF;
glm::vec3 base2 = _hairTuft[t].basePosition + basePerpendicular * _hairTuft[t].thickness * ONE_HALF;
glm::vec3 mid1 = _hairTuft[t].midPosition - midPerpendicular * _hairTuft[t].thickness * ONE_HALF * ONE_HALF;
glm::vec3 mid2 = _hairTuft[t].midPosition + midPerpendicular * _hairTuft[t].thickness * ONE_HALF * ONE_HALF;
glm::vec3 base1 = _hairTuft[t].getBasePosition() - basePerpendicular * _hairTuft[t].getThickness() * ONE_HALF;
glm::vec3 base2 = _hairTuft[t].getBasePosition() + basePerpendicular * _hairTuft[t].getThickness() * ONE_HALF;
glm::vec3 mid1 = _hairTuft[t].getMidPosition() - midPerpendicular * _hairTuft[t].getThickness() * ONE_HALF * ONE_HALF;
glm::vec3 mid2 = _hairTuft[t].getMidPosition() + midPerpendicular * _hairTuft[t].getThickness() * ONE_HALF * ONE_HALF;
glColor3f(_mohawkColors[t].x, _mohawkColors[t].y, _mohawkColors[t].z);
@ -399,7 +400,7 @@ void Head::renderMohawk() {
glVertex3f(mid2.x, mid2.y, mid2.z );
glVertex3f(mid1.x, mid1.y, mid1.z );
glVertex3f(mid2.x, mid2.y, mid2.z );
glVertex3f(_hairTuft[t].endPosition.x, _hairTuft[t].endPosition.y, _hairTuft[t].endPosition.z );
glVertex3f(_hairTuft[t].getEndPosition().x, _hairTuft[t].getEndPosition().y, _hairTuft[t].getEndPosition().z );
glEnd();
}
} else {
@ -735,100 +736,17 @@ void Head::renderLookatVectors(glm::vec3 leftEyePosition, glm::vec3 rightEyePosi
glEnd();
}
void Head::updateHairPhysics(float deltaTime) {
glm::quat orientation = getOrientation();
glm::vec3 up = orientation * IDENTITY_UP;
glm::vec3 front = orientation * IDENTITY_FRONT;
for (int t = 0; t < NUM_HAIR_TUFTS; t ++) {
float fraction = (float)t / (float)(NUM_HAIR_TUFTS - 1);
float angle = -20.0f + 40.0f * fraction;
float radian = angle * PI_OVER_180;
glm::vec3 baseDirection
= front * sinf(radian)
+ up * cosf(radian);
_hairTuft[t].basePosition = _position + _scale * BODY_BALL_RADIUS_HEAD_BASE * 0.9f * baseDirection;
glm::vec3 midAxis = _hairTuft[t].midPosition - _hairTuft[t].basePosition;
glm::vec3 endAxis = _hairTuft[t].endPosition - _hairTuft[t].midPosition;
float midLength = glm::length(midAxis);
float endLength = glm::length(endAxis);
glm::vec3 midDirection;
glm::vec3 endDirection;
if (midLength > 0.0f) {
midDirection = midAxis / midLength;
} else {
midDirection = up;
}
if (endLength > 0.0f) {
endDirection = endAxis / endLength;
} else {
endDirection = up;
}
// add spring force
float midForce = midLength - _hairTuft[t].length * ONE_HALF;
float endForce = endLength - _hairTuft[t].length * ONE_HALF;
_hairTuft[t].midVelocity -= midDirection * midForce * HAIR_SPRING_FORCE * deltaTime;
_hairTuft[t].endVelocity -= endDirection * endForce * HAIR_SPRING_FORCE * deltaTime;
// add gravity force
glm::vec3 gravityForce = _gravity * HAIR_GRAVITY_FORCE * deltaTime;
_hairTuft[t].midVelocity += gravityForce;
_hairTuft[t].endVelocity += gravityForce;
// add torque force
_hairTuft[t].midVelocity += baseDirection * HAIR_TORQUE_FORCE * deltaTime;
_hairTuft[t].endVelocity += midDirection * HAIR_TORQUE_FORCE * deltaTime;
// add drag force
float momentum = 1.0f - (HAIR_DRAG * deltaTime);
if (momentum < 0.0f) {
_hairTuft[t].midVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
_hairTuft[t].endVelocity = glm::vec3(0.0f, 0.0f, 0.0f);
} else {
_hairTuft[t].midVelocity *= momentum;
_hairTuft[t].endVelocity *= momentum;
}
// update position by velocity
_hairTuft[t].midPosition += _hairTuft[t].midVelocity;
_hairTuft[t].endPosition += _hairTuft[t].endVelocity;
// clamp lengths
glm::vec3 newMidVector = _hairTuft[t].midPosition - _hairTuft[t].basePosition;
glm::vec3 newEndVector = _hairTuft[t].endPosition - _hairTuft[t].midPosition;
float newMidLength = glm::length(newMidVector);
float newEndLength = glm::length(newEndVector);
glm::vec3 newMidDirection;
glm::vec3 newEndDirection;
if (newMidLength > 0.0f) {
newMidDirection = newMidVector/newMidLength;
} else {
newMidDirection = up;
}
if (newEndLength > 0.0f) {
newEndDirection = newEndVector/newEndLength;
} else {
newEndDirection = up;
}
_hairTuft[t].endPosition = _hairTuft[t].midPosition + newEndDirection * _hairTuft[t].length * ONE_HALF;
_hairTuft[t].midPosition = _hairTuft[t].basePosition + newMidDirection * _hairTuft[t].length * ONE_HALF;
glm::vec3 baseDirection = front * sinf(radian) + up * cosf(radian);
_hairTuft[t].setBasePosition (_position + _scale * BODY_BALL_RADIUS_HEAD_BASE * 0.9f * baseDirection);
_hairTuft[t].setBaseDirection(baseDirection);
_hairTuft[t].update(deltaTime);
}
}

View file

@ -18,6 +18,7 @@
#include <VoxelConstants.h>
#include "Face.h"
#include "BendyLine.h"
#include "InterfaceConfig.h"
#include "SerialInterface.h"
#include "world.h"
@ -29,7 +30,7 @@ enum eyeContactTargets
MOUTH
};
const int NUM_HAIR_TUFTS = 4;
const int NUM_HAIR_TUFTS = 4;
class Avatar;
class ProgramObject;
@ -80,18 +81,6 @@ private:
Head(const Head&);
Head& operator= (const Head&);
struct HairTuft
{
float length;
float thickness;
glm::vec3 basePosition;
glm::vec3 midPosition;
glm::vec3 endPosition;
glm::vec3 midVelocity;
glm::vec3 endVelocity;
};
struct Nose
{
glm::vec3 top;
@ -123,7 +112,7 @@ private:
float _returnSpringScale; //strength of return springs
glm::vec3 _bodyRotation;
bool _renderLookatVectors;
HairTuft _hairTuft[NUM_HAIR_TUFTS];
BendyLine _hairTuft[NUM_HAIR_TUFTS];
glm::vec3* _mohawkTriangleFan;
glm::vec3* _mohawkColors;
glm::vec3 _saccade;

View file

@ -18,7 +18,7 @@ GeometryCache::~GeometryCache() {
}
void GeometryCache::renderHemisphere(int slices, int stacks) {
VerticesIndices& vbo = _hemisphereVBOs[SlicesStacks(slices, stacks)];
VerticesIndices& vbo = _hemisphereVBOs[IntPair(slices, stacks)];
int vertices = slices * (stacks - 1) + 1;
int indices = slices * 2 * 3 * (stacks - 2) + slices * 3;
if (vbo.first == 0) {
@ -95,3 +95,71 @@ void GeometryCache::renderHemisphere(int slices, int stacks) {
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void GeometryCache::renderSquare(int xDivisions, int yDivisions) {
VerticesIndices& vbo = _squareVBOs[IntPair(xDivisions, yDivisions)];
int xVertices = xDivisions + 1;
int yVertices = yDivisions + 1;
int vertices = xVertices * yVertices;
int indices = 2 * 3 * xDivisions * yDivisions;
if (vbo.first == 0) {
GLfloat* vertexData = new GLfloat[vertices * 3];
GLfloat* vertex = vertexData;
for (int i = 0; i <= yDivisions; i++) {
float y = (float)i / yDivisions;
for (int j = 0; j <= xDivisions; j++) {
*(vertex++) = (float)j / xDivisions;
*(vertex++) = y;
*(vertex++) = 0.0f;
}
}
glGenBuffers(1, &vbo.first);
glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
const int BYTES_PER_VERTEX = 3 * sizeof(GLfloat);
glBufferData(GL_ARRAY_BUFFER, vertices * BYTES_PER_VERTEX, vertexData, GL_STATIC_DRAW);
delete[] vertexData;
GLushort* indexData = new GLushort[indices];
GLushort* index = indexData;
for (int i = 0; i < yDivisions; i++) {
GLushort bottom = i * xVertices;
GLushort top = bottom + xVertices;
for (int j = 0; j < xDivisions; j++) {
int next = j + 1;
*(index++) = bottom + j;
*(index++) = top + next;
*(index++) = top + j;
*(index++) = bottom + j;
*(index++) = bottom + next;
*(index++) = top + next;
}
}
glGenBuffers(1, &vbo.second);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
const int BYTES_PER_INDEX = sizeof(GLushort);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices * BYTES_PER_INDEX, indexData, GL_STATIC_DRAW);
delete[] indexData;
} else {
glBindBuffer(GL_ARRAY_BUFFER, vbo.first);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo.second);
}
glEnableClientState(GL_VERTEX_ARRAY);
// all vertices have the same normal
glNormal3f(0.0f, 0.0f, 1.0f);
glVertexPointer(3, GL_FLOAT, 0, 0);
glDrawRangeElementsEXT(GL_TRIANGLES, 0, vertices - 1, indices, GL_UNSIGNED_SHORT, 0);
glDisableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

View file

@ -19,13 +19,15 @@ public:
~GeometryCache();
void renderHemisphere(int slices, int stacks);
void renderSquare(int xDivisions, int yDivisions);
private:
typedef QPair<int, int> SlicesStacks;
typedef QPair<int, int> IntPair;
typedef QPair<GLuint, GLuint> VerticesIndices;
QHash<SlicesStacks, VerticesIndices> _hemisphereVBOs;
QHash<IntPair, VerticesIndices> _hemisphereVBOs;
QHash<IntPair, VerticesIndices> _squareVBOs;
};
#endif /* defined(__interface__GeometryCache__) */

View file

@ -6,8 +6,8 @@
// Copyright (c) 2013 HighFidelity, Inc. All rights reserved.
//
#import <QtScript/QScriptEngine>
#import <QtNetwork/QtNetwork>
#include <QtScript/QScriptEngine>
#include <QtNetwork/QtNetwork>
#include <NodeList.h>
@ -85,4 +85,4 @@ void Agent::run(QUrl scriptURL) {
}
}
}
}

View file

@ -146,21 +146,7 @@ int AvatarData::getBroadcastData(unsigned char* destinationBuffer) {
*destinationBuffer++ = bitItems;
// leap hand data
std::vector<glm::vec3> fingerVectors;
//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);
}
destinationBuffer += _handData->encodeRemoteData(destinationBuffer);
// skeleton joints
*destinationBuffer++ = (unsigned char)_joints.size();
@ -263,34 +249,10 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
// hand state, stored as a semi-nibble in the bitItems
_handState = getSemiNibbleAt(bitItems,HAND_STATE_START_BIT);
//printf("about to call leap hand data code in AvatarData::parseData...\n");
// leap hand data
if (sourceBuffer - startPosition < numBytes) {
//printf("got inside of 'if (sourceBuffer - startPosition < numBytes)'\n");
// check passed, bytes match
unsigned int numFingerVectors = *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);
}
sourceBuffer += _handData->decodeRemoteData(sourceBuffer);
}
// skeleton joints
@ -324,6 +286,23 @@ int unpackFloatScalarFromSignedTwoByteFixed(int16_t* byteFixedPointer, float* de
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) {
const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.0);

View file

@ -191,4 +191,8 @@ int unpackFloatFromByte(unsigned char* buffer, float& value, float scaleBy);
int packFloatScalarToSignedTwoByteFixed(unsigned char* buffer, float scalar, 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__) */

View file

@ -7,11 +7,20 @@
//
#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) :
_basePosition(0.0f, 0.0f, 0.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
addNewPalm();
@ -49,53 +58,113 @@ _owningHandData(owningHandData)
setTrailLength(standardTrailLength);
}
void HandData::encodeRemoteData(std::vector<glm::vec3>& fingerVectors) {
fingerVectors.clear();
for (size_t i = 0; i < getNumPalms(); ++i) {
int HandData::encodeRemoteData(unsigned char* destinationBuffer) {
const unsigned char* startPosition = destinationBuffer;
PalmData& palm = getPalms()[i];
if (!palm.isActive()) {
continue;
unsigned char gloveFlags = 0;
if (isRaveGloveActive())
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());
for (size_t f = 0; f < palm.getNumFingers(); ++f) {
FingerData& finger = palm.getFingers()[f];
if (finger.isActive()) {
fingerVectors.push_back(finger.getTipRawPosition());
fingerVectors.push_back(finger.getRootRawPosition());
}
*destinationBuffer++ = numHands;
for (unsigned int handIndex = 0; handIndex < getNumPalms(); ++handIndex) {
PalmData& palm = getPalms()[handIndex];
if (palm.isActive()) {
destinationBuffer += packFloatVec3ToSignedTwoByteFixed(destinationBuffer, palm.getRawPosition(), fingerVectorRadix);
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 {
fingerVectors.push_back(glm::vec3(0,0,0));
fingerVectors.push_back(glm::vec3(0,0,0));
*destinationBuffer++ = numFingers;
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) {
size_t vectorIndex = 0;
for (size_t i = 0; i < getNumPalms(); ++i) {
PalmData& palm = getPalms()[i];
// If a palm is active, there will be
// 1 vector for its position
// 1 vector for normal
// 10 vectors for fingers (5 tip/root pairs)
bool palmActive = fingerVectors.size() >= i * 12;
palm.setActive(palmActive);
if (palmActive) {
palm.setRawPosition(fingerVectors[vectorIndex++]);
palm.setRawNormal(fingerVectors[vectorIndex++]);
for (size_t f = 0; f < NUM_FINGERS_PER_HAND; ++f) {
FingerData& finger = palm.getFingers()[f];
int HandData::decodeRemoteData(unsigned char* sourceBuffer) {
const unsigned char* startPosition = sourceBuffer;
unsigned char gloveFlags = *sourceBuffer++;
char effectsMode = *sourceBuffer++;
unsigned int numHands = *sourceBuffer++;
for (unsigned int handIndex = 0; handIndex < numHands; ++handIndex) {
if (handIndex >= getNumPalms())
addNewPalm();
PalmData& palm = getPalms()[handIndex];
glm::vec3 handPosition;
glm::vec3 handNormal;
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.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) {

View file

@ -25,6 +25,22 @@ const int NUM_FINGERS = NUM_HANDS * NUM_FINGERS_PER_HAND;
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 {
public:
HandData(AvatarData* owningAvatar);
@ -49,15 +65,22 @@ public:
void updateFingerTrails();
// Use these for sending and receiving hand data
void encodeRemoteData(std::vector<glm::vec3>& fingerVectors);
void decodeRemoteData(const std::vector<glm::vec3>& fingerVectors);
int encodeRemoteData(unsigned char* destinationBuffer);
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;
protected:
glm::vec3 _basePosition; // Hands are placed relative to this
glm::quat _baseOrientation; // Hands are placed relative to this
AvatarData* _owningAvatarData;
std::vector<PalmData> _palms;
bool _isRaveGloveActive;
int _raveGloveMode;
private:
// privatize copy ctor and assignment operator so copies of this object cannot be made
HandData(const HandData&);

View file

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