From af48998cc783ddf60d6ee3e8eeed53923abd9e02 Mon Sep 17 00:00:00 2001 From: Jose Carlos Date: Sat, 15 Feb 2014 18:40:36 +0100 Subject: [PATCH] Fixed position of display name: we take into account skeleton and head's height Saved opengl state in renderDisplayName Moved display data to AvatarData Unified static chat function for chat and display name --- interface/src/avatar/Avatar.cpp | 99 +++++++++++++++------------- interface/src/avatar/Avatar.h | 9 +-- interface/src/avatar/MyAvatar.cpp | 10 +-- libraries/avatars/src/AvatarData.cpp | 4 +- libraries/avatars/src/AvatarData.h | 4 ++ 5 files changed, 70 insertions(+), 56 deletions(-) diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 837c77b970..21aee11936 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -75,9 +75,7 @@ Avatar::Avatar() : _moving(false), _owningAvatarMixer(), _collisionFlags(0), - _initialized(false), - _displayNameWidth(0), - _isShowDisplayName(false) + _initialized(false) { // we may have been created in the network thread, but we live in the main thread moveToThread(Application::getInstance()->thread()); @@ -148,14 +146,23 @@ void Avatar::setMouseRay(const glm::vec3 &origin, const glm::vec3 &direction) { _mouseRayDirection = direction; } -static TextRenderer* chatTextRenderer() { - static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 24, -1, false, TextRenderer::SHADOW_EFFECT); - return renderer; -} +enum TextRendererType { + CHAT, + DISPLAYNAME +}; -static TextRenderer* displayNameTextRenderer() { - static TextRenderer* renderer = new TextRenderer(SANS_FONT_FAMILY, 12, -1, false, TextRenderer::SHADOW_EFFECT); - return renderer; +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) { @@ -177,7 +184,7 @@ void Avatar::render(bool forceRenderHead) { // render sphere when far away const float MAX_ANGLE = 10.f; - float height = getHeight(); + float height = getSkeletonHeight(); glm::vec3 delta = height * (_head.getCameraOrientation() * IDENTITY_UP) / 2.f; float angle = abs(angleBetween(toTarget + delta, toTarget - delta)); @@ -200,7 +207,7 @@ void Avatar::render(bool forceRenderHead) { int width = 0; int lastWidth = 0; for (string::iterator it = _chatMessage.begin(); it != _chatMessage.end(); it++) { - width += (lastWidth = chatTextRenderer()->computeWidth(*it)); + width += (lastWidth = textRenderer(CHAT)->computeWidth(*it)); } glPushMatrix(); @@ -219,7 +226,7 @@ void Avatar::render(bool forceRenderHead) { glDisable(GL_LIGHTING); glDepthMask(false); if (_keyState == NO_KEY_DOWN) { - chatTextRenderer()->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 @@ -227,10 +234,10 @@ void Avatar::render(bool forceRenderHead) { int lastIndex = _chatMessage.size() - 1; char lastChar = _chatMessage[lastIndex]; _chatMessage[lastIndex] = '\0'; - chatTextRenderer()->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); - chatTextRenderer()->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); @@ -267,38 +274,32 @@ void Avatar::renderBody(bool forceRenderHead) { } void Avatar::renderDisplayName() { - QString displayName; if (_displayName.isEmpty()) { displayName = "test string"; // just for debugging } else { displayName = _displayName; } - - glm::vec3 textPosition = getPosition() + getBodyUpDirection() * getHeight(); // Scale is already considered in getHeight + + glm::vec3 textPosition = getPosition() + getBodyUpDirection() * (getSkeletonHeight() + getHeadHeight()); glPushMatrix(); + + // save opengl state + GLboolean isDepthMaskEnabled; + glGetBooleanv(GL_DEPTH_WRITEMASK, &isDepthMaskEnabled); + GLboolean isLightingEnabled = glIsEnabled(GL_LIGHTING); + glDepthMask(false); glDisable(GL_LIGHTING); - - // Set the correct modelview matrix: set the identity matrix in the rotation part - // [R|t1] = current modelview matrix (the camera rotation and translation) - // [I|t2] = the translation for the text - // We want this final model view matrix: [I | t1 + R*t2] + glm::dmat4 modelViewMatrix2; glGetDoublev(GL_MODELVIEW_MATRIX, (GLdouble*)&modelViewMatrix2); glTranslatef(textPosition.x, textPosition.y, textPosition.z); - // Extract rotation matrix from the modelview matrix - glm::dmat4 modelViewMatrix; - glGetDoublev(GL_MODELVIEW_MATRIX, (GLdouble*)&modelViewMatrix); - - // Delete rotation info - modelViewMatrix[0][0] = modelViewMatrix[1][1] = modelViewMatrix[2][2] = 1.0; - modelViewMatrix[0][1] = modelViewMatrix[0][2] = 0.0; - modelViewMatrix[1][0] = modelViewMatrix[1][2] = 0.0; - modelViewMatrix[2][0] = modelViewMatrix[2][1] = 0.0; - glLoadMatrixd((GLdouble*)&modelViewMatrix); // Override current matrix with our own - + // 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 y = 0 and y = 1 and check the difference in projection coordinates @@ -328,8 +329,8 @@ void Avatar::renderDisplayName() { float scaleFactor = (textWindowHeight > EPSILON) ? 1.0f / textWindowHeight : 1.0f; glScalef(scaleFactor, scaleFactor, 1.0); - // draw a gray background so that we can actually see what we're typing - QFontMetrics metrics = displayNameTextRenderer()->metrics(); + // draw a gray background + QFontMetrics metrics = textRenderer(DISPLAYNAME)->metrics(); int bottom = -metrics.descent(), top = bottom + metrics.height(); int left = -_displayNameWidth/2, right = _displayNameWidth/2; int border = 5; @@ -338,7 +339,7 @@ void Avatar::renderDisplayName() { top += border; right += border; - glColor3f(0.2f, 0.2f, 0.2f); + glColor4f(0.2f, 0.2f, 0.2f, 0.95f); glBegin(GL_QUADS); glVertex2f(left, bottom); glVertex2f(right, bottom); @@ -346,16 +347,21 @@ void Avatar::renderDisplayName() { glVertex2f(left, top); glEnd(); - glScalef(1.0f, -1.0f, 1.0f); // TextRenderer::draw paints the text upside down in y axis - glColor3f(0.93f, 0.93f, 0.93f); + glColor4f(0.93f, 0.93f, 0.93f, 0.95f); QByteArray ba = displayName.toLocal8Bit(); const char *text = ba.data(); - displayNameTextRenderer()->draw(-_displayNameWidth/2.0, 0, text); + textRenderer(DISPLAYNAME)->draw(-_displayNameWidth/2.0, 0, text); + } + + // restore state + if (isLightingEnabled) { + glEnable(GL_LIGHTING); + } + if (isDepthMaskEnabled) { + glDepthMask(true); } - glEnable(GL_LIGHTING); - glDepthMask(true); glPopMatrix(); } @@ -466,7 +472,7 @@ void Avatar::setDisplayName(const QString& displayName) { AvatarData::setDisplayName(displayName); int width = 0; for (int i = 0; i < displayName.size(); i++) { - width += (displayNameTextRenderer()->computeWidth(displayName[i].toLatin1())); + width += (textRenderer(DISPLAYNAME)->computeWidth(displayName[i].toLatin1())); } _displayNameWidth = width; } @@ -556,11 +562,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 = _head.getFaceModel().getBindExtents(); + return extents.maximum.y - extents.minimum.y; +} + bool Avatar::collisionWouldMoveAvatar(ModelCollisionInfo& collision) const { // ATM only the Skeleton is pokeable // TODO: make poke affect head diff --git a/interface/src/avatar/Avatar.h b/interface/src/avatar/Avatar.h index 19e720f771..5c19b8b60f 100755 --- a/interface/src/avatar/Avatar.h +++ b/interface/src/avatar/Avatar.h @@ -130,7 +130,9 @@ public: static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2); - float getHeight() const; + float getSkeletonHeight() const; + + float getHeadHeight() const; /// \return true if we expect the avatar would move as a result of the collision bool collisionWouldMoveAvatar(ModelCollisionInfo& collision) const; @@ -178,11 +180,6 @@ private: bool _initialized; - int _displayNameWidth; - bool _isShowDisplayName; - - - void renderBody(bool forceRenderHead); void renderDisplayName(); diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index c97cc96ea8..72ab283da8 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -197,7 +197,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; @@ -840,7 +840,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); @@ -855,7 +855,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); @@ -962,7 +962,7 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { // no need to compute a bunch of stuff if we have one or fewer avatars return; } - float myBoundingRadius = 0.5f * getHeight(); + float myBoundingRadius = 0.5f * getSkeletonHeight(); // HACK: body-body collision uses two coaxial capsules with axes parallel to y-axis // TODO: make the collision work without assuming avatar orientation @@ -982,7 +982,7 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) { if (_distanceToNearestAvatar > distance) { _distanceToNearestAvatar = distance; } - float theirBoundingRadius = 0.5f * avatar->getHeight(); + float theirBoundingRadius = 0.5f * avatar->getSkeletonHeight(); if (distance < myBoundingRadius + theirBoundingRadius) { Extents theirStaticExtents = _skeletonModel.getStaticExtents(); glm::vec3 staticScale = theirStaticExtents.maximum - theirStaticExtents.minimum; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 548129b871..5a71f7c3d2 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -35,7 +35,9 @@ AvatarData::AvatarData() : _keyState(NO_KEY_DOWN), _isChatCirclingEnabled(false), _headData(NULL), - _handData(NULL) + _handData(NULL), + _displayNameWidth(0), + _isShowDisplayName(false) { } diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index f5d9da2447..6b3de797bb 100755 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -182,6 +182,10 @@ protected: QUrl _faceModelURL; QUrl _skeletonModelURL; QString _displayName; + + int _displayNameWidth; + bool _isShowDisplayName; + private: // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&);