Merge branch 'master' of https://github.com/highfidelity/hifi into fix_import

This commit is contained in:
Atlante45 2014-02-19 16:11:31 -08:00
commit b69bdccc8f
10 changed files with 264 additions and 32 deletions

View file

@ -653,6 +653,9 @@ void Application::updateProjectionMatrix(Camera& camera, bool updateViewFrustum)
}
glFrustum(left, right, bottom, top, nearVal, farVal);
// save matrix
glGetFloatv(GL_PROJECTION_MATRIX, (GLfloat*)&_projectionMatrix);
glMatrixMode(GL_MODELVIEW);
}
@ -2961,6 +2964,15 @@ void Application::loadTranslatedViewMatrix(const glm::vec3& translation) {
translation.z + _viewMatrixTranslation.z);
}
void Application::getModelViewMatrix(glm::dmat4* modelViewMatrix) {
(*modelViewMatrix) =_untranslatedViewMatrix;
(*modelViewMatrix)[3] = _untranslatedViewMatrix * glm::vec4(_viewMatrixTranslation, 1);
}
void Application::getProjectionMatrix(glm::dmat4* projectionMatrix) {
*projectionMatrix = _projectionMatrix;
}
void Application::computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const {

View file

@ -193,6 +193,9 @@ public:
const glm::mat4& getShadowMatrix() const { return _shadowMatrix; }
void getModelViewMatrix(glm::dmat4* modelViewMatrix);
void getProjectionMatrix(glm::dmat4* projectionMatrix);
/// Computes the off-axis frustum parameters for the view frustum, taking mirroring into account.
void computeOffAxisFrustum(float& left, float& right, float& bottom, float& top, float& nearVal,
float& farVal, glm::vec4& nearClipPlane, glm::vec4& farClipPlane) const;
@ -398,6 +401,7 @@ private:
glm::mat4 _untranslatedViewMatrix;
glm::vec3 _viewMatrixTranslation;
glm::mat4 _projectionMatrix;
glm::mat4 _shadowMatrix;

View file

@ -785,6 +785,11 @@ void Menu::editPreferences() {
skeletonURLEdit->setPlaceholderText(DEFAULT_BODY_MODEL_URL.toString());
form->addRow("Skeleton URL:", skeletonURLEdit);
QString displayNameString = applicationInstance->getAvatar()->getDisplayName();
QLineEdit* displayNameEdit = new QLineEdit(displayNameString);
displayNameEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
form->addRow("Display name:", displayNameEdit);
QSlider* pupilDilation = new QSlider(Qt::Horizontal);
pupilDilation->setValue(applicationInstance->getAvatar()->getHead()->getPupilDilation() * pupilDilation->maximum());
form->addRow("Pupil Dilation:", pupilDilation);
@ -857,7 +862,14 @@ void Menu::editPreferences() {
applicationInstance->getAvatar()->setSkeletonModelURL(skeletonModelURL);
shouldDispatchIdentityPacket = true;
}
QString displayNameStr(displayNameEdit->text());
if (displayNameStr != displayNameString) {
applicationInstance->getAvatar()->setDisplayName(displayNameStr);
shouldDispatchIdentityPacket = true;
}
if (shouldDispatchIdentityPacket) {
applicationInstance->getAvatar()->sendIdentityPacket();
}

View file

@ -56,6 +56,9 @@ const float HEAD_RATE_MAX = 50.f;
const int NUM_BODY_CONE_SIDES = 9;
const float CHAT_MESSAGE_SCALE = 0.0015f;
const float CHAT_MESSAGE_HEIGHT = 0.1f;
const float DISPLAYNAME_FADE_TIME = 0.5f;
const float DISPLAYNAME_FADE_FACTOR = pow(0.01f, 1.0f / DISPLAYNAME_FADE_TIME);
const float DISPLAYNAME_ALPHA = 0.95f;
Avatar::Avatar() :
AvatarData(),
@ -107,7 +110,7 @@ void Avatar::simulate(float deltaTime) {
if (_scale != _targetScale) {
setScale(_targetScale);
}
// copy velocity so we can use it later for acceleration
glm::vec3 oldVelocity = getVelocity();
@ -135,7 +138,23 @@ void Avatar::simulate(float deltaTime) {
// Zero thrust out now that we've added it to velocity in this frame
_thrust = glm::vec3(0, 0, 0);
// update animation for display name fade in/out
if ( _displayNameTargetAlpha != _displayNameAlpha) {
// the alpha function is
// Fade out => alpha(t) = factor ^ t => alpha(t+dt) = alpha(t) * factor^(dt)
// Fade in => alpha(t) = 1 - factor^t => alpha(t+dt) = 1-(1-alpha(t))*coef^(dt)
// factor^(dt) = coef
float coef = pow(DISPLAYNAME_FADE_FACTOR, deltaTime);
if (_displayNameTargetAlpha < _displayNameAlpha) {
// Fading out
_displayNameAlpha *= coef;
} else {
// Fading in
_displayNameAlpha = 1 - (1 - _displayNameAlpha) * coef;
}
_displayNameAlpha = abs(_displayNameAlpha - _displayNameTargetAlpha) < 0.01? _displayNameTargetAlpha : _displayNameAlpha;
}
}
void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction) {
@ -143,19 +162,35 @@ void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction) {
_mouseRayDirection = direction;
}
static TextRenderer* textRenderer() {
static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 24, -1, false, TextRenderer::SHADOW_EFFECT);
return renderer;
enum TextRendererType {
CHAT,
DISPLAYNAME
};
static TextRenderer* textRenderer(TextRendererType type) {
static TextRenderer* chatRenderer = new TextRenderer(SANS_FONT_FAMILY, 24, -1, false, TextRenderer::SHADOW_EFFECT);
static TextRenderer* displayNameRenderer = new TextRenderer(SANS_FONT_FAMILY, 12, -1, false, TextRenderer::NO_EFFECT);
switch(type) {
case CHAT:
return chatRenderer;
case DISPLAYNAME:
return displayNameRenderer;
}
return displayNameRenderer;
}
void Avatar::render(bool forceRenderHead) {
glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition();
float lengthToTarget = glm::length(toTarget);
{
// glow when moving in the distance
glm::vec3 toTarget = _position - Application::getInstance()->getAvatar()->getPosition();
const float GLOW_DISTANCE = 5.0f;
Glower glower(_moving && glm::length(toTarget) > GLOW_DISTANCE ? 1.0f : 0.0f);
const float GLOW_DISTANCE = 5.0f;
Glower glower(_moving && lengthToTarget > GLOW_DISTANCE ? 1.0f : 0.0f);
// render body
if (Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionProxies)) {
_skeletonModel.renderCollisionProxies(0.7f);
@ -166,10 +201,10 @@ void Avatar::render(bool forceRenderHead) {
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
renderBody(forceRenderHead);
}
// render sphere when far away
const float MAX_ANGLE = 10.f;
float height = getHeight();
float height = getSkeletonHeight();
glm::vec3 delta = height * (getHead()->getCameraOrientation() * IDENTITY_UP) / 2.f;
float angle = abs(angleBetween(toTarget + delta, toTarget - delta));
@ -182,13 +217,15 @@ void Avatar::render(bool forceRenderHead) {
glPopMatrix();
}
}
const float DISPLAYNAME_DISTANCE = 4.0f;
setShowDisplayName(lengthToTarget < DISPLAYNAME_DISTANCE);
renderDisplayName();
if (!_chatMessage.empty()) {
int width = 0;
int lastWidth = 0;
for (string::iterator it = _chatMessage.begin(); it != _chatMessage.end(); it++) {
width += (lastWidth = textRenderer()->computeWidth(*it));
width += (lastWidth = textRenderer(CHAT)->computeWidth(*it));
}
glPushMatrix();
@ -207,7 +244,7 @@ void Avatar::render(bool forceRenderHead) {
glDisable(GL_LIGHTING);
glDepthMask(false);
if (_keyState == NO_KEY_DOWN) {
textRenderer()->draw(-width / 2.0f, 0, _chatMessage.c_str());
textRenderer(CHAT)->draw(-width / 2.0f, 0, _chatMessage.c_str());
} else {
// rather than using substr and allocating a new string, just replace the last
@ -215,10 +252,10 @@ void Avatar::render(bool forceRenderHead) {
int lastIndex = _chatMessage.size() - 1;
char lastChar = _chatMessage[lastIndex];
_chatMessage[lastIndex] = '\0';
textRenderer()->draw(-width / 2.0f, 0, _chatMessage.c_str());
textRenderer(CHAT)->draw(-width / 2.0f, 0, _chatMessage.c_str());
_chatMessage[lastIndex] = lastChar;
glColor3f(0, 1, 0);
textRenderer()->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex);
textRenderer(CHAT)->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex);
}
glEnable(GL_LIGHTING);
glDepthMask(true);
@ -254,6 +291,93 @@ void Avatar::renderBody(bool forceRenderHead) {
getHand()->render(false);
}
void Avatar::renderDisplayName() {
if (_displayName.isEmpty() || _displayNameAlpha == 0.0f) {
return;
}
glDisable(GL_LIGHTING);
glPushMatrix();
glm::vec3 textPosition = getPosition() + getBodyUpDirection() * ((getSkeletonHeight() + getHeadHeight()) / 1.5f);
glTranslatef(textPosition.x, textPosition.y, textPosition.z);
// we need "always facing camera": we must remove the camera rotation from the stack
glm::quat rotation = Application::getInstance()->getCamera()->getRotation();
glm::vec3 axis = glm::axis(rotation);
glRotatef(glm::angle(rotation), axis.x, axis.y, axis.z);
// We need to compute the scale factor such as the text remains with fixed size respect to window coordinates
// We project a unit vector and check the difference in screen coordinates, to check which is the
// correction scale needed
// save the matrices for later scale correction factor
glm::dmat4 modelViewMatrix;
glm::dmat4 projectionMatrix;
GLint viewportMatrix[4];
Application::getInstance()->getModelViewMatrix(&modelViewMatrix);
Application::getInstance()->getProjectionMatrix(&projectionMatrix);
glGetIntegerv(GL_VIEWPORT, viewportMatrix);
GLdouble result0[3], result1[3];
glm::dvec3 upVector(modelViewMatrix[1]);
glm::dvec3 testPoint0 = glm::dvec3(textPosition);
glm::dvec3 testPoint1 = glm::dvec3(textPosition) + upVector;
bool success;
success = gluProject(testPoint0.x, testPoint0.y, testPoint0.z,
(GLdouble*)&modelViewMatrix, (GLdouble*)&projectionMatrix, viewportMatrix,
&result0[0], &result0[1], &result0[2]);
success = success &&
gluProject(testPoint1.x, testPoint1.y, testPoint1.z,
(GLdouble*)&modelViewMatrix, (GLdouble*)&projectionMatrix, viewportMatrix,
&result1[0], &result1[1], &result1[2]);
if (success) {
double textWindowHeight = abs(result1[1] - result0[1]);
float scaleFactor = (textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f;
glScalef(scaleFactor, scaleFactor, 1.0);
// draw a gray background
QFontMetrics metrics = textRenderer(DISPLAYNAME)->metrics();
int bottom = -metrics.descent(), top = bottom + metrics.height();
int left = -_displayNameWidth/2, right = _displayNameWidth/2;
const int border = 5;
bottom -= border;
left -= border;
top += border;
right += border;
// We are drawing coplanar textures with depth: need the polygon offset
glEnable(GL_POLYGON_OFFSET_FILL);
glPolygonOffset(1.0f, 1.0f);
glColor4f(0.2f, 0.2f, 0.2f, _displayNameAlpha);
glBegin(GL_QUADS);
glVertex2f(left, bottom);
glVertex2f(right, bottom);
glVertex2f(right, top);
glVertex2f(left, top);
glEnd();
glScalef(1.0f, -1.0f, 1.0f); // TextRenderer::draw paints the text upside down in y axis
glColor4f(0.93f, 0.93f, 0.93f, _displayNameAlpha);
QByteArray ba = _displayName.toLocal8Bit();
const char* text = ba.data();
glDisable(GL_POLYGON_OFFSET_FILL);
textRenderer(DISPLAYNAME)->draw(-_displayNameWidth / 2, 0, text);
}
glPopMatrix();
glEnable(GL_LIGHTING);
}
bool Avatar::findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance) const {
float minDistance = FLT_MAX;
float modelDistance;
@ -363,6 +487,15 @@ void Avatar::setSkeletonModelURL(const QUrl &skeletonModelURL) {
_skeletonModel.setURL(_skeletonModelURL, DEFAULT_SKELETON_MODEL_URL);
}
void Avatar::setDisplayName(const QString& displayName) {
AvatarData::setDisplayName(displayName);
int width = 0;
for (int i = 0; i < displayName.size(); i++) {
width += (textRenderer(DISPLAYNAME)->computeWidth(displayName[i].toLatin1()));
}
_displayNameWidth = width;
}
int Avatar::parseData(const QByteArray& packet) {
// change in position implies movement
glm::vec3 oldPosition = _position;
@ -448,11 +581,16 @@ void Avatar::setScale(float scale) {
}
}
float Avatar::getHeight() const {
float Avatar::getSkeletonHeight() const {
Extents extents = _skeletonModel.getBindExtents();
return extents.maximum.y - extents.minimum.y;
}
float Avatar::getHeadHeight() const {
Extents extents = getHead()->getFaceModel().getBindExtents();
return extents.maximum.y - extents.minimum.y;
}
bool Avatar::collisionWouldMoveAvatar(CollisionInfo& collision) const {
if (!collision._data || collision._type != MODEL_COLLISION) {
return false;
@ -491,3 +629,21 @@ float Avatar::getPelvisToHeadLength() const {
return glm::distance(_position, getHead()->getPosition());
}
void Avatar::setShowDisplayName(bool showDisplayName) {
// For myAvatar, the alpha update is not done (called in simulate for other avatars)
if (Application::getInstance()->getAvatar() == this) {
if (showDisplayName) {
_displayNameAlpha = DISPLAYNAME_ALPHA;
} else {
_displayNameAlpha = 0.0f;
}
}
if (showDisplayName) {
_displayNameTargetAlpha = DISPLAYNAME_ALPHA;
} else {
_displayNameTargetAlpha = 0.0f;
}
}

View file

@ -113,18 +113,23 @@ public:
virtual void setFaceModelURL(const QUrl& faceModelURL);
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
virtual void setDisplayName(const QString& displayName);
void setShowDisplayName(bool showDisplayName);
int parseData(const QByteArray& packet);
static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2);
/// \return true if we expect the avatar would move as a result of the collision
bool collisionWouldMoveAvatar(CollisionInfo& collision) const;
/// \param collision a data structure for storing info about collisions against Models
void applyCollision(CollisionInfo& collision);
float getBoundingRadius() const { return 0.5f * getHeight(); }
float getBoundingRadius() const { return 0.5f * getSkeletonHeight(); }
public slots:
void updateCollisionFlags();
@ -154,7 +159,8 @@ protected:
glm::quat computeRotationFromBodyToWorldUp(float proportion = 1.0f) const;
void setScale(float scale);
float getHeight() const;
float getSkeletonHeight() const;
float getHeadHeight() const;
float getPelvisFloatingHeight() const;
float getPelvisToHeadLength() const;
@ -163,6 +169,8 @@ private:
bool _initialized;
void renderBody(bool forceRenderHead);
void renderDisplayName();
};
#endif

View file

@ -5,6 +5,9 @@
// Created by Stephen Birarda on 1/23/2014.
// Copyright (c) 2014 HighFidelity, Inc. All rights reserved.
//
#include <string>
#include <glm/gtx/string_cast.hpp>
#include <PerfStat.h>
#include <UUID.h>
@ -71,6 +74,8 @@ void AvatarManager::renderAvatars(bool forceRenderHead, bool selfAvatarOnly) {
"Application::renderAvatars()");
bool renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::LookAtVectors);
if (!selfAvatarOnly) {
foreach (const AvatarSharedPointer& avatarPointer, _avatarHash) {
Avatar* avatar = static_cast<Avatar*>(avatarPointer.data());
@ -184,8 +189,9 @@ void AvatarManager::processAvatarIdentityPacket(const QByteArray &packet) {
while (!identityStream.atEnd()) {
QUrl faceMeshURL, skeletonURL;
identityStream >> nodeUUID >> faceMeshURL >> skeletonURL;
QString displayName;
identityStream >> nodeUUID >> faceMeshURL >> skeletonURL >> displayName;
// mesh URL for a UUID, find avatar in our list
AvatarSharedPointer matchingAvatar = _avatarHash.value(nodeUUID);
if (matchingAvatar) {
@ -198,6 +204,10 @@ void AvatarManager::processAvatarIdentityPacket(const QByteArray &packet) {
if (avatar->getSkeletonModelURL() != skeletonURL) {
avatar->setSkeletonModelURL(skeletonURL);
}
if (avatar->getDisplayName() != displayName) {
avatar->setDisplayName(displayName);
}
}
}
}

View file

@ -198,7 +198,7 @@ void MyAvatar::simulate(float deltaTime) {
if (_collisionFlags != 0) {
Camera* myCamera = Application::getInstance()->getCamera();
float radius = getHeight() * COLLISION_RADIUS_SCALE;
float radius = getSkeletonHeight() * COLLISION_RADIUS_SCALE;
if (myCamera->getMode() == CAMERA_MODE_FIRST_PERSON && !OculusManager::isConnected()) {
radius = myCamera->getAspectRatio() * (myCamera->getNearClip() / cos(myCamera->getFieldOfView() / 2.f));
radius *= COLLISION_RADIUS_SCALAR;
@ -610,6 +610,7 @@ void MyAvatar::saveData(QSettings* settings) {
settings->setValue("faceModelURL", _faceModelURL);
settings->setValue("skeletonModelURL", _skeletonModelURL);
settings->setValue("displayName", _displayName);
settings->endGroup();
}
@ -637,6 +638,7 @@ void MyAvatar::loadData(QSettings* settings) {
setFaceModelURL(settings->value("faceModelURL").toUrl());
setSkeletonModelURL(settings->value("skeletonModelURL").toUrl());
setDisplayName(settings->value("displayName").toString());
settings->endGroup();
}
@ -689,7 +691,9 @@ void MyAvatar::updateLookAtTargetAvatar(glm::vec3 &eyePosition) {
(avatar->getScale() / avatar->getHead()->getScale()) + avatar->getHead()->getScalePivot();
_lookAtTargetAvatar = avatarPointer;
return;
} else {
}
}
_lookAtTargetAvatar.clear();
}
@ -854,7 +858,7 @@ void MyAvatar::updateCollisionWithEnvironment(float deltaTime, float radius) {
float pelvisFloatingHeight = getPelvisFloatingHeight();
if (Application::getInstance()->getEnvironment()->findCapsulePenetration(
_position - up * (pelvisFloatingHeight - radius),
_position + up * (getHeight() - pelvisFloatingHeight + radius), radius, penetration)) {
_position + up * (getSkeletonHeight() - pelvisFloatingHeight + radius), radius, penetration)) {
_lastCollisionPosition = _position;
updateCollisionSound(penetration, deltaTime, ENVIRONMENT_COLLISION_FREQUENCY);
applyHardCollision(penetration, ENVIRONMENT_SURFACE_ELASTICITY, ENVIRONMENT_SURFACE_DAMPING);
@ -869,7 +873,7 @@ void MyAvatar::updateCollisionWithVoxels(float deltaTime, float radius) {
float pelvisFloatingHeight = getPelvisFloatingHeight();
if (Application::getInstance()->getVoxels()->findCapsulePenetration(
_position - glm::vec3(0.0f, pelvisFloatingHeight - radius, 0.0f),
_position + glm::vec3(0.0f, getHeight() - pelvisFloatingHeight + radius, 0.0f), radius, penetration)) {
_position + glm::vec3(0.0f, getSkeletonHeight() - pelvisFloatingHeight + radius, 0.0f), radius, penetration)) {
_lastCollisionPosition = _position;
updateCollisionSound(penetration, deltaTime, VOXEL_COLLISION_FREQUENCY);
applyHardCollision(penetration, VOXEL_ELASTICITY, VOXEL_DAMPING);

View file

@ -27,7 +27,7 @@ public:
QString getUserString() const;
const QString& getUsername() const { return _username; }
void setUUID(const QUuid& uuid) { _uuid = uuid; }
const QUuid& getUUID() { return _uuid; }
@ -45,6 +45,8 @@ public:
private:
void setUsername(const QString& username);
void setDisplayName(const QString& displaName);
QString _username;
QUuid _uuid;

View file

@ -35,7 +35,10 @@ AvatarData::AvatarData() :
_keyState(NO_KEY_DOWN),
_isChatCirclingEnabled(false),
_headData(NULL),
_handData(NULL)
_handData(NULL),
_displayNameWidth(0),
_displayNameTargetAlpha(0.0f),
_displayNameAlpha(0.0f)
{
}
@ -270,7 +273,8 @@ bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray &packet) {
QUuid avatarUUID;
QUrl faceModelURL, skeletonModelURL;
packetStream >> avatarUUID >> faceModelURL >> skeletonModelURL;
QString displayName;
packetStream >> avatarUUID >> faceModelURL >> skeletonModelURL >> displayName;
bool hasIdentityChanged = false;
@ -283,15 +287,20 @@ bool AvatarData::hasIdentityChangedAfterParsing(const QByteArray &packet) {
setSkeletonModelURL(skeletonModelURL);
hasIdentityChanged = true;
}
if (displayName != _displayName) {
setDisplayName(displayName);
hasIdentityChanged = true;
}
return hasIdentityChanged;
}
QByteArray AvatarData::identityByteArray() {
QByteArray identityData;
QDataStream identityStream(&identityData, QIODevice::Append);
identityStream << QUuid() << _faceModelURL << _skeletonModelURL;
identityStream << QUuid() << _faceModelURL << _skeletonModelURL << _displayName;
return identityData;
}
@ -308,6 +317,13 @@ void AvatarData::setSkeletonModelURL(const QUrl& skeletonModelURL) {
qDebug() << "Changing skeleton model for avatar to" << _skeletonModelURL.toString();
}
void AvatarData::setDisplayName(const QString& displayName) {
_displayName = displayName;
qDebug() << "Changing display name for avatar to" << displayName;
}
void AvatarData::setClampedTargetScale(float targetScale) {
targetScale = glm::clamp(targetScale, MIN_AVATAR_SCALE, MAX_AVATAR_SCALE);

View file

@ -150,11 +150,13 @@ public:
const QUrl& getFaceModelURL() const { return _faceModelURL; }
const QUrl& getSkeletonModelURL() const { return _skeletonModelURL; }
const QString& getDisplayName() const { return _displayName; }
virtual void setFaceModelURL(const QUrl& faceModelURL);
virtual void setSkeletonModelURL(const QUrl& skeletonModelURL);
virtual float getBoundingRadius() const { return 1.f; }
virtual void setDisplayName(const QString& displayName);
virtual float getBoundingRadius() const { return 1.f; }
protected:
glm::vec3 _position;
glm::vec3 _handPosition;
@ -183,6 +185,12 @@ protected:
QUrl _faceModelURL;
QUrl _skeletonModelURL;
QString _displayName;
int _displayNameWidth;
float _displayNameTargetAlpha;
float _displayNameAlpha;
private:
// privatize the copy constructor and assignment operator so they cannot be called
AvatarData(const AvatarData&);