From 78b614f8553d956de855ddda35a275ad123350d1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Mon, 16 Mar 2015 16:24:32 -0700 Subject: [PATCH 001/177] move avatar details into CharacterController --- libraries/physics/src/CharacterController.cpp | 254 +++++++++++------- libraries/physics/src/CharacterController.h | 24 +- libraries/physics/src/PhysicsEngine.cpp | 125 +++------ libraries/physics/src/PhysicsEngine.h | 3 - 4 files changed, 200 insertions(+), 206 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 5173b368c1..994c95e074 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -16,10 +16,9 @@ subject to the following restrictions: */ -//#include <stdio.h> - #include "BulletCollision/CollisionDispatch/btGhostObject.h" +#include "BulletUtil.h" #include "CharacterController.h" @@ -64,8 +63,7 @@ btCollisionObject* m_me; }; */ -class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback -{ +class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: btKinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot) : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) @@ -111,16 +109,14 @@ protected: * * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html */ -btVector3 CharacterController::computeReflectionDirection(const btVector3& direction, const btVector3& normal) -{ +btVector3 CharacterController::computeReflectionDirection(const btVector3& direction, const btVector3& normal) { return direction - (btScalar(2.0) * direction.dot(normal)) * normal; } /* * Returns the portion of 'direction' that is parallel to 'normal' */ -btVector3 CharacterController::parallelComponent(const btVector3& direction, const btVector3& normal) -{ +btVector3 CharacterController::parallelComponent(const btVector3& direction, const btVector3& normal) { btScalar magnitude = direction.dot(normal); return normal * magnitude; } @@ -128,36 +124,34 @@ btVector3 CharacterController::parallelComponent(const btVector3& direction, con /* * Returns the portion of 'direction' that is perpindicular to 'normal' */ -btVector3 CharacterController::perpindicularComponent(const btVector3& direction, const btVector3& normal) -{ +btVector3 CharacterController::perpindicularComponent(const btVector3& direction, const btVector3& normal) { return direction - parallelComponent(direction, normal); } -CharacterController::CharacterController( - btPairCachingGhostObject* ghostObject, - btConvexShape* convexShape, - btScalar stepHeight, - int upAxis) { - m_upAxis = upAxis; - m_addedMargin = 0.02; - m_walkDirection.setValue(0,0,0); +CharacterController::CharacterController(AvatarData* avatarData) { + assert(avatarData); + m_avatarData = avatarData; + + createShapeAndGhost(); + + m_upAxis = 1; // HACK: hard coded to be 1 for now (yAxis) + + m_addedMargin = 0.02f; + m_walkDirection.setValue(0.0f,0.0f,0.0f); m_useGhostObjectSweepTest = true; - m_ghostObject = ghostObject; - m_stepHeight = stepHeight; - m_turnAngle = btScalar(0.0); - m_convexShape = convexShape; + m_turnAngle = btScalar(0.0f); m_useWalkDirection = true; // use walk direction by default, legacy behavior - m_velocityTimeInterval = 0.0; - m_verticalVelocity = 0.0; - m_verticalOffset = 0.0; - m_gravity = 9.8 * 3 ; // 3G acceleration. - m_fallSpeed = 55.0; // Terminal velocity of a sky diver in m/s. - m_jumpSpeed = 10.0; // ? + m_velocityTimeInterval = 0.0f; + m_verticalVelocity = 0.0f; + m_verticalOffset = 0.0f; + m_gravity = 9.8f; + m_maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s. + m_jumpSpeed = 10.0f; // ? m_wasOnGround = false; m_wasJumping = false; m_interpolateUp = true; - setMaxSlope(btRadians(45.0)); - m_currentStepOffset = 0; + setMaxSlope(btRadians(45.0f)); + m_currentStepOffset = 0.0f; // internal state data members full_drop = false; @@ -226,8 +220,6 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl } m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2); penetration = true; - } else { - //printf("touching %f\n", dist); } } @@ -237,14 +229,13 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl btTransform newTrans = m_ghostObject->getWorldTransform(); newTrans.setOrigin(m_currentPosition); m_ghostObject->setWorldTransform(newTrans); - //printf("m_touchingNormal = %f,%f,%f\n", m_touchingNormal[0], m_touchingNormal[1], m_touchingNormal[2]); return penetration; } void CharacterController::stepUp( btCollisionWorld* world) { // phase 1: up btTransform start, end; - m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.f?m_verticalOffset:0.f)); + m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.0f ? m_verticalOffset : 0.0f)); start.setIdentity(); end.setIdentity(); @@ -301,22 +292,17 @@ void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& //if (tangentMag != 0.0) { if (0) { btVector3 parComponent = parallelDir * btScalar(tangentMag*movementLength); - //printf("parComponent=%f,%f,%f\n", parComponent[0], parComponent[1], parComponent[2]); m_targetPosition += parComponent; } if (normalMag != 0.0) { btVector3 perpComponent = perpindicularDir * btScalar(normalMag*movementLength); - //printf("perpComponent=%f,%f,%f\n", perpComponent[0], perpComponent[1], perpComponent[2]); m_targetPosition += perpComponent; } - } else { - //printf("movementLength don't normalize a zero vector\n"); } } void CharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld, const btVector3& walkMove) { - //printf("m_normalizedDirection=%f,%f,%f\n", // m_normalizedDirection[0], m_normalizedDirection[1], m_normalizedDirection[2]); // phase 2: forward and strafe btTransform start, end; @@ -327,7 +313,6 @@ void CharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld btScalar fraction = 1.0; btScalar distance2 = (m_currentPosition-m_targetPosition).length2(); - //printf("distance2=%f\n", distance2); if (m_touchingContact) { if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0)) { @@ -380,7 +365,6 @@ void CharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld break; } } else { - //printf("currentDir: don't normalize a zero vector\n"); break; } } else { @@ -388,7 +372,7 @@ void CharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld m_currentPosition = m_targetPosition; } - //if (callback.m_closestHitFraction == 0.f) { + //if (callback.m_closestHitFraction == 0.0f) { // break; //} @@ -397,24 +381,23 @@ void CharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar dt) { btTransform start, end, end_double; - bool runonce = false; + bool runOnce = false; // phase 3: down /*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0; btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + additionalDownStep); - btScalar downVelocity = (additionalDownStep == 0.0 && m_verticalVelocity<0.0?-m_verticalVelocity:0.0) * dt; - btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * downVelocity; + btScalar downSpeed = (additionalDownStep == 0.0 && m_verticalVelocity < 0.0 ? -m_verticalVelocity : 0.0); + btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * downSpeed; m_targetPosition -= (step_drop + gravity_drop);*/ btVector3 orig_position = m_targetPosition; - btScalar downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt; - - if (downVelocity > 0.0 && downVelocity > m_fallSpeed && (m_wasOnGround || !m_wasJumping)) { - downVelocity = m_fallSpeed; + btScalar downSpeed = (m_verticalVelocity < 0.0f) ? -m_verticalVelocity : 0.0f; + if (downSpeed > 0.0f && downSpeed > m_maxFallSpeed && (m_wasOnGround || !m_wasJumping)) { + downSpeed = m_maxFallSpeed; } - btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity); + btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downSpeed * dt); m_targetPosition -= step_drop; btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine); @@ -453,7 +436,7 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d } } - btScalar downVelocity2 = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt; + btScalar downDistance = (m_verticalVelocity < 0.0f ? -m_verticalVelocity : 0.0f) * dt; bool has_hit = false; if(bounce_fix == true) { has_hit = callback.hasHit() || callback2.hasHit(); @@ -461,29 +444,25 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d has_hit = callback2.hasHit(); } - if(downVelocity2 > 0.0 && downVelocity2 < m_stepHeight && has_hit == true && runonce == false + if(downDistance > 0.0 && downDistance < m_stepHeight && has_hit == true && runOnce == false && (m_wasOnGround || !m_wasJumping)) { //redo the velocity calculation when falling a small amount, for fast stairs motion //for larger falls, use the smoother/slower interpolated movement by not touching the target position m_targetPosition = orig_position; - downVelocity = m_stepHeight; - - btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity); + btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + m_stepHeight); m_targetPosition -= step_drop; - runonce = true; + runOnce = true; continue; //re-run previous tests } break; } - if (callback.hasHit() || runonce == true) { + if (callback.hasHit() || runOnce == true) { // we dropped a fraction of the height -> hit floor btScalar fraction = (m_currentPosition.getY() - callback.m_hitPointWorld.getY()) / 2; - //printf("hitpoint: %g - pos %g\n", callback.m_hitPointWorld.getY(), m_currentPosition.getY()); - if (bounce_fix == true) { if (full_drop == true) { m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); @@ -502,39 +481,28 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d m_wasJumping = false; } else { // we dropped the full height - full_drop = true; if (bounce_fix == true) { - downVelocity = (m_verticalVelocity<0.f?-m_verticalVelocity:0.f) * dt; - if (downVelocity > m_fallSpeed && (m_wasOnGround || !m_wasJumping)) { + downSpeed = (m_verticalVelocity < 0.0f) ? -m_verticalVelocity : 0.0f; + if (downSpeed > m_maxFallSpeed && (m_wasOnGround || !m_wasJumping)) { m_targetPosition += step_drop; //undo previous target change - downVelocity = m_fallSpeed; - step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downVelocity); + // use fallSpeed instead of downSpeed + step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + m_maxFallSpeed * dt); m_targetPosition -= step_drop; } } - //printf("full drop - %g, %g\n", m_currentPosition.getY(), m_targetPosition.getY()); - m_currentPosition = m_targetPosition; } } - - void CharacterController::setWalkDirection(const btVector3& walkDirection) { m_useWalkDirection = true; m_walkDirection = walkDirection; m_normalizedDirection = getNormalizedVector(m_walkDirection); } - - void CharacterController::setVelocityForTimeInterval(const btVector3& velocity, btScalar timeInterval) { - //printf("setVelocity!\n"); - //printf(" interval: %f\n", timeInterval); - //printf(" velocity: (%f, %f, %f)\n", velocity.x(), velocity.y(), velocity.z()); - m_useWalkDirection = false; m_walkDirection = velocity; m_normalizedDirection = getNormalizedVector(m_walkDirection); @@ -571,23 +539,16 @@ void CharacterController::preStep( btCollisionWorld* collisionWorld) { numPenetrationLoops++; m_touchingContact = true; if (numPenetrationLoops > 4) { - //printf("character could not recover from penetration = %d\n", numPenetrationLoops); break; } } m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); m_targetPosition = m_currentPosition; - //printf("m_targetPosition=%f,%f,%f\n", m_targetPosition[0], m_targetPosition[1], m_targetPosition[2]); } void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScalar dt) { - //printf("playerStep(): "); - //printf(" dt = %f", dt); - - // quick check... if (!m_useWalkDirection && m_velocityTimeInterval <= 0.0) { - //printf("\n"); return; // no motion } @@ -595,49 +556,36 @@ void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScala // Update fall velocity. m_verticalVelocity -= m_gravity * dt; - if (m_verticalVelocity > 0.0 && m_verticalVelocity > m_jumpSpeed) { + if (m_verticalVelocity > m_jumpSpeed) { m_verticalVelocity = m_jumpSpeed; - } - if (m_verticalVelocity < 0.0 && btFabs(m_verticalVelocity) > btFabs(m_fallSpeed)) { - m_verticalVelocity = -btFabs(m_fallSpeed); + } else if (m_verticalVelocity < -m_maxFallSpeed) { + m_verticalVelocity = -m_maxFallSpeed; } m_verticalOffset = m_verticalVelocity * dt; - btTransform xform; xform = m_ghostObject->getWorldTransform(); - //printf("walkDirection(%f,%f,%f)\n", walkDirection[0], walkDirection[1], walkDirection[2]); - //printf("walkSpeed=%f\n", walkSpeed); - stepUp (collisionWorld); if (m_useWalkDirection) { stepForwardAndStrafe(collisionWorld, m_walkDirection); } else { - //printf(" time: %f", m_velocityTimeInterval); - // still have some time left for moving! - btScalar dtMoving = - (dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval; + // compute substep and decrement total interval + btScalar dtMoving = (dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval; m_velocityTimeInterval -= dt; - // how far will we move while we are moving? + // stepForward substep btVector3 move = m_walkDirection * dtMoving; - - //printf(" dtMoving: %f", dtMoving); - - // okay, step stepForwardAndStrafe(collisionWorld, move); } stepDown(collisionWorld, dt); - //printf("\n"); - xform.setOrigin(m_currentPosition); m_ghostObject->setWorldTransform(xform); } -void CharacterController::setFallSpeed(btScalar fallSpeed) { - m_fallSpeed = fallSpeed; +void CharacterController::setMaxFallSpeed(btScalar speed) { + m_maxFallSpeed = speed; } void CharacterController::setJumpSpeed(btScalar jumpSpeed) { @@ -662,7 +610,7 @@ void CharacterController::jump() { #if 0 currently no jumping. - btTransform xform; + btTransform xform; m_rigidBody->getMotionState()->getWorldTransform(xform); btVector3 up = xform.getBasis()[1]; up.normalize(); @@ -704,3 +652,103 @@ void CharacterController::debugDraw(btIDebugDraw* debugDrawer) { void CharacterController::setUpInterpolate(bool value) { m_interpolateUp = value; } + +// protected +void CharacterController::createShapeAndGhost() { + // get new dimensions from avatar + AABox box = m_avatarData->getLocalAABox(); + const glm::vec3& diagonal = box.getScale(); + float radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); + float halfHeight = 0.5f * diagonal.y - radius; + float MIN_HALF_HEIGHT = 0.1f; + if (halfHeight < MIN_HALF_HEIGHT) { + halfHeight = MIN_HALF_HEIGHT; + } + glm::vec3 offset = box.getCorner() + 0.5f * diagonal; + m_shapeLocalOffset = offset; + + const float MIN_STEP_HEIGHT = 0.35f; + m_stepHeight = glm::max(MIN_STEP_HEIGHT, radius + 0.5f * halfHeight); + + // create new shape + m_convexShape = new btCapsuleShape(radius, 2.0f * halfHeight); + + // create new ghost + m_ghostObject = new btPairCachingGhostObject(); + m_ghostObject->setWorldTransform(btTransform(glmToBullet(m_avatarData->getOrientation()), + glmToBullet(m_avatarData->getPosition()))); + m_ghostObject->setCollisionShape(m_convexShape); + m_ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); +} + +bool CharacterController::needsShapeUpdate() { + // get new dimensions from avatar + AABox box = m_avatarData->getLocalAABox(); + const glm::vec3& diagonal = box.getScale(); + float radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); + float halfHeight = 0.5f * diagonal.y - radius; + float MIN_HALF_HEIGHT = 0.1f; + if (halfHeight < MIN_HALF_HEIGHT) { + halfHeight = MIN_HALF_HEIGHT; + } + glm::vec3 offset = box.getCorner() + 0.5f * diagonal; + + // get old dimensions from shape + btCapsuleShape* capsule = static_cast<btCapsuleShape*>(m_convexShape); + btScalar oldRadius = capsule->getRadius(); + btScalar oldHalfHeight = capsule->getHalfHeight(); + + // compare dimensions (and offset) + float radiusDelta = glm::abs(radius - oldRadius); + float heightDelta = glm::abs(halfHeight - oldHalfHeight); + if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) { + // shape hasn't changed --> nothing to do + float offsetDelta = glm::distance(offset, m_shapeLocalOffset); + if (offsetDelta > FLT_EPSILON) { + // if only the offset changes then we can update it --> no need to rebuild shape + m_shapeLocalOffset = offset; + } + return false; + } + return true; +} + +void CharacterController::updateShape() { + // DANGER: make sure this CharacterController and its GhostShape have been removed from + // the PhysicsEngine before calling this. + + // delete shape and GhostObject + delete m_ghostObject; + m_ghostObject = NULL; + delete m_convexShape; + m_convexShape = NULL; + + createShapeAndGhost(); +} + +void CharacterController::preSimulation(btScalar timeStep) { + if (m_avatarData->isPhysicsEnabled()) { + m_avatarData->lockForRead(); + // update character controller + glm::quat rotation = m_avatarData->getOrientation(); + glm::vec3 position = m_avatarData->getPosition() + rotation * m_shapeLocalOffset; + m_ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); + + btVector3 walkVelocity = glmToBullet(m_avatarData->getVelocity()); + setVelocityForTimeInterval(walkVelocity, timeStep); + m_avatarData->unlock(); + } +} + +void CharacterController::postSimulation() { + if (m_avatarData->isPhysicsEnabled()) { + m_avatarData->lockForWrite(); + const btTransform& avatarTransform = m_ghostObject->getWorldTransform(); + glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); + glm::vec3 offset = rotation * m_shapeLocalOffset; + m_avatarData->setOrientation(rotation); + m_avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); + m_avatarData->unlock(); + } +} + diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 301253b2bd..8e1116f7ea 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -19,6 +19,8 @@ subject to the following restrictions: #ifndef hifi_CharacterController_h #define hifi_CharacterController_h +#include <AvatarData.h> + #include <btBulletDynamicsCommon.h> #include <BulletDynamics/Character/btCharacterControllerInterface.h> #include <BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h> @@ -39,14 +41,15 @@ ATTRIBUTE_ALIGNED16(class) CharacterController : public btCharacterControllerInt { protected: - btScalar m_halfHeight; - + AvatarData* m_avatarData = NULL; btPairCachingGhostObject* m_ghostObject; + glm::vec3 m_shapeLocalOffset; + btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast btScalar m_verticalVelocity; btScalar m_verticalOffset; - btScalar m_fallSpeed; + btScalar m_maxFallSpeed; btScalar m_jumpSpeed; btScalar m_maxJumpHeight; btScalar m_maxSlopeRadians; // Slope angle that is set (used for returning the exact value) @@ -95,15 +98,12 @@ protected: void updateTargetPositionBasedOnCollision(const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0)); void stepForwardAndStrafe(btCollisionWorld* collisionWorld, const btVector3& walkMove); void stepDown(btCollisionWorld* collisionWorld, btScalar dt); + void createShapeAndGhost(); public: BT_DECLARE_ALIGNED_ALLOCATOR(); - CharacterController( - btPairCachingGhostObject* ghostObject, - btConvexShape* convexShape, - btScalar stepHeight, - int upAxis = 1); + CharacterController(AvatarData* avatarData); ~CharacterController(); @@ -145,7 +145,7 @@ public: void preStep(btCollisionWorld* collisionWorld); void playerStep(btCollisionWorld* collisionWorld, btScalar dt); - void setFallSpeed(btScalar fallSpeed); + void setMaxFallSpeed(btScalar speed); void setJumpSpeed(btScalar jumpSpeed); void setMaxJumpHeight(btScalar maxJumpHeight); bool canJump() const; @@ -167,6 +167,12 @@ public: bool onGround() const; void setUpInterpolate(bool value); + + bool needsShapeUpdate(); + void updateShape(); + + void preSimulation(btScalar timeStep); + void postSimulation(); }; #endif // hifi_CharacterController_h diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 3e2fabfd89..ba42163a0a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -24,8 +24,7 @@ uint32_t PhysicsEngine::getNumSubsteps() { } PhysicsEngine::PhysicsEngine(const glm::vec3& offset) - : _originOffset(offset), - _avatarShapeLocalOffset(0.0f) { + : _originOffset(offset) { } PhysicsEngine::~PhysicsEngine() { @@ -277,9 +276,6 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) { } void PhysicsEngine::stepSimulation() { - // expect the engine to have an avatar (and hence: a character controller) - assert(_avatarData); - lock(); // NOTE: the grand order of operations is: // (1) relay incoming changes @@ -296,17 +292,11 @@ void PhysicsEngine::stepSimulation() { _clock.reset(); float timeStep = btMin(dt, MAX_TIMESTEP); - if (_avatarData->isPhysicsEnabled()) { - // update character controller - glm::quat rotation = _avatarData->getOrientation(); - glm::vec3 position = _avatarData->getPosition() + rotation * _avatarShapeLocalOffset; - _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); - - btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity()); - _characterController->setVelocityForTimeInterval(walkVelocity, timeStep); + // This is step (2). + if (_characterController) { + _characterController->preSimulation(timeStep); } - // This is step (2). int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); _numSubsteps += (uint32_t)numSubsteps; stepNonPhysicalKinematics(usecTimestampNow()); @@ -322,20 +312,14 @@ void PhysicsEngine::stepSimulation() { // // TODO: untangle these lock sequences. _entityTree->lockForWrite(); - _avatarData->lockForWrite(); lock(); _dynamicsWorld->synchronizeMotionStates(); - if (_avatarData->isPhysicsEnabled()) { - const btTransform& avatarTransform = _avatarGhostObject->getWorldTransform(); - glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); - glm::vec3 offset = rotation * _avatarShapeLocalOffset; - _avatarData->setOrientation(rotation); - _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); + if (_characterController) { + _characterController->postSimulation(); } unlock(); - _avatarData->unlock(); _entityTree->unlock(); computeCollisionEvents(); @@ -614,76 +598,35 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio return true; } - - void PhysicsEngine::setAvatarData(AvatarData *avatarData) { - assert(avatarData); // don't pass NULL argument - - // compute capsule dimensions - AABox box = avatarData->getLocalAABox(); - const glm::vec3& diagonal = box.getScale(); - float radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); - float halfHeight = 0.5f * diagonal.y - radius; - float MIN_HALF_HEIGHT = 0.1f; - if (halfHeight < MIN_HALF_HEIGHT) { - halfHeight = MIN_HALF_HEIGHT; - } - glm::vec3 offset = box.getCorner() + 0.5f * diagonal; - - if (!_avatarData) { - // _avatarData is being initialized - _avatarData = avatarData; - } else { - // _avatarData is being updated - assert(_avatarData == avatarData); - - // get old dimensions from shape - btCapsuleShape* capsule = static_cast<btCapsuleShape*>(_avatarGhostObject->getCollisionShape()); - btScalar oldRadius = capsule->getRadius(); - btScalar oldHalfHeight = capsule->getHalfHeight(); - - // compare dimensions (and offset) - float radiusDelta = glm::abs(radius - oldRadius); - float heightDelta = glm::abs(halfHeight - oldHalfHeight); - if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) { - // shape hasn't changed --> nothing to do - float offsetDelta = glm::distance(offset, _avatarShapeLocalOffset); - if (offsetDelta > FLT_EPSILON) { - // if only the offset changes then we can update it --> no need to rebuild shape - _avatarShapeLocalOffset = offset; - } - return; + if (_characterController) { + bool needsShapeUpdate = _characterController->needsShapeUpdate(); + if (needsShapeUpdate) { + lock(); + // remove old info + _dynamicsWorld->removeCollisionObject(_characterController->getGhostObject()); + _dynamicsWorld->removeAction(_characterController); + // update shape + _characterController->updateShape(); + // insert new info + _dynamicsWorld->addCollisionObject(_characterController->getGhostObject(), + btBroadphaseProxy::CharacterFilter, + btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); + _dynamicsWorld->addAction(_characterController); + _characterController->reset(_dynamicsWorld); + unlock(); } - - // delete old controller and friends - _dynamicsWorld->removeCollisionObject(_avatarGhostObject); - _dynamicsWorld->removeAction(_characterController); - delete _characterController; - _characterController = NULL; - delete _avatarGhostObject; - _avatarGhostObject = NULL; - delete capsule; + } else { + // initialize _characterController + assert(avatarData); // don't pass NULL argument + lock(); + _characterController = new CharacterController(avatarData); + _dynamicsWorld->addCollisionObject(_characterController->getGhostObject(), + btBroadphaseProxy::CharacterFilter, + btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); + _dynamicsWorld->addAction(_characterController); + _characterController->reset(_dynamicsWorld); + unlock(); } - - // set offset - _avatarShapeLocalOffset = offset; - - // build ghost, shape, and controller - _avatarGhostObject = new btPairCachingGhostObject(); - _avatarGhostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), - glmToBullet(_avatarData->getPosition()))); - // ?TODO: use ShapeManager to get avatar's shape? - btCapsuleShape* capsule = new btCapsuleShape(radius, 2.0f * halfHeight); - - _avatarGhostObject->setCollisionShape(capsule); - _avatarGhostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); - - const float MIN_STEP_HEIGHT = 0.35f; - btScalar stepHeight = glm::max(MIN_STEP_HEIGHT, radius + 0.5f * halfHeight); - _characterController = new CharacterController(_avatarGhostObject, capsule, stepHeight); - - _dynamicsWorld->addCollisionObject(_avatarGhostObject, btBroadphaseProxy::CharacterFilter, - btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); - _dynamicsWorld->addAction(_characterController); - _characterController->reset(_dynamicsWorld); } + diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index acf1617b16..cb637c60b9 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -123,9 +123,6 @@ private: /// character collisions CharacterController* _characterController = NULL; - class btPairCachingGhostObject* _avatarGhostObject = NULL; - AvatarData* _avatarData = NULL; - glm::vec3 _avatarShapeLocalOffset; }; #endif // hifi_PhysicsEngine_h From b4263cd2ebf4129b4cd9bd272a63603cfeb2f013 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Mon, 16 Mar 2015 17:10:49 -0700 Subject: [PATCH 002/177] allow objs to collide agains char controller but char controller only responds to penetration when enabled --- libraries/physics/src/CharacterController.cpp | 54 ++++++++++++------- libraries/physics/src/CharacterController.h | 5 +- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 994c95e074..8fb3125ad0 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -132,6 +132,11 @@ CharacterController::CharacterController(AvatarData* avatarData) { assert(avatarData); m_avatarData = avatarData; + // cache the "PhysicsEnabled" state of m_avatarData + m_avatarData->lockForRead(); + m_enabled = m_avatarData->isPhysicsEnabled(); + m_avatarData->unlock(); + createShapeAndGhost(); m_upAxis = 1; // HACK: hard coded to be 1 for now (yAxis) @@ -533,6 +538,9 @@ void CharacterController::warp(const btVector3& origin) { void CharacterController::preStep( btCollisionWorld* collisionWorld) { + if (!m_enabled) { + return; + } int numPenetrationLoops = 0; m_touchingContact = false; while (recoverFromPenetration(collisionWorld)) { @@ -548,7 +556,7 @@ void CharacterController::preStep( btCollisionWorld* collisionWorld) { } void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScalar dt) { - if (!m_useWalkDirection && m_velocityTimeInterval <= 0.0) { + if (!m_enabled || (!m_useWalkDirection && m_velocityTimeInterval <= 0.0)) { return; // no motion } @@ -637,7 +645,7 @@ btScalar CharacterController::getMaxSlope() const { } bool CharacterController::onGround() const { - return m_verticalVelocity == 0.0 && m_verticalOffset == 0.0; + return m_enabled && m_verticalVelocity == 0.0 && m_verticalOffset == 0.0; } btVector3* CharacterController::getUpAxisDirections() { @@ -656,7 +664,15 @@ void CharacterController::setUpInterpolate(bool value) { // protected void CharacterController::createShapeAndGhost() { // get new dimensions from avatar + m_avatarData->lockForRead(); AABox box = m_avatarData->getLocalAABox(); + + // create new ghost + m_ghostObject = new btPairCachingGhostObject(); + m_ghostObject->setWorldTransform(btTransform(glmToBullet(m_avatarData->getOrientation()), + glmToBullet(m_avatarData->getPosition()))); + m_avatarData->unlock(); + const glm::vec3& diagonal = box.getScale(); float radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); float halfHeight = 0.5f * diagonal.y - radius; @@ -672,18 +688,16 @@ void CharacterController::createShapeAndGhost() { // create new shape m_convexShape = new btCapsuleShape(radius, 2.0f * halfHeight); - - // create new ghost - m_ghostObject = new btPairCachingGhostObject(); - m_ghostObject->setWorldTransform(btTransform(glmToBullet(m_avatarData->getOrientation()), - glmToBullet(m_avatarData->getPosition()))); m_ghostObject->setCollisionShape(m_convexShape); m_ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); } bool CharacterController::needsShapeUpdate() { // get new dimensions from avatar + m_avatarData->lockForRead(); AABox box = m_avatarData->getLocalAABox(); + m_avatarData->unlock(); + const glm::vec3& diagonal = box.getScale(); float radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); float halfHeight = 0.5f * diagonal.y - radius; @@ -727,21 +741,23 @@ void CharacterController::updateShape() { } void CharacterController::preSimulation(btScalar timeStep) { - if (m_avatarData->isPhysicsEnabled()) { - m_avatarData->lockForRead(); - // update character controller - glm::quat rotation = m_avatarData->getOrientation(); - glm::vec3 position = m_avatarData->getPosition() + rotation * m_shapeLocalOffset; - m_ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); - - btVector3 walkVelocity = glmToBullet(m_avatarData->getVelocity()); - setVelocityForTimeInterval(walkVelocity, timeStep); - m_avatarData->unlock(); - } + m_avatarData->lockForRead(); + + // cache the "PhysicsEnabled" state of m_avatarData here + // and use the cached value for the rest of the simulation step + m_enabled = m_avatarData->isPhysicsEnabled(); + + glm::quat rotation = m_avatarData->getOrientation(); + glm::vec3 position = m_avatarData->getPosition() + rotation * m_shapeLocalOffset; + m_ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); + btVector3 walkVelocity = glmToBullet(m_avatarData->getVelocity()); + setVelocityForTimeInterval(walkVelocity, timeStep); + + m_avatarData->unlock(); } void CharacterController::postSimulation() { - if (m_avatarData->isPhysicsEnabled()) { + if (m_enabled) { m_avatarData->lockForWrite(); const btTransform& avatarTransform = m_ghostObject->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 8e1116f7ea..436f9a7277 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -77,8 +77,9 @@ protected: bool m_touchingContact; btVector3 m_touchingNormal; - bool m_wasOnGround; - bool m_wasJumping; + bool m_enabled; + bool m_wasOnGround; + bool m_wasJumping; bool m_useGhostObjectSweepTest; bool m_useWalkDirection; btScalar m_velocityTimeInterval; From 9ea13fac378673cb5982f1158e56af1aaf90d31b Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 17 Mar 2015 09:01:36 -0700 Subject: [PATCH 003/177] cleanup formatting --- libraries/physics/src/CharacterController.cpp | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 8fb3125ad0..ae408a9aea 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -53,7 +53,7 @@ m_me = me; virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) { -if(rayResult.m_collisionObject == m_me) +if (rayResult.m_collisionObject == m_me) return 1.0; return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); @@ -221,7 +221,6 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl if (dist < maxPen) { maxPen = dist; m_touchingNormal = pt.m_normalWorldOnB * directionSign;//?? - } m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2); penetration = true; @@ -282,7 +281,7 @@ void CharacterController::stepUp( btCollisionWorld* world) { void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag) { btVector3 movementDirection = m_targetPosition - m_currentPosition; btScalar movementLength = movementDirection.length(); - if (movementLength>SIMD_EPSILON) { + if (movementLength > SIMD_EPSILON) { movementDirection.normalize(); btVector3 reflectDir = computeReflectionDirection(movementDirection, hitNormal); @@ -296,12 +295,12 @@ void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& m_targetPosition = m_currentPosition; //if (tangentMag != 0.0) { if (0) { - btVector3 parComponent = parallelDir * btScalar(tangentMag*movementLength); + btVector3 parComponent = parallelDir * btScalar(tangentMag * movementLength); m_targetPosition += parComponent; } if (normalMag != 0.0) { - btVector3 perpComponent = perpindicularDir * btScalar(normalMag*movementLength); + btVector3 perpComponent = perpindicularDir * btScalar(normalMag * movementLength); m_targetPosition += perpComponent; } } @@ -337,11 +336,9 @@ void CharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; - btScalar margin = m_convexShape->getMargin(); m_convexShape->setMargin(margin + m_addedMargin); - if (m_useGhostObjectSweepTest) { m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); } else { @@ -350,7 +347,6 @@ void CharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld m_convexShape->setMargin(margin); - fraction -= callback.m_closestHitFraction; if (callback.hasHit()) { @@ -443,13 +439,13 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d btScalar downDistance = (m_verticalVelocity < 0.0f ? -m_verticalVelocity : 0.0f) * dt; bool has_hit = false; - if(bounce_fix == true) { + if (bounce_fix == true) { has_hit = callback.hasHit() || callback2.hasHit(); } else { has_hit = callback2.hasHit(); } - if(downDistance > 0.0 && downDistance < m_stepHeight && has_hit == true && runOnce == false + if (downDistance > 0.0 && downDistance < m_stepHeight && has_hit == true && runOnce == false && (m_wasOnGround || !m_wasJumping)) { //redo the velocity calculation when falling a small amount, for fast stairs motion //for larger falls, use the smoother/slower interpolated movement by not touching the target position @@ -475,9 +471,9 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d //due to errors in the closestHitFraction variable when used with large polygons, calculate the hit fraction manually m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, fraction); } - } - else + } else { m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); + } full_drop = false; From 46f6c9f8882a8943b5f85b845291060e1dc01d02 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Tue, 17 Mar 2015 09:06:31 -0700 Subject: [PATCH 004/177] Add WebWindow::setURL --- interface/src/scripting/WebWindowClass.cpp | 8 ++++++++ interface/src/scripting/WebWindowClass.h | 1 + 2 files changed, 9 insertions(+) diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index ae0e327cb1..01e5f07ca9 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -96,6 +96,14 @@ void WebWindowClass::setVisible(bool visible) { QMetaObject::invokeMethod(_windowWidget, "setVisible", Qt::BlockingQueuedConnection, Q_ARG(bool, visible)); } +void WebWindowClass::setURL(const QString& url) { + if (QThread::currentThread() != thread()) { + QMetaObject::invokeMethod(this, "setURL", Qt::BlockingQueuedConnection, Q_ARG(QString, url)); + return; + } + _webView->setUrl(url); +} + QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { WebWindowClass* retVal; QString file = context->argument(0).toString(); diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h index c923fdd748..08d9a42478 100644 --- a/interface/src/scripting/WebWindowClass.h +++ b/interface/src/scripting/WebWindowClass.h @@ -42,6 +42,7 @@ public: public slots: void setVisible(bool visible); + void setURL(const QString& url); ScriptEventBridge* getEventBridge() const { return _eventBridge; } void addEventBridgeToWindowObject(); From 8088b0135622487454df0f9a0b387718dad6ad28 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Tue, 17 Mar 2015 09:06:48 -0700 Subject: [PATCH 005/177] Add WebWindow::raise --- interface/src/scripting/WebWindowClass.cpp | 4 ++++ interface/src/scripting/WebWindowClass.h | 1 + 2 files changed, 5 insertions(+) diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index 01e5f07ca9..c3a3dada73 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -104,6 +104,10 @@ void WebWindowClass::setURL(const QString& url) { _webView->setUrl(url); } +void WebWindowClass::raise() { + QMetaObject::invokeMethod(_windowWidget, "raise", Qt::BlockingQueuedConnection); +} + QScriptValue WebWindowClass::constructor(QScriptContext* context, QScriptEngine* engine) { WebWindowClass* retVal; QString file = context->argument(0).toString(); diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h index 08d9a42478..60732acf67 100644 --- a/interface/src/scripting/WebWindowClass.h +++ b/interface/src/scripting/WebWindowClass.h @@ -43,6 +43,7 @@ public: public slots: void setVisible(bool visible); void setURL(const QString& url); + void raise(); ScriptEventBridge* getEventBridge() const { return _eventBridge; } void addEventBridgeToWindowObject(); From 1e1c60847bf5d2f415eadde65f6f8c6753c1331f Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Tue, 17 Mar 2015 09:07:01 -0700 Subject: [PATCH 006/177] Add WebWindow::getURL --- interface/src/scripting/WebWindowClass.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/interface/src/scripting/WebWindowClass.h b/interface/src/scripting/WebWindowClass.h index 60732acf67..429b054966 100644 --- a/interface/src/scripting/WebWindowClass.h +++ b/interface/src/scripting/WebWindowClass.h @@ -34,6 +34,7 @@ signals: class WebWindowClass : public QObject { Q_OBJECT Q_PROPERTY(QObject* eventBridge READ getEventBridge) + Q_PROPERTY(QString url READ getURL) public: WebWindowClass(const QString& title, const QString& url, int width, int height, bool isToolWindow = false); ~WebWindowClass(); @@ -42,6 +43,7 @@ public: public slots: void setVisible(bool visible); + QString getURL() const { return _webView->url().url(); } void setURL(const QString& url); void raise(); ScriptEventBridge* getEventBridge() const { return _eventBridge; } From 66517fa1c0bb4f51a62e3f4991ff75092a846194 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Tue, 17 Mar 2015 09:07:33 -0700 Subject: [PATCH 007/177] Add ability to show marketplace url from edit properties --- examples/edit.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/edit.js b/examples/edit.js index 72938e5ed4..03137310b6 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -338,7 +338,11 @@ var toolBar = (function () { return true; } if (browseModelsButton === toolBar.clicked(clickedOverlay)) { + if (marketplaceWindow.url != MARKETPLACE_URL) { + marketplaceWindow.setURL(MARKETPLACE_URL); + } marketplaceWindow.setVisible(true); + marketplaceWindow.raise(); return true; } @@ -1143,6 +1147,10 @@ PropertiesTool = function(opts) { } pushCommandForSelections(); selectionManager._update(); + } else if (data.type = "showMarketplace") { + if (marketplaceWindow.url != data.url) { + marketplaceWindow.setURL(data.url); + } } else if (data.type == "action") { if (data.action == "moveSelectionToGrid") { if (selectionManager.hasSelection()) { From d097b4409e79dcba8b500fe655f293069606c7ce Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Tue, 17 Mar 2015 10:40:51 -0700 Subject: [PATCH 008/177] Add title to non-toolbar WebWindows --- interface/src/scripting/WebWindowClass.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/scripting/WebWindowClass.cpp b/interface/src/scripting/WebWindowClass.cpp index c3a3dada73..61b3ce225f 100644 --- a/interface/src/scripting/WebWindowClass.cpp +++ b/interface/src/scripting/WebWindowClass.cpp @@ -55,6 +55,7 @@ WebWindowClass::WebWindowClass(const QString& title, const QString& url, int wid _windowWidget = dockWidget; } else { _windowWidget = new QWidget(Application::getInstance()->getWindow(), Qt::Window); + _windowWidget->setWindowTitle(title); _windowWidget->setMinimumSize(width, height); auto layout = new QVBoxLayout(_windowWidget); From af789f842dabe3837777ebd85ebadc823d9712c8 Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski <stojce@me.com> Date: Tue, 17 Mar 2015 22:47:18 +0100 Subject: [PATCH 009/177] #20397 initial version of script --- examples/example/entities/makeHouses.js | 146 ++++++++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 examples/example/entities/makeHouses.js diff --git a/examples/example/entities/makeHouses.js b/examples/example/entities/makeHouses.js new file mode 100644 index 0000000000..26224fd58a --- /dev/null +++ b/examples/example/entities/makeHouses.js @@ -0,0 +1,146 @@ +// +// makeHouses.js +// +// +// Created by Stojce Slavkovski on March 14, 2015 +// Copyright 2015 High Fidelity, Inc. +// +// This sample script that creates house entities based on parameters. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +(function () { + + /** options **/ + var numHouses = 100; + var xRange = 300; + var yRange = 300; + + var sizeOfTheHouse = { + x: 10, + y: 10, + z: 10 + }; + /**/ + + var modelUrl = "http://localhost/~stojce/models/3-Buildings-2-SanFranciscoHouse-"; + var modelurlExt = ".fbx"; + var modelVariations = 90; + var houses = []; + + function addHouseAt(position, rotation) { + // get random house model + var modelNumber = 1 + Math.floor(Math.random() * (modelVariations - 1)); + var modUrl = modelUrl + modelNumber + modelurlExt; + print("Model ID:" + modelNumber); + + var properties = { + type: "Model", + position: position, + rotation: rotation, + dimensions: sizeOfTheHouse, + modelURL: modUrl + }; + + return Entities.addEntity(properties); + } + + // calculate initial position + var posX = MyAvatar.position.x - (xRange / 2); + var measures = calculateParcels(numHouses, xRange, yRange); + var dd = 0; + + // avatar facing rotation + var rotEven = Quat.fromPitchYawRollDegrees(0, 270.0 + MyAvatar.bodyYaw, 0.0); + + // avatar opposite rotation + var rotOdd = Quat.fromPitchYawRollDegrees(0, 90.0 + MyAvatar.bodyYaw, 0.0); + var housePos = Vec3.sum(MyAvatar.position, Quat.getFront(Camera.getOrientation())); + + for (var j = 0; j < measures.rows; j++) { + + var posX1 = 0 - (xRange / 2); + dd += measures.parcelLength; + + for (var i = 0; i < measures.cols; i++) { + + // skip reminder of houses + if (houses.length > numHouses) { + break; + } + + var posShift = { + x: posX1, + y: 0, + z: dd + }; + + print("House nr.:" + houses.length + 1); + houses.push( + addHouseAt(Vec3.sum(housePos, posShift), (j % 2 == 0) ? rotEven : rotOdd) + ); + posX1 += measures.parcelWidth; + } + } + + // calculate rows and columns in area, and dimension of single parcel + function calculateParcels(items, areaWidth, areaLength) { + + var idealSize = Math.min(Math.sqrt(areaWidth * areaLength / items), areaWidth, areaLength); + + var baseWidth = Math.min(Math.floor(areaWidth / idealSize), items); + var baseLength = Math.min(Math.floor(areaLength / idealSize), items); + + var sirRows = baseWidth; + var sirCols = Math.ceil(items / sirRows); + var sirW = areaWidth / sirRows; + var sirL = areaLength / sirCols; + + var visCols = baseLength; + var visRows = Math.ceil(items / visCols); + var visW = areaWidth / visRows; + var visL = areaLength / visCols; + + var rows = 0; + var cols = 0; + var parcelWidth = 0; + var parcelLength = 0; + + if (Math.min(sirW, sirL) > Math.min(visW, visL)) { + rows = sirRows; + cols = sirCols; + parcelWidth = sirW; + parcelLength = sirL; + } else { + rows = visRows; + cols = visCols; + parcelWidth = visW; + parcelLength = visL; + } + + print("rows:" + rows); + print("cols:" + cols); + print("parcelWidth:" + parcelWidth); + print("parcelLength:" + parcelLength); + + return { + rows: rows, + cols: cols, + parcelWidth: parcelWidth, + parcelLength: parcelLength + }; + } + + function cleanup() { + while (houses.length > 0) { + if (!houses[0].isKnownID) { + houses[0] = Entities.identifyEntity(houses[0]); + } + Entities.deleteEntity(houses.shift()); + } + } + + Script.scriptEnding.connect(cleanup); +})(); \ No newline at end of file From 03da3aeab4afcbcba1aad6a858e417428ebc62ba Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Tue, 17 Mar 2015 16:15:10 -0700 Subject: [PATCH 010/177] Clean up on the GPU Profile defines in order to control features --- libraries/gpu/src/gpu/Config.slh | 6 ++++ libraries/gpu/src/gpu/GLBackendPipeline.cpp | 12 ++++---- libraries/gpu/src/gpu/GLBackendShader.cpp | 6 ++-- libraries/gpu/src/gpu/GLBackendTransform.cpp | 12 +++----- libraries/gpu/src/gpu/GPUConfig.h | 8 +++++ libraries/gpu/src/gpu/Transform.slh | 19 ++---------- libraries/model/src/model/Light.h | 29 +++++++------------ libraries/model/src/model/Light.slh | 19 ++---------- libraries/model/src/model/Material.h | 21 +++++--------- libraries/model/src/model/Material.slh | 26 ++++------------- .../src/DeferredLightingEffect.cpp | 19 ++---------- libraries/render-utils/src/Model.cpp | 14 +++------ libraries/render-utils/src/Shadow.slh | 4 +-- 13 files changed, 64 insertions(+), 131 deletions(-) diff --git a/libraries/gpu/src/gpu/Config.slh b/libraries/gpu/src/gpu/Config.slh index b17bd7b2b8..011f9d96d0 100644 --- a/libraries/gpu/src/gpu/Config.slh +++ b/libraries/gpu/src/gpu/Config.slh @@ -12,10 +12,16 @@ <@def GPU_CONFIG_SLH@> <@if GLPROFILE == PC_GL @> + <@def GPU_FEATURE_PROFILE Core@> + <@def GPU_TRANSFORM_PROFILE Core@> <@def VERSION_HEADER #version 330 compatibility@> <@elif GLPROFILE == MAC_GL @> + <@def GPU_FEATURE_PROFILE Legacy@> + <@def GPU_TRANSFORM_PROFILE Legacy@> <@def VERSION_HEADER #version 120@> <@else@> + <@def GPU_FEATURE_PROFILE Legacy@> + <@def GPU_TRANSFORM_PROFILE Legacy@> <@def VERSION_HEADER #version 120@> <@endif@> diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index eba904ae4f..56df4d0178 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -55,19 +55,17 @@ void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { BufferPointer uniformBuffer = batch._buffers.get(batch._params[paramOffset + 2]._uint); GLintptr rangeStart = batch._params[paramOffset + 1]._uint; GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint; -#if defined(Q_OS_MAC) + +#if (GPU_FEATURE_PROFILE == Core) + GLuint bo = getBufferID(*uniformBuffer); + glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize); +#else GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart); glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data); // NOT working so we ll stick to the uniform float array until we move to core profile // GLuint bo = getBufferID(*uniformBuffer); //glUniformBufferEXT(_shader._program, slot, bo); -#elif defined(Q_OS_WIN) - GLuint bo = getBufferID(*uniformBuffer); - glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize); -#else - GLfloat* data = (GLfloat*) (uniformBuffer->getData() + rangeStart); - glUniform4fv(slot, rangeSize / sizeof(GLfloat[4]), data); #endif CHECK_GL_ERROR(); } diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 9bcc278d8e..0a74ca69ca 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -88,7 +88,7 @@ void makeBindings(GLBackend::GLShader* shader) { // now assign the ubo binding, then DON't relink! //Check for gpu specific uniform slotBindings -#if defined(Q_OS_WIN) +#if (GPU_TRANSFORM_PROFILE == Core) loc = glGetUniformBlockIndex(glprogram, "transformObjectBuffer"); if (loc >= 0) { glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); @@ -551,7 +551,9 @@ bool isUnusedSlot(GLint binding) { int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) { GLint buffersCount = 0; -#if defined(Q_OS_WIN) + +#if (GPU_FEATURE_PROFILE == Core) + glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount); // fast exit diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index 6e928bcf09..ad6d4b2395 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -32,7 +32,7 @@ void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { } void GLBackend::initTransform() { -#if defined(Q_OS_WIN) + #if (GPU_TRANSFORM_PROFILE == Core) glGenBuffers(1, &_transform._transformObjectBuffer); glGenBuffers(1, &_transform._transformCameraBuffer); @@ -49,7 +49,7 @@ void GLBackend::initTransform() { } void GLBackend::killTransform() { -#if defined(Q_OS_WIN) + #if (GPU_TRANSFORM_PROFILE == Core) glDeleteBuffers(1, &_transform._transformObjectBuffer); glDeleteBuffers(1, &_transform._transformCameraBuffer); #else @@ -77,34 +77,30 @@ void GLBackend::updateTransform() { _transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated; } + #if (GPU_TRANSFORM_PROFILE == Core) if (_transform._invalidView || _transform._invalidProj) { -#if defined(Q_OS_WIN) glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0); glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformCamera), (const void*) &_transform._transformCamera, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); CHECK_GL_ERROR(); -#endif } if (_transform._invalidModel) { -#if defined(Q_OS_WIN) glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, 0); glBindBuffer(GL_ARRAY_BUFFER, _transform._transformObjectBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(_transform._transformObject), (const void*) &_transform._transformObject, GL_DYNAMIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); CHECK_GL_ERROR(); -#endif } -#if defined(Q_OS_WIN) glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_OBJECT_SLOT, _transform._transformObjectBuffer); glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, _transform._transformCameraBuffer); CHECK_GL_ERROR(); #endif -#if defined(Q_OS_MAC) || defined(Q_OS_LINUX) +#if (GPU_TRANSFORM_PROFILE == Legacy) // Do it again for fixed pipeline until we can get rid of it if (_transform._invalidProj) { if (_transform._lastMode != GL_PROJECTION) { diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index 5894d2a91d..9372eb0dbf 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -18,17 +18,25 @@ #include <OpenGL/gl.h> #include <OpenGL/glext.h> +#define GPU_FEATURE_PROFILE Core +#define GPU_TRANSFORM_PROFILE Core + #elif defined(WIN32) #include <windowshacks.h> #include <GL/glew.h> #include <GL/wglew.h> +#define GPU_FEATURE_PROFILE Legacy +#define GPU_TRANSFORM_PROFILE Legacy + #elif defined(ANDROID) #else #include <GL/gl.h> #include <GL/glext.h> +#define GPU_FEATURE_PROFILE Legacy +#define GPU_TRANSFORM_PROFILE Legacy #endif diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index d3d2629c2e..6779386065 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -24,9 +24,7 @@ struct TransformCamera { }; vec4 transformModelToClipPos(TransformCamera camera, TransformObject object, vec4 pos) { -<@if GLPROFILE == MAC_GL@> - return gl_ModelViewProjectionMatrix * pos; -<@elif GLPROFILE == PC_GL@> +<@if GPU_TRANSFORM_PROFILE == GPUCore@> vec4 epos = (object._model * pos) + vec4(-pos.w * camera._viewInverse[3].xyz, 0.0); return camera._projectionViewUntranslated * epos; // Equivalent to the following but hoppefully a bit more accurate @@ -37,9 +35,7 @@ vec4 transformModelToClipPos(TransformCamera camera, TransformObject object, vec } vec3 transformModelToEyeDir(TransformCamera camera, TransformObject object, vec3 dir) { -<@if GLPROFILE == MAC_GL@> - return gl_NormalMatrix * dir; -<@elif GLPROFILE == PC_GL@> +<@if GPU_TRANSFORM_PROFILE == GPUCore@> vec3 mr0 = vec3(object._modelInverse[0].x, object._modelInverse[1].x, object._modelInverse[2].x); vec3 mr1 = vec3(object._modelInverse[0].y, object._modelInverse[1].y, object._modelInverse[2].y); vec3 mr2 = vec3(object._modelInverse[0].z, object._modelInverse[1].z, object._modelInverse[2].z); @@ -56,7 +52,7 @@ vec3 transformModelToEyeDir(TransformCamera camera, TransformObject object, vec3 <@endif@> } -<@if GLPROFILE == PC_GL@> +<@if GPU_TRANSFORM_PROFILE == GPUCore@> uniform transformObjectBuffer { TransformObject object; }; @@ -70,16 +66,7 @@ uniform transformCameraBuffer { TransformCamera getTransformCamera() { return camera; } -<@elif GLPROFILE == MAC_GL@> -TransformObject getTransformObject() { - TransformObject object; - return object; -} -TransformCamera getTransformCamera() { - TransformCamera camera; - return camera; -} <@else@> TransformObject getTransformObject() { diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 2ef2bf3036..2c76714740 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -252,27 +252,18 @@ public: // Schema to access the attribute values of the light class Schema { public: - Vec4 _position; - Vec3 _direction; - float _spare0; - Color _color; - float _intensity; - Vec4 _attenuation; - Vec4 _spot; - Vec4 _shadow; + Vec4 _position = Vec4(0.0f, 0.0f, 0.0f, 1.0f); + Vec3 _direction = Vec3(0.0f, 0.0f, -1.0f); + float _spare0 = 0.0f; + Color _color = Color(1.0f); + float _intensity = 1.0f; + Vec4 _attenuation = Vec4(1.0f); + Vec4 _spot = Vec4(0.0f, 0.0f, 0.0f, 3.0f); + Vec4 _shadow = Vec4(0.0f); - Vec4 _control; + Vec4 _control = Vec4(0.0f); - Schema() : - _position(0.0f, 0.0f, 0.0f, 1.0f), - _direction(0.0f, 0.0f, -1.0f), - _spare0(0.f), - _color(1.0f), - _intensity(1.0f), - _attenuation(1.0f, 1.0f, 1.0f, 1.0f), - _spot(0.0f, 0.0f, 0.0f, 3.0f), - _control(0.0f) - {} + Schema() {} }; const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; } diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index fc17e94050..5a65bf7d18 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -19,7 +19,6 @@ struct Light { vec4 _spot; vec4 _shadow; - vec4 _control; }; @@ -65,29 +64,15 @@ float getLightShowContour(Light l) { return l._control.w; } -<@if GLPROFILE == PC_GL@> +<@if GPU_FEATURE_PROFILE == Core @> uniform lightBuffer { Light light; }; Light getLight() { return light; } -<@elif GLPROFILE == MAC_GL@> -uniform vec4 lightBuffer[9]; -Light getLight() { - Light light; - light._position = lightBuffer[0]; - light._direction = lightBuffer[1]; - light._color = lightBuffer[2]; - light._attenuation = lightBuffer[3]; - light._spot = lightBuffer[4]; - light._shadow = lightBuffer[5]; - light._control = lightBuffer[6]; - - return light; -} <@else@> -uniform vec4 lightBuffer[9]; +uniform vec4 lightBuffer[7]; Light getLight() { Light light; light._position = lightBuffer[0]; diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 2718b1dfa8..865fd6dfb1 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -79,20 +79,15 @@ public: class Schema { public: - Color _diffuse; - float _opacity; - Color _specular; - float _shininess; - Color _emissive; - float _spare0; + Color _diffuse = Color(0.5f); + float _opacity = 1.f; + Color _specular = Color(0.03f); + float _shininess = 0.1f; + Color _emissive = Color(0.0f); + float _spare0 = 0.0f; + glm::vec4 _spareVec4 = glm::vec4(0.0f); // for alignment beauty, Mat size == Mat4x4 - Schema() : - _diffuse(0.5f), - _opacity(1.0f), - _specular(0.03f), - _shininess(0.1f), - _emissive(0.0f) - {} + Schema() {} }; const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; } diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index 9ea269f214..739b60502e 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -14,7 +14,8 @@ struct Material { vec4 _diffuse; vec4 _specular; - + vec4 _emissive; + vec4 _spare; }; float getMaterialOpacity(Material m) { return m._diffuse.a; } @@ -24,36 +25,21 @@ float getMaterialShininess(Material m) { return m._specular.a; } -<@if GLPROFILE == PC_GL@> +<@if GPU_FEATURE_PROFILE == Core@> uniform materialBuffer { Material _mat; }; Material getMaterial() { return _mat; } -<@elif GLPROFILE == MAC_GL@> -uniform vec4 materialBuffer[2]; -Material getMaterial() { - Material mat; - mat._diffuse = materialBuffer[0]; - mat._specular = materialBuffer[1]; - return mat; -} -<!/* tryed and failed... - bindable uniform struct { - Material mat; - } materialBuffer; - - Material getMaterial() { - return materialBuffer.mat; - } - */!> <@else@> -uniform vec4 materialBuffer[2]; +uniform vec4 materialBuffer[4]; Material getMaterial() { Material mat; mat._diffuse = materialBuffer[0]; mat._specular = materialBuffer[1]; + mat._emissive = materialBuffer[2]; + mat._spare = materialBuffer[3]; return mat; } <@endif@> diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 96ab790cd6..ccfe25297c 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -494,14 +494,8 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit locations.invViewMat = program.uniformLocation("invViewMat"); GLint loc = -1; -#if defined(Q_OS_MAC) - loc = program.uniformLocation("lightBuffer"); - if (loc >= 0) { - locations.lightBufferUnit = loc; - } else { - locations.lightBufferUnit = -1; - } -#elif defined(Q_OS_WIN) + +#if (GPU_FEATURE_PROFILE == Core) loc = glGetUniformBlockIndex(program.programId(), "lightBuffer"); if (loc >= 0) { glUniformBlockBinding(program.programId(), loc, 0); @@ -518,14 +512,7 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit } #endif -#if defined(Q_OS_MAC) - loc = program.uniformLocation("atmosphereBufferUnit"); - if (loc >= 0) { - locations.atmosphereBufferUnit = loc; - } else { - locations.atmosphereBufferUnit = -1; - } -#elif defined(Q_OS_WIN) +#if (GPU_FEATURE_PROFILE == Core) loc = glGetUniformBlockIndex(program.programId(), "atmosphereBufferUnit"); if (loc >= 0) { glUniformBlockBinding(program.programId(), loc, 1); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index be2e7b4aec..d3369572ff 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -199,14 +199,8 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo } // bindable uniform version -#if defined(Q_OS_MAC) - loc = program.uniformLocation("materialBuffer"); - if (loc >= 0) { - locations.materialBufferUnit = loc; - } else { - locations.materialBufferUnit = -1; - } -#elif defined(Q_OS_WIN) + +#if (GPU_FEATURE_PROFILE == Core) loc = glGetUniformBlockIndex(program.programId(), "materialBuffer"); if (loc >= 0) { glUniformBlockBinding(program.programId(), loc, 1); @@ -223,7 +217,7 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo } #endif -#if defined(Q_OS_WIN) +#if (GPU_FEATURE_PROFILE == Core) loc = glGetUniformBlockIndex(program.programId(), "transformObjectBuffer"); if (loc >= 0) { glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_OBJECT_SLOT); @@ -231,7 +225,7 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo } #endif -#if defined(Q_OS_WIN) +#if (GPU_FEATURE_PROFILE == Core) loc = glGetUniformBlockIndex(program.programId(), "transformCameraBuffer"); if (loc >= 0) { glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_CAMERA_SLOT); diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index d4c19915ff..70c0ac02de 100755 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -16,10 +16,8 @@ uniform sampler2DShadow shadowMap; // Fetching it float fetchShadow(vec3 texcoord) { -<@if GLPROFILE == PC_GL @> +<@if GPU_FEATURE_PROFILE == Core @> return texture(shadowMap, texcoord); -<@elif GLPROFILE == MAC_GL@> - return shadow2D(shadowMap, texcoord).r; <@else@> return shadow2D(shadowMap, texcoord).r; <@endif@> From 74ae0c4a8596b54eaf1d65549d12dbb0131cc247 Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Tue, 17 Mar 2015 16:35:32 -0700 Subject: [PATCH 011/177] set the defines for GPU profile correctly --- libraries/gpu/src/gpu/GPUConfig.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index 9372eb0dbf..8308860c82 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -18,16 +18,16 @@ #include <OpenGL/gl.h> #include <OpenGL/glext.h> -#define GPU_FEATURE_PROFILE Core -#define GPU_TRANSFORM_PROFILE Core +#define GPU_FEATURE_PROFILE Legacy +#define GPU_TRANSFORM_PROFILE Legacy #elif defined(WIN32) #include <windowshacks.h> #include <GL/glew.h> #include <GL/wglew.h> -#define GPU_FEATURE_PROFILE Legacy -#define GPU_TRANSFORM_PROFILE Legacy +#define GPU_FEATURE_PROFILE Core +#define GPU_TRANSFORM_PROFILE Core #elif defined(ANDROID) From 5a40fcee172ba5c3683148c55e416448024dfbf1 Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Tue, 17 Mar 2015 16:51:59 -0700 Subject: [PATCH 012/177] set the defines for GPU profile correctly AGAIN --- libraries/gpu/src/gpu/Config.slh | 12 ++++++------ libraries/gpu/src/gpu/GLBackendPipeline.cpp | 2 +- libraries/gpu/src/gpu/GLBackendShader.cpp | 4 ++-- libraries/gpu/src/gpu/GLBackendTransform.cpp | 8 ++++---- libraries/gpu/src/gpu/GPUConfig.h | 15 +++++++++------ libraries/gpu/src/gpu/Transform.slh | 6 +++--- libraries/model/src/model/Light.slh | 2 +- libraries/model/src/model/Material.slh | 2 +- .../render-utils/src/DeferredLightingEffect.cpp | 4 ++-- libraries/render-utils/src/Model.cpp | 6 +++--- libraries/render-utils/src/Shadow.slh | 2 +- 11 files changed, 33 insertions(+), 30 deletions(-) diff --git a/libraries/gpu/src/gpu/Config.slh b/libraries/gpu/src/gpu/Config.slh index 011f9d96d0..7a51de594a 100644 --- a/libraries/gpu/src/gpu/Config.slh +++ b/libraries/gpu/src/gpu/Config.slh @@ -12,16 +12,16 @@ <@def GPU_CONFIG_SLH@> <@if GLPROFILE == PC_GL @> - <@def GPU_FEATURE_PROFILE Core@> - <@def GPU_TRANSFORM_PROFILE Core@> + <@def GPU_FEATURE_PROFILE GPU_CORE@> + <@def GPU_TRANSFORM_PROFILE GPU_CORE@> <@def VERSION_HEADER #version 330 compatibility@> <@elif GLPROFILE == MAC_GL @> - <@def GPU_FEATURE_PROFILE Legacy@> - <@def GPU_TRANSFORM_PROFILE Legacy@> + <@def GPU_FEATURE_PROFILE GPU_LEGACY@> + <@def GPU_TRANSFORM_PROFILE GPU_LEGACY@> <@def VERSION_HEADER #version 120@> <@else@> - <@def GPU_FEATURE_PROFILE Legacy@> - <@def GPU_TRANSFORM_PROFILE Legacy@> + <@def GPU_FEATURE_PROFILE GPU_LEGACY@> + <@def GPU_TRANSFORM_PROFILE GPU_LEGACY@> <@def VERSION_HEADER #version 120@> <@endif@> diff --git a/libraries/gpu/src/gpu/GLBackendPipeline.cpp b/libraries/gpu/src/gpu/GLBackendPipeline.cpp index 56df4d0178..aee3f009d1 100755 --- a/libraries/gpu/src/gpu/GLBackendPipeline.cpp +++ b/libraries/gpu/src/gpu/GLBackendPipeline.cpp @@ -56,7 +56,7 @@ void GLBackend::do_setUniformBuffer(Batch& batch, uint32 paramOffset) { GLintptr rangeStart = batch._params[paramOffset + 1]._uint; GLsizeiptr rangeSize = batch._params[paramOffset + 0]._uint; -#if (GPU_FEATURE_PROFILE == Core) +#if (GPU_FEATURE_PROFILE == GPU_CORE) GLuint bo = getBufferID(*uniformBuffer); glBindBufferRange(GL_UNIFORM_BUFFER, slot, bo, rangeStart, rangeSize); #else diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 0a74ca69ca..48ae0eb7c9 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -88,7 +88,7 @@ void makeBindings(GLBackend::GLShader* shader) { // now assign the ubo binding, then DON't relink! //Check for gpu specific uniform slotBindings -#if (GPU_TRANSFORM_PROFILE == Core) +#if (GPU_TRANSFORM_PROFILE == GPU_CORE) loc = glGetUniformBlockIndex(glprogram, "transformObjectBuffer"); if (loc >= 0) { glUniformBlockBinding(glprogram, loc, gpu::TRANSFORM_OBJECT_SLOT); @@ -552,7 +552,7 @@ bool isUnusedSlot(GLint binding) { int makeUniformBlockSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& buffers) { GLint buffersCount = 0; -#if (GPU_FEATURE_PROFILE == Core) +#if (GPU_FEATURE_PROFILE == GPU_CORE) glGetProgramiv(glprogram, GL_ACTIVE_UNIFORM_BLOCKS, &buffersCount); diff --git a/libraries/gpu/src/gpu/GLBackendTransform.cpp b/libraries/gpu/src/gpu/GLBackendTransform.cpp index ad6d4b2395..f0318a66aa 100755 --- a/libraries/gpu/src/gpu/GLBackendTransform.cpp +++ b/libraries/gpu/src/gpu/GLBackendTransform.cpp @@ -32,7 +32,7 @@ void GLBackend::do_setProjectionTransform(Batch& batch, uint32 paramOffset) { } void GLBackend::initTransform() { - #if (GPU_TRANSFORM_PROFILE == Core) + #if (GPU_TRANSFORM_PROFILE == GPU_CORE) glGenBuffers(1, &_transform._transformObjectBuffer); glGenBuffers(1, &_transform._transformCameraBuffer); @@ -49,7 +49,7 @@ void GLBackend::initTransform() { } void GLBackend::killTransform() { - #if (GPU_TRANSFORM_PROFILE == Core) + #if (GPU_TRANSFORM_PROFILE == GPU_CORE) glDeleteBuffers(1, &_transform._transformObjectBuffer); glDeleteBuffers(1, &_transform._transformCameraBuffer); #else @@ -77,7 +77,7 @@ void GLBackend::updateTransform() { _transform._transformCamera._projectionViewUntranslated = _transform._transformCamera._projection * viewUntranslated; } - #if (GPU_TRANSFORM_PROFILE == Core) + #if (GPU_TRANSFORM_PROFILE == GPU_CORE) if (_transform._invalidView || _transform._invalidProj) { glBindBufferBase(GL_UNIFORM_BUFFER, TRANSFORM_CAMERA_SLOT, 0); glBindBuffer(GL_ARRAY_BUFFER, _transform._transformCameraBuffer); @@ -100,7 +100,7 @@ void GLBackend::updateTransform() { #endif -#if (GPU_TRANSFORM_PROFILE == Legacy) +#if (GPU_TRANSFORM_PROFILE == GPU_LEGACY) // Do it again for fixed pipeline until we can get rid of it if (_transform._invalidProj) { if (_transform._lastMode != GL_PROJECTION) { diff --git a/libraries/gpu/src/gpu/GPUConfig.h b/libraries/gpu/src/gpu/GPUConfig.h index 8308860c82..0b2d93b18d 100644 --- a/libraries/gpu/src/gpu/GPUConfig.h +++ b/libraries/gpu/src/gpu/GPUConfig.h @@ -14,20 +14,23 @@ #define GL_GLEXT_PROTOTYPES 1 +#define GPU_CORE 1 +#define GPU_LEGACY 0 + #if defined(__APPLE__) #include <OpenGL/gl.h> #include <OpenGL/glext.h> -#define GPU_FEATURE_PROFILE Legacy -#define GPU_TRANSFORM_PROFILE Legacy +#define GPU_FEATURE_PROFILE GPU_LEGACY +#define GPU_TRANSFORM_PROFILE GPU_LEGACY #elif defined(WIN32) #include <windowshacks.h> #include <GL/glew.h> #include <GL/wglew.h> -#define GPU_FEATURE_PROFILE Core -#define GPU_TRANSFORM_PROFILE Core +#define GPU_FEATURE_PROFILE GPU_CORE +#define GPU_TRANSFORM_PROFILE GPU_CORE #elif defined(ANDROID) @@ -35,8 +38,8 @@ #include <GL/gl.h> #include <GL/glext.h> -#define GPU_FEATURE_PROFILE Legacy -#define GPU_TRANSFORM_PROFILE Legacy +#define GPU_FEATURE_PROFILE GPU_LEGACY +#define GPU_TRANSFORM_PROFILE GPU_LEGACY #endif diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 6779386065..355713f9ae 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -24,7 +24,7 @@ struct TransformCamera { }; vec4 transformModelToClipPos(TransformCamera camera, TransformObject object, vec4 pos) { -<@if GPU_TRANSFORM_PROFILE == GPUCore@> +<@if GPU_TRANSFORM_PROFILE == GPU_CORE@> vec4 epos = (object._model * pos) + vec4(-pos.w * camera._viewInverse[3].xyz, 0.0); return camera._projectionViewUntranslated * epos; // Equivalent to the following but hoppefully a bit more accurate @@ -35,7 +35,7 @@ vec4 transformModelToClipPos(TransformCamera camera, TransformObject object, vec } vec3 transformModelToEyeDir(TransformCamera camera, TransformObject object, vec3 dir) { -<@if GPU_TRANSFORM_PROFILE == GPUCore@> +<@if GPU_TRANSFORM_PROFILE == GPU_CORE@> vec3 mr0 = vec3(object._modelInverse[0].x, object._modelInverse[1].x, object._modelInverse[2].x); vec3 mr1 = vec3(object._modelInverse[0].y, object._modelInverse[1].y, object._modelInverse[2].y); vec3 mr2 = vec3(object._modelInverse[0].z, object._modelInverse[1].z, object._modelInverse[2].z); @@ -52,7 +52,7 @@ vec3 transformModelToEyeDir(TransformCamera camera, TransformObject object, vec3 <@endif@> } -<@if GPU_TRANSFORM_PROFILE == GPUCore@> +<@if GPU_TRANSFORM_PROFILE == GPU_CORE@> uniform transformObjectBuffer { TransformObject object; }; diff --git a/libraries/model/src/model/Light.slh b/libraries/model/src/model/Light.slh index 5a65bf7d18..41c6e075cf 100644 --- a/libraries/model/src/model/Light.slh +++ b/libraries/model/src/model/Light.slh @@ -64,7 +64,7 @@ float getLightShowContour(Light l) { return l._control.w; } -<@if GPU_FEATURE_PROFILE == Core @> +<@if GPU_FEATURE_PROFILE == GPU_CORE @> uniform lightBuffer { Light light; }; diff --git a/libraries/model/src/model/Material.slh b/libraries/model/src/model/Material.slh index 739b60502e..6b8eea18a6 100644 --- a/libraries/model/src/model/Material.slh +++ b/libraries/model/src/model/Material.slh @@ -25,7 +25,7 @@ float getMaterialShininess(Material m) { return m._specular.a; } -<@if GPU_FEATURE_PROFILE == Core@> +<@if GPU_FEATURE_PROFILE == GPU_CORE@> uniform materialBuffer { Material _mat; }; diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index ccfe25297c..87d187086d 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -495,7 +495,7 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit GLint loc = -1; -#if (GPU_FEATURE_PROFILE == Core) +#if (GPU_FEATURE_PROFILE == GPU_CORE) loc = glGetUniformBlockIndex(program.programId(), "lightBuffer"); if (loc >= 0) { glUniformBlockBinding(program.programId(), loc, 0); @@ -512,7 +512,7 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit } #endif -#if (GPU_FEATURE_PROFILE == Core) +#if (GPU_FEATURE_PROFILE == GPU_CORE) loc = glGetUniformBlockIndex(program.programId(), "atmosphereBufferUnit"); if (loc >= 0) { glUniformBlockBinding(program.programId(), loc, 1); diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index d3369572ff..73abd46480 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -200,7 +200,7 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo // bindable uniform version -#if (GPU_FEATURE_PROFILE == Core) +#if (GPU_FEATURE_PROFILE == GPU_CORE) loc = glGetUniformBlockIndex(program.programId(), "materialBuffer"); if (loc >= 0) { glUniformBlockBinding(program.programId(), loc, 1); @@ -217,7 +217,7 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo } #endif -#if (GPU_FEATURE_PROFILE == Core) +#if (GPU_FEATURE_PROFILE == GPU_CORE) loc = glGetUniformBlockIndex(program.programId(), "transformObjectBuffer"); if (loc >= 0) { glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_OBJECT_SLOT); @@ -225,7 +225,7 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo } #endif -#if (GPU_FEATURE_PROFILE == Core) +#if (GPU_FEATURE_PROFILE == GPU_CORE) loc = glGetUniformBlockIndex(program.programId(), "transformCameraBuffer"); if (loc >= 0) { glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_CAMERA_SLOT); diff --git a/libraries/render-utils/src/Shadow.slh b/libraries/render-utils/src/Shadow.slh index 70c0ac02de..2e75e2764c 100755 --- a/libraries/render-utils/src/Shadow.slh +++ b/libraries/render-utils/src/Shadow.slh @@ -16,7 +16,7 @@ uniform sampler2DShadow shadowMap; // Fetching it float fetchShadow(vec3 texcoord) { -<@if GPU_FEATURE_PROFILE == Core @> +<@if GPU_FEATURE_PROFILE == GPU_CORE @> return texture(shadowMap, texcoord); <@else@> return shadow2D(shadowMap, texcoord).r; From 8eec83c14489008c8c5de35de14d18bab08bccf1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 17 Mar 2015 22:28:38 -0700 Subject: [PATCH 013/177] comments and formatting --- libraries/physics/src/CharacterController.cpp | 17 ++++++++++++----- libraries/physics/src/CharacterController.h | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index ae408a9aea..6fdf55abed 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -90,6 +90,9 @@ class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::Clo hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; } + // Note: hitNormalWorld points into character, away from object + // and m_up points opposite to movement + btScalar dotUp = m_up.dot(hitNormalWorld); if (dotUp < m_minSlopeDot) { return btScalar(1.0); @@ -209,10 +212,10 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray); } - for (int j=0;j<m_manifoldArray.size();j++) { + for (int j = 0;j < m_manifoldArray.size(); j++) { btPersistentManifold* manifold = m_manifoldArray[j]; - btScalar directionSign = manifold->getBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0); - for (int p=0;p<manifold->getNumContacts();p++) { + btScalar directionSign = (manifold->getBody0() == m_ghostObject) ? btScalar(-1.0) : btScalar(1.0); + for (int p = 0;p < manifold->getNumContacts(); p++) { const btManifoldPoint&pt = manifold->getContactPoint(p); btScalar dist = pt.getDistance(); @@ -570,6 +573,11 @@ void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScala btTransform xform; xform = m_ghostObject->getWorldTransform(); + // the algorithm is as follows: + // (1) step the character up a little bit so that its forward step doesn't hit the floor + // (2) step the character forward + // (3) step the character down so that its back in contact with the ground + stepUp (collisionWorld); if (m_useWalkDirection) { stepForwardAndStrafe(collisionWorld, m_walkDirection); @@ -679,8 +687,7 @@ void CharacterController::createShapeAndGhost() { glm::vec3 offset = box.getCorner() + 0.5f * diagonal; m_shapeLocalOffset = offset; - const float MIN_STEP_HEIGHT = 0.35f; - m_stepHeight = glm::max(MIN_STEP_HEIGHT, radius + 0.5f * halfHeight); + m_stepHeight = 0.1f; // create new shape m_convexShape = new btCapsuleShape(radius, 2.0f * halfHeight); diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 436f9a7277..1805dcba74 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -58,7 +58,7 @@ protected: btScalar m_turnAngle; - btScalar m_stepHeight; + btScalar m_stepHeight; // height of stepUp prior to stepForward btScalar m_addedMargin;//@todo: remove this and fix the code @@ -75,7 +75,7 @@ protected: btManifoldArray m_manifoldArray; bool m_touchingContact; - btVector3 m_touchingNormal; + btVector3 m_touchingNormal; // points from character to object bool m_enabled; bool m_wasOnGround; From 8b5ade10b83b5c71de0616ca9d3a7c3eed8d8822 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Wed, 18 Mar 2015 18:53:08 +0100 Subject: [PATCH 014/177] Initial add of the Attribution property --- libraries/entities/src/EntityItem.cpp | 10 +++++++++- libraries/entities/src/EntityItem.h | 4 ++++ libraries/entities/src/EntityItemProperties.cpp | 10 ++++++++++ libraries/entities/src/EntityItemProperties.h | 5 +++++ libraries/entities/src/EntityItemPropertiesDefaults.h | 1 + libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/networking/src/PacketHeaders.h | 1 + 7 files changed, 31 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 4f74438a45..d0f727642f 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -57,6 +57,7 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _collisionsWillMove = ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE; _locked = ENTITY_ITEM_DEFAULT_LOCKED; _userData = ENTITY_ITEM_DEFAULT_USER_DATA; + _attribution = ENTITY_ITEM_DEFAULT_ATTRIBUTION; } EntityItem::EntityItem(const EntityItemID& entityItemID) { @@ -116,6 +117,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_COLLISIONS_WILL_MOVE; requestedProperties += PROP_LOCKED; requestedProperties += PROP_USER_DATA; + requestedProperties += PROP_ATTRIBUTION; return requestedProperties; } @@ -245,6 +247,8 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet propertiesDidntFit, propertyCount, appendState); + + APPEND_ENTITY_PROPERTY(PROP_ATTRIBUTION, appendValue, getAttribution()); } if (propertyCount > 0) { @@ -550,9 +554,11 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY_SETTER(PROP_IGNORE_FOR_COLLISIONS, bool, updateIgnoreForCollisions); READ_ENTITY_PROPERTY_SETTER(PROP_COLLISIONS_WILL_MOVE, bool, updateCollisionsWillMove); READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked); - READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA,setUserData); + READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA, setUserData); bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); + + READ_ENTITY_PROPERTY_STRING(PROP_ATTRIBUTION, setAttribution); if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) { // NOTE: This code is attempting to "repair" the old data we just got from the server to make it more @@ -820,6 +826,7 @@ EntityItemProperties EntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(attribution, getAttribution); properties._defaultSettings = false; @@ -848,6 +855,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(attribution, setAttribution); if (somethingChanged) { somethingChangedNotification(); // notify derived classes that something has changed diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 5193aa4490..8d007992f6 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -251,6 +251,9 @@ public: const QString& getUserData() const { return _userData; } void setUserData(const QString& value) { _userData = value; } + const QString& getAttribution() const { return _attribution; } + void setAttribution(const QString& value) { _attribution = value; } + // TODO: get rid of users of getRadius()... float getRadius() const; @@ -338,6 +341,7 @@ protected: bool _collisionsWillMove; bool _locked; QString _userData; + QString _attribution; // NOTE: Damping is applied like this: v *= pow(1 - damping, dt) // diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 2b8e82d28f..e83692de47 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -70,6 +70,7 @@ EntityItemProperties::EntityItemProperties() : CONSTRUCT_PROPERTY(emitStrength, ParticleEffectEntityItem::DEFAULT_EMIT_STRENGTH), CONSTRUCT_PROPERTY(localGravity, ParticleEffectEntityItem::DEFAULT_LOCAL_GRAVITY), CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS), + CONSTRUCT_PROPERTY(attribution, ENTITY_ITEM_DEFAULT_ATTRIBUTION), _id(UNKNOWN_ENTITY_ID), _idSet(false), @@ -246,6 +247,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_EMIT_STRENGTH, emitStrength); CHECK_PROPERTY_CHANGE(PROP_LOCAL_GRAVITY, localGravity); CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius); + CHECK_PROPERTY_CHANGE(PROP_ATTRIBUTION, attribution); return changedProperties; } @@ -308,6 +310,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(emitStrength); COPY_PROPERTY_TO_QSCRIPTVALUE(localGravity); COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius); + COPY_PROPERTY_TO_QSCRIPTVALUE(attribution); // Sitting properties support QScriptValue sittingPoints = engine->newObject(); @@ -389,6 +392,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(emitStrength, setEmitStrength); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localGravity, setLocalGravity); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(particleRadius, setParticleRadius); + COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(attribution, setAttribution); _lastEdited = usecTimestampNow(); } @@ -573,6 +577,8 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, appendValue, properties.getLocalGravity()); APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, properties.getParticleRadius()); } + + APPEND_ENTITY_PROPERTY(PROP_ATTRIBUTION, appendValue, properties.getAttribution()); } if (propertyCount > 0) { int endOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -803,6 +809,8 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius); } + READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ATTRIBUTION, setAttribution); + return valid; } @@ -883,6 +891,8 @@ void EntityItemProperties::markAllChanged() { _emitStrengthChanged = true; _localGravityChanged = true; _particleRadiusChanged = true; + + _attributionChanged = true; } /// The maximum bounding cube for the entity, independent of it's rotation. diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 308a2d23bb..28c48c889b 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -103,6 +103,9 @@ enum EntityPropertyList { PROP_LINE_HEIGHT = PROP_ANIMATION_URL, PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS, PROP_COLLISION_MODEL_URL, + + // used by Model entities + PROP_ATTRIBUTION }; typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags; @@ -195,6 +198,7 @@ public: DEFINE_PROPERTY(PROP_EMIT_STRENGTH, EmitStrength, emitStrength, float); DEFINE_PROPERTY(PROP_LOCAL_GRAVITY, LocalGravity, localGravity, float); DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float); + DEFINE_PROPERTY_REF(PROP_ATTRIBUTION, Attribution, attribution, QString); public: float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); } @@ -322,6 +326,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitStrength, emitStrength, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalGravity, localGravity, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, Attribution, attribution, ""); debug << " last edited:" << properties.getLastEdited() << "\n"; debug << " edited ago:" << properties.getEditedAgo() << "\n"; diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index b184d510b3..e57aea3d85 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -22,6 +22,7 @@ const glm::vec3 ENTITY_ITEM_ZERO_VEC3(0.0f); const bool ENTITY_ITEM_DEFAULT_LOCKED = false; const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString(""); +const QString ENTITY_ITEM_DEFAULT_ATTRIBUTION = QString(""); const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f; diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index a14191bf09..abac09d238 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_HAS_COLLISION_MODEL; + return VERSION_ENTITIES_HAS_ATTRIBUTION; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index f930fd9632..81195d13d4 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -132,6 +132,7 @@ const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10; const PacketVersion VERSION_ENTITIES_USE_METERS_AND_RADIANS = 11; const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 12; +const PacketVersion VERSION_ENTITIES_HAS_ATTRIBUTION = 13; const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; #endif // hifi_PacketHeaders_h From 00f1d96af5060180a375a8cbf7b9deb35cbeeb79 Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski <stojce@me.com> Date: Wed, 18 Mar 2015 19:30:08 +0100 Subject: [PATCH 015/177] Use existing house models --- examples/example/entities/makeHouses.js | 33 ++++++++++++++++++------- 1 file changed, 24 insertions(+), 9 deletions(-) diff --git a/examples/example/entities/makeHouses.js b/examples/example/entities/makeHouses.js index 26224fd58a..12205db4ce 100644 --- a/examples/example/entities/makeHouses.js +++ b/examples/example/entities/makeHouses.js @@ -25,23 +25,38 @@ }; /**/ - var modelUrl = "http://localhost/~stojce/models/3-Buildings-2-SanFranciscoHouse-"; - var modelurlExt = ".fbx"; - var modelVariations = 90; + // + // var modelUrl = "http://localhost/~stojce/models/3-Buildings-2-SanFranciscoHouse-"; + // var modelurlExt = ".fbx"; + // var modelVariations = 100; + + var houseModels = [ + "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseBlue.fbx", + "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseBlue3.fbx", + "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseGreen.fbx", + "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseGreen2.fbx", + "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseRed.fbx", + "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseRose.fbx", + "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseViolet.fbx", + "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseYellow.fbx", + "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseYellow2.fbx" + ]; + var houses = []; function addHouseAt(position, rotation) { // get random house model - var modelNumber = 1 + Math.floor(Math.random() * (modelVariations - 1)); - var modUrl = modelUrl + modelNumber + modelurlExt; - print("Model ID:" + modelNumber); - + //var modelNumber = 1 + Math.floor(Math.random() * (modelVariations - 1)); + //var modelUrl = modelUrl + modelNumber + modelurlExt; + //print("Model ID:" + modelNumber); + var modelUrl = houseModels[Math.floor(Math.random() * houseModels.length)]; + var properties = { type: "Model", position: position, rotation: rotation, dimensions: sizeOfTheHouse, - modelURL: modUrl + modelURL: modelUrl }; return Entities.addEntity(properties); @@ -77,7 +92,7 @@ z: dd }; - print("House nr.:" + houses.length + 1); + print("House nr.:" + (houses.length + 1)); houses.push( addHouseAt(Vec3.sum(housePos, posShift), (j % 2 == 0) ? rotEven : rotOdd) ); From 0bd78be7f40d39233399914f5b33d1ae38aa8761 Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Wed, 18 Mar 2015 15:57:01 -0700 Subject: [PATCH 016/177] Transition model shaders to gpu:Shader --- libraries/gpu/src/gpu/Batch.h | 5 +- libraries/gpu/src/gpu/GLBackendShader.cpp | 26 +- libraries/gpu/src/gpu/Shader.h | 38 +- libraries/gpu/src/gpu/Transform.slh | 37 +- .../src/DeferredLightingEffect.cpp | 8 +- libraries/render-utils/src/Model.cpp | 537 ++++++++++++------ libraries/render-utils/src/Model.h | 80 ++- 7 files changed, 507 insertions(+), 224 deletions(-) diff --git a/libraries/gpu/src/gpu/Batch.h b/libraries/gpu/src/gpu/Batch.h index 84358b7ae1..3468e75738 100644 --- a/libraries/gpu/src/gpu/Batch.h +++ b/libraries/gpu/src/gpu/Batch.h @@ -56,8 +56,11 @@ enum Primitive { }; enum ReservedSlot { - TRANSFORM_OBJECT_SLOT = 6, +/* TRANSFORM_OBJECT_SLOT = 6, TRANSFORM_CAMERA_SLOT = 7, + */ + TRANSFORM_OBJECT_SLOT = 1, + TRANSFORM_CAMERA_SLOT = 2, }; class Batch { diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 48ae0eb7c9..0fe1eb07f3 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -41,6 +41,12 @@ void makeBindings(GLBackend::GLShader* shader) { glBindAttribLocation(glprogram, gpu::Stream::POSITION, "position"); } + //Check for gpu specific attribute slotBindings + loc = glGetAttribLocation(glprogram, "gl_Vertex"); + if (loc >= 0) { + glBindAttribLocation(glprogram, gpu::Stream::POSITION, "position"); + } + loc = glGetAttribLocation(glprogram, "normal"); if (loc >= 0) { glBindAttribLocation(glprogram, gpu::Stream::NORMAL, "normal"); @@ -520,18 +526,32 @@ int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, S // The uniform as a standard var type if (location != INVALID_UNIFORM_LOCATION) { + // Let's make sure the name doesn't contains an array element + std::string sname(name); + auto foundBracket = sname.find_first_of('['); + if (foundBracket != std::string::npos) { + // std::string arrayname = sname.substr(0, foundBracket); + + if (sname[foundBracket + 1] == '0') { + sname = sname.substr(0, foundBracket); + } else { + // skip this uniform since it's not the first element of an array + continue; + } + } + if (elementResource._resource == Resource::BUFFER) { - uniforms.insert(Shader::Slot(name, location, elementResource._element, elementResource._resource)); + uniforms.insert(Shader::Slot(sname, location, elementResource._element, elementResource._resource)); } else { // For texture/Sampler, the location is the actual binding value GLint binding = -1; glGetUniformiv(glprogram, location, &binding); - auto requestedBinding = slotBindings.find(std::string(name)); + auto requestedBinding = slotBindings.find(std::string(sname)); if (requestedBinding != slotBindings.end()) { if (binding != (*requestedBinding)._location) { binding = (*requestedBinding)._location; - glUniform1i(location, binding); + glProgramUniform1i(glprogram, location, binding); } } diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 9a5bec313b..535faff64c 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -41,31 +41,51 @@ public: Language _lang = GLSL; }; + static const uint32 INVALID_LOCATION = -1; + class Slot { public: - std::string _name; - uint32 _location; - Element _element; - uint16 _resourceType; + std::string _name = (""); + int32 _location = INVALID_LOCATION; + Element _element = Element(); + uint16 _resourceType = Resource::BUFFER; - Slot(const std::string& name, uint16 location, const Element& element, uint16 resourceType = Resource::BUFFER) : + Slot(const Slot&& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType) {} + // Slot& operator&&(const Slot&& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType) {} + Slot(const std::string& name, int32 location, const Element& element, uint16 resourceType = Resource::BUFFER) : _name(name), _location(location), _element(element), _resourceType(resourceType) {} - + Slot(const std::string& name) : _name(name) {} }; class Binding { public: std::string _name; - uint32 _location; - Binding(const std::string&& name, uint32 loc = 0) : _name(name), _location(loc) {} + int32 _location; + Binding(const std::string&& name, int32 loc = INVALID_LOCATION) : _name(name), _location(loc) {} }; template <typename T> class Less { public: bool operator() (const T& x, const T& y) const { return x._name < y._name; } }; - typedef std::set<Slot, Less<Slot>> SlotSet; + + class SlotSet : public std::set<Slot, Less<Slot>> { + public: + const Slot&& findSlot(const std::string& name) const { + auto key = Slot(name); + auto found = static_cast<const std::set<Slot, Less<Slot>>*>(this)->find(key); + if (found != end()) { + return std::move((*found)); + } + return std::move(key); + } + int32 findLocation(const std::string& name) const { + return findSlot(name)._location; + } + protected: + }; + typedef std::set<Binding, Less<Binding>> BindingSet; diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 355713f9ae..93ea0ce9f6 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -28,7 +28,7 @@ vec4 transformModelToClipPos(TransformCamera camera, TransformObject object, vec vec4 epos = (object._model * pos) + vec4(-pos.w * camera._viewInverse[3].xyz, 0.0); return camera._projectionViewUntranslated * epos; // Equivalent to the following but hoppefully a bit more accurate - // return camera._projection * camera._view * object._model * pos; + //return camera._projection * camera._view * object._model * pos; <@else@> return gl_ModelViewProjectionMatrix * pos; <@endif@> @@ -68,14 +68,47 @@ TransformCamera getTransformCamera() { } <@else@> - +uniform vec4 transformObjectBuffer[7]; TransformObject getTransformObject() { TransformObject object; + object._model[0] = transformObjectBuffer[0]; + object._model[1] = transformObjectBuffer[1]; + object._model[2] = transformObjectBuffer[2]; + object._model[3] = transformObjectBuffer[3]; + + object._modelInverse[0] = transformObjectBuffer[4]; + object._modelInverse[1] = transformObjectBuffer[5]; + object._modelInverse[2] = transformObjectBuffer[6]; + object._modelInverse[3] = transformObjectBuffer[7]; + return object; } +uniform vec4 transformCameraBuffer[17]; TransformCamera getTransformCamera() { TransformCamera camera; + camera._view[0] = transformCameraBuffer[0]; + camera._view[1] = transformCameraBuffer[1]; + camera._view[2] = transformCameraBuffer[2]; + camera._view[3] = transformCameraBuffer[3]; + + camera._viewInverse[0] = transformCameraBuffer[4]; + camera._viewInverse[1] = transformCameraBuffer[5]; + camera._viewInverse[2] = transformCameraBuffer[6]; + camera._viewInverse[3] = transformCameraBuffer[7]; + + camera._projectionViewUntranslated[0] = transformCameraBuffer[8]; + camera._projectionViewUntranslated[1] = transformCameraBuffer[9]; + camera._projectionViewUntranslated[2] = transformCameraBuffer[10]; + camera._projectionViewUntranslated[3] = transformCameraBuffer[11]; + + camera._projection[0] = transformCameraBuffer[12]; + camera._projection[1] = transformCameraBuffer[13]; + camera._projection[2] = transformCameraBuffer[14]; + camera._projection[3] = transformCameraBuffer[15]; + + camera._viewport = transformCameraBuffer[16]; + return camera; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 87d187086d..5b1ad44c69 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -498,8 +498,8 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit #if (GPU_FEATURE_PROFILE == GPU_CORE) loc = glGetUniformBlockIndex(program.programId(), "lightBuffer"); if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, 0); - locations.lightBufferUnit = 0; + glUniformBlockBinding(program.programId(), loc, 3); + locations.lightBufferUnit = 3; } else { locations.lightBufferUnit = -1; } @@ -515,8 +515,8 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit #if (GPU_FEATURE_PROFILE == GPU_CORE) loc = glGetUniformBlockIndex(program.programId(), "atmosphereBufferUnit"); if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, 1); - locations.atmosphereBufferUnit = 1; + glUniformBlockBinding(program.programId(), loc, 4); + locations.atmosphereBufferUnit = 4; } else { locations.atmosphereBufferUnit = -1; } diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 73abd46480..17702895d9 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -93,27 +93,66 @@ Model::Model(QObject* parent) : Model::~Model() { deleteGeometry(); } +/* +ProgramObject Model::_POprogram; +ProgramObject Model::_POnormalMapProgram; +ProgramObject Model::_POspecularMapProgram; +ProgramObject Model::_POnormalSpecularMapProgram; +ProgramObject Model::_POtranslucentProgram; -ProgramObject Model::_program; -ProgramObject Model::_normalMapProgram; -ProgramObject Model::_specularMapProgram; -ProgramObject Model::_normalSpecularMapProgram; -ProgramObject Model::_translucentProgram; +ProgramObject Model::_POlightmapProgram; +ProgramObject Model::_POlightmapNormalMapProgram; +ProgramObject Model::_POlightmapSpecularMapProgram; +ProgramObject Model::_POlightmapNormalSpecularMapProgram; -ProgramObject Model::_lightmapProgram; -ProgramObject Model::_lightmapNormalMapProgram; -ProgramObject Model::_lightmapSpecularMapProgram; -ProgramObject Model::_lightmapNormalSpecularMapProgram; +ProgramObject Model::_POshadowProgram; -ProgramObject Model::_shadowProgram; +ProgramObject Model::_POskinProgram; +ProgramObject Model::_POskinNormalMapProgram; +ProgramObject Model::_POskinSpecularMapProgram; +ProgramObject Model::_POskinNormalSpecularMapProgram; +ProgramObject Model::_POskinTranslucentProgram; -ProgramObject Model::_skinProgram; -ProgramObject Model::_skinNormalMapProgram; -ProgramObject Model::_skinSpecularMapProgram; -ProgramObject Model::_skinNormalSpecularMapProgram; -ProgramObject Model::_skinTranslucentProgram; +ProgramObject Model::_POskinShadowProgram; -ProgramObject Model::_skinShadowProgram; +Model::Locations Model::_POlocations; +Model::Locations Model::_POnormalMapLocations; +Model::Locations Model::_POspecularMapLocations; +Model::Locations Model::_POnormalSpecularMapLocations; +Model::Locations Model::_POtranslucentLocations; + +Model::Locations Model::_POlightmapLocations; +Model::Locations Model::_POlightmapNormalMapLocations; +Model::Locations Model::_POlightmapSpecularMapLocations; +Model::Locations Model::_POlightmapNormalSpecularMapLocations; + +Model::SkinLocations Model::_POskinLocations; +Model::SkinLocations Model::_POskinNormalMapLocations; +Model::SkinLocations Model::_POskinSpecularMapLocations; +Model::SkinLocations Model::_POskinNormalSpecularMapLocations; +Model::SkinLocations Model::_POskinShadowLocations; +Model::SkinLocations Model::_POskinTranslucentLocations; +*/ +gpu::ShaderPointer Model::_program; +gpu::ShaderPointer Model::_normalMapProgram; +gpu::ShaderPointer Model::_specularMapProgram; +gpu::ShaderPointer Model::_normalSpecularMapProgram; +gpu::ShaderPointer Model::_translucentProgram; + +gpu::ShaderPointer Model::_lightmapProgram; +gpu::ShaderPointer Model::_lightmapNormalMapProgram; +gpu::ShaderPointer Model::_lightmapSpecularMapProgram; +gpu::ShaderPointer Model::_lightmapNormalSpecularMapProgram; + +gpu::ShaderPointer Model::_shadowProgram; + +gpu::ShaderPointer Model::_skinProgram; +gpu::ShaderPointer Model::_skinNormalMapProgram; +gpu::ShaderPointer Model::_skinSpecularMapProgram; +gpu::ShaderPointer Model::_skinNormalSpecularMapProgram; +gpu::ShaderPointer Model::_skinTranslucentProgram; + +gpu::ShaderPointer Model::_skinShadowProgram; Model::Locations Model::_locations; Model::Locations Model::_normalMapLocations; @@ -135,6 +174,8 @@ Model::SkinLocations Model::_skinTranslucentLocations; AbstractViewStateInterface* Model::_viewState = NULL; +const GLint MATERIAL_GPU_SLOT = 3; + void Model::setScale(const glm::vec3& scale) { setScaleInternal(scale); // if anyone sets scale manually, then we are no longer scaled to fit @@ -165,6 +206,33 @@ void Model::setOffset(const glm::vec3& offset) { _snappedToRegistrationPoint = false; } +void Model::initProgram(gpu::ShaderPointer& program, Model::Locations& locations) { + locations.alphaThreshold = program->getUniforms().findLocation("alphaThreshold"); + locations.texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices"); + locations.emissiveParams = program->getUniforms().findLocation("emissiveParams"); + locations.glowIntensity = program->getUniforms().findLocation("glowIntensity"); + + locations.specularTextureUnit = program->getTextures().findLocation("specularMap"); + locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap"); + +#if (GPU_FEATURE_PROFILE == GPU_CORE) + locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); +#else + locations.materialBuffer = program->getUniforms().findLocation("materialBuffer"); +#endif + +} + +void Model::initSkinProgram(gpu::ShaderPointer& program, Model::SkinLocations& locations) { + + initProgram(program, locations); + + locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices"); + + locations.clusterIndices = program->getInputs().findLocation("clusterIndices");; + locations.clusterWeights = program->getInputs().findLocation("clusterWeights");; +} +/* void Model::initProgram(ProgramObject& program, Model::Locations& locations, bool link) { if (link) { program.bindAttributeLocation("tangent", gpu::Stream::TANGENT); @@ -203,8 +271,8 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo #if (GPU_FEATURE_PROFILE == GPU_CORE) loc = glGetUniformBlockIndex(program.programId(), "materialBuffer"); if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, 1); - locations.materialBufferUnit = 1; + glUniformBlockBinding(program.programId(), loc, MATERIAL_GPU_SLOT); + locations.materialBufferUnit = MATERIAL_GPU_SLOT; } else { locations.materialBufferUnit = -1; } @@ -239,8 +307,8 @@ void Model::initProgram(ProgramObject& program, Model::Locations& locations, boo } program.release(); -} - +}*/ +/* void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations) { program.bindAttributeLocation("tangent", gpu::Stream::TANGENT); program.bindAttributeLocation("texcoord1", gpu::Stream::TEXCOORD1); @@ -257,7 +325,7 @@ void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locati locations.clusterWeights = program.attributeLocation("clusterWeights"); program.release(); -} +}*/ QVector<JointState> Model::createJointStates(const FBXGeometry& geometry) { QVector<JointState> jointStates; @@ -292,10 +360,11 @@ void Model::initJointTransforms() { } void Model::init() { - if (!_program.isLinked()) { -/* //Work in progress not used yet + if (_program.isNull()) { + // if (!_program.isLinked()) { + //Work in progress not used yet gpu::Shader::BindingSet slotBindings; - slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), 1)); + slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1)); slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2)); @@ -327,124 +396,142 @@ void Model::init() { bool makeResult = false; // Programs - auto program = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelPixel)); - makeResult = gpu::Shader::makeProgram(*program, slotBindings); - - auto normalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalMapPixel)); - makeResult = gpu::Shader::makeProgram(*normalMapProgram, slotBindings); - - auto specularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*specularMapProgram, slotBindings); - - auto normalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*normalSpecularMapProgram, slotBindings); - - auto translucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelTranslucentPixel)); - makeResult = gpu::Shader::makeProgram(*translucentProgram, slotBindings); - - auto shadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelShadowVertex, modelShadowPixel)); - makeResult = gpu::Shader::makeProgram(*shadowProgram, slotBindings); - - auto lightmapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapPixel)); - makeResult = gpu::Shader::makeProgram(*lightmapProgram, slotBindings); - - auto lightmapNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalMapPixel)); - makeResult = gpu::Shader::makeProgram(*lightmapNormalMapProgram, slotBindings); - - auto lightmapSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*lightmapSpecularMapProgram, slotBindings); - - auto lightmapNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*lightmapNormalSpecularMapProgram, slotBindings); - - auto skinProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelPixel)); - makeResult = gpu::Shader::makeProgram(*skinProgram, slotBindings); - - auto skinNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalMapPixel)); - makeResult = gpu::Shader::makeProgram(*skinNormalMapProgram, slotBindings); - - auto skinSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*skinSpecularMapProgram, slotBindings); - - auto skinNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalSpecularMapPixel)); - makeResult = gpu::Shader::makeProgram(*skinNormalSpecularMapProgram, slotBindings); - - auto skinShadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelShadowVertex, modelShadowPixel)); - makeResult = gpu::Shader::makeProgram(*skinShadowProgram, slotBindings); - - auto skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel)); - makeResult = gpu::Shader::makeProgram(*skinTranslucentProgram, slotBindings); -*/ - - _program.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _program.addShaderFromSourceCode(QGLShader::Fragment, model_frag); + _program = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelPixel)); + makeResult = gpu::Shader::makeProgram(*_program, slotBindings); initProgram(_program, _locations); + + _normalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalMapPixel)); + makeResult = gpu::Shader::makeProgram(*_normalMapProgram, slotBindings); + initProgram(_normalMapProgram, _normalMapLocations); + + _specularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*_specularMapProgram, slotBindings); + initProgram(_specularMapProgram, _specularMapLocations); + + _normalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*_normalSpecularMapProgram, slotBindings); + initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations); + + _translucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelTranslucentPixel)); + makeResult = gpu::Shader::makeProgram(*_translucentProgram, slotBindings); + initProgram(_translucentProgram, _translucentLocations); + + _shadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelShadowVertex, modelShadowPixel)); + makeResult = gpu::Shader::makeProgram(*_shadowProgram, slotBindings); + Model::Locations tempShadowLoc; + initProgram(_shadowProgram, tempShadowLoc); + + _lightmapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapPixel)); + makeResult = gpu::Shader::makeProgram(*_lightmapProgram, slotBindings); + initProgram(_lightmapProgram, _lightmapLocations); + + _lightmapNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalMapPixel)); + makeResult = gpu::Shader::makeProgram(*_lightmapNormalMapProgram, slotBindings); + initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations); + + _lightmapSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*_lightmapSpecularMapProgram, slotBindings); + initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations); + + _lightmapNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*_lightmapNormalSpecularMapProgram, slotBindings); + initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations); + + _skinProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelPixel)); + makeResult = gpu::Shader::makeProgram(*_skinProgram, slotBindings); + initSkinProgram(_skinProgram, _skinLocations); + + _skinNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalMapPixel)); + makeResult = gpu::Shader::makeProgram(*_skinNormalMapProgram, slotBindings); + initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); + + _skinSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*_skinSpecularMapProgram, slotBindings); + initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); + + _skinNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalSpecularMapPixel)); + makeResult = gpu::Shader::makeProgram(*_skinNormalSpecularMapProgram, slotBindings); + initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations); + + _skinShadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelShadowVertex, modelShadowPixel)); + makeResult = gpu::Shader::makeProgram(*_skinShadowProgram, slotBindings); + initSkinProgram(_skinShadowProgram, _skinShadowLocations); + + _skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel)); + makeResult = gpu::Shader::makeProgram(*_skinTranslucentProgram, slotBindings); + initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); + + /* + _POprogram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _POprogram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); + initProgram(_POprogram, _POlocations); - _normalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); - _normalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); - initProgram(_normalMapProgram, _normalMapLocations); + _POnormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); + _POnormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); + initProgram(_POnormalMapProgram, _POnormalMapLocations); - _specularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _specularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); - initProgram(_specularMapProgram, _specularMapLocations); + _POspecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _POspecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); + initProgram(_POspecularMapProgram, _POspecularMapLocations); - _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); - _normalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); - initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations); + _POnormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); + _POnormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); + initProgram(_POnormalSpecularMapProgram, _POnormalSpecularMapLocations); - _translucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _translucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); - initProgram(_translucentProgram, _translucentLocations); + _POtranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _POtranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); + initProgram(_POtranslucentProgram, _POtranslucentLocations); // Lightmap - _lightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); - _lightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag); - initProgram(_lightmapProgram, _lightmapLocations); + _POlightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); + _POlightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag); + initProgram(_POlightmapProgram, _POlightmapLocations); - _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); - _lightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag); - initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations); + _POlightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); + _POlightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag); + initProgram(_POlightmapNormalMapProgramddd, _POlightmapNormalMapLocations); - _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); - _lightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag); - initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations); + _POlightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); + _POlightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag); + initProgram(_POlightmapSpecularMapProgram, _POlightmapSpecularMapLocations); - _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); - _lightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag); - initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations); + _POlightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); + _POlightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag); + initProgram(_POlightmapNormalSpecularMapProgram, _POlightmapNormalSpecularMapLocations); // end lightmap - _shadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert); - _shadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); + _POshadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert); + _POshadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); // Shadow program uses the same locations as standard rendering path but we still need to set the bindings Model::Locations tempLoc; - initProgram(_shadowProgram, tempLoc); + initProgram(_POshadowProgram, tempLoc); - _skinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); - _skinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); - initSkinProgram(_skinProgram, _skinLocations); + _POskinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); + _POskinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); + initSkinProgram(_POskinProgram, _POskinLocations); - _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); - _skinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); - initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); + _POskinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); + _POskinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); + initSkinProgram(_POskinNormalMapProgram, _PaOskinNormalMapLocations); - _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _skinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); - initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); + _POskinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _POskinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); + initSkinProgram(_POskinSpecularMapProgram, _POskinSpecularMapLocations); - _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); - _skinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); - initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations); + _POskinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); + _POskinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); + initSkinProgram(_POskinNormalSpecularMapProgram, _POskinNormalSpecularMapLocations); - _skinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert); - _skinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); - initSkinProgram(_skinShadowProgram, _skinShadowLocations); + _POskinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert); + _POskinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); + initSkinProgram(_POskinShadowProgram, _POskinShadowLocations); - _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); - _skinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); - initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); + _POskinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); + _POskinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); + initSkinProgram(_POskinTranslucentProgram, _POskinTranslucentLocations); + */ } } @@ -2302,83 +2389,165 @@ QVector<int>* Model::pickMeshList(bool translucent, float alphaThreshold, bool h void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, Locations*& locations, SkinLocations*& skinLocations) { - - ProgramObject* program = &_program; - locations = &_locations; - ProgramObject* skinProgram = &_skinProgram; - skinLocations = &_skinLocations; - if (mode == SHADOW_RENDER_MODE) { - program = &_shadowProgram; - skinProgram = &_skinShadowProgram; - skinLocations = &_skinShadowLocations; - } else if (translucent && alphaThreshold == 0.0f) { - program = &_translucentProgram; - locations = &_translucentLocations; - skinProgram = &_skinTranslucentProgram; - skinLocations = &_skinTranslucentLocations; +/* if (false) + { + ProgramObject* program = &_POprogram; + locations = &_POlocations; + ProgramObject* skinProgram = &_POskinProgram; + skinLocations = &_POskinLocations; + if (mode == SHADOW_RENDER_MODE) { + program = &_POshadowProgram; + skinProgram = &_POskinShadowProgram; + skinLocations = &_POskinShadowLocations; + } else if (translucent && alphaThreshold == 0.0f) { + program = &_POtranslucentProgram; + locations = &_POtranslucentLocations; + skinProgram = &_POskinTranslucentProgram; + skinLocations = &_POskinTranslucentLocations; - } else if (hasLightmap) { - if (hasTangents) { - if (hasSpecular) { - program = &_lightmapNormalSpecularMapProgram; - locations = &_lightmapNormalSpecularMapLocations; + } else if (hasLightmap) { + if (hasTangents) { + if (hasSpecular) { + program = &_POlightmapNormalSpecularMapProgram; + locations = &_POlightmapNormalSpecularMapLocations; + skinProgram = NULL; + skinLocations = NULL; + } else { + program = &_POlightmapNormalMapProgram; + locations = &_POlightmapNormalMapLocations; + skinProgram = NULL; + skinLocations = NULL; + } + } else if (hasSpecular) { + program = &_POlightmapSpecularMapProgram; + locations = &_POlightmapSpecularMapLocations; skinProgram = NULL; skinLocations = NULL; } else { - program = &_lightmapNormalMapProgram; - locations = &_lightmapNormalMapLocations; + program = &_POlightmapProgram; + locations = &_POlightmapLocations; skinProgram = NULL; skinLocations = NULL; } - } else if (hasSpecular) { - program = &_lightmapSpecularMapProgram; - locations = &_lightmapSpecularMapLocations; - skinProgram = NULL; - skinLocations = NULL; } else { - program = &_lightmapProgram; - locations = &_lightmapLocations; - skinProgram = NULL; - skinLocations = NULL; - } - } else { - if (hasTangents) { - if (hasSpecular) { - program = &_normalSpecularMapProgram; - locations = &_normalSpecularMapLocations; - skinProgram = &_skinNormalSpecularMapProgram; - skinLocations = &_skinNormalSpecularMapLocations; - } else { - program = &_normalMapProgram; - locations = &_normalMapLocations; - skinProgram = &_skinNormalMapProgram; - skinLocations = &_skinNormalMapLocations; + if (hasTangents) { + if (hasSpecular) { + program = &_POnormalSpecularMapProgram; + locations = &_POnormalSpecularMapLocations; + skinProgram = &_POskinNormalSpecularMapProgram; + skinLocations = &_POskinNormalSpecularMapLocations; + } else { + program = &_POnormalMapProgram; + locations = &_POnormalMapLocations; + skinProgram = &_POskinNormalMapProgram; + skinLocations = &_POskinNormalMapLocations; + } + } else if (hasSpecular) { + program = &_POspecularMapProgram; + locations = &_POspecularMapLocations; + skinProgram = &_POskinSpecularMapProgram; + skinLocations = &_POskinSpecularMapLocations; } - } else if (hasSpecular) { - program = &_specularMapProgram; - locations = &_specularMapLocations; - skinProgram = &_skinSpecularMapProgram; - skinLocations = &_skinSpecularMapLocations; + } + + ProgramObject* activeProgram = program; + Locations* activeLocations = locations; + + if (isSkinned) { + activeProgram = skinProgram; + activeLocations = skinLocations; + locations = skinLocations; + } + // This code replace the "bind()" on the QGLProgram + if (!activeProgram->isLinked()) { + activeProgram->link(); } - } - ProgramObject* activeProgram = program; - Locations* activeLocations = locations; - - if (isSkinned) { - activeProgram = skinProgram; - activeLocations = skinLocations; - locations = skinLocations; - } - // This code replace the "bind()" on the QGLProgram - if (!activeProgram->isLinked()) { - activeProgram->link(); - } + GLBATCH(glUseProgram)(activeProgram->programId()); - GLBATCH(glUseProgram)(activeProgram->programId()); - if ((activeLocations->alphaThreshold > -1) && (mode != SHADOW_RENDER_MODE)) { - GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold); + if ((activeLocations->alphaThreshold > -1) && (mode != SHADOW_RENDER_MODE)) { + GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold); + } + + } + else */ + { + gpu::ShaderPointer program = _program; + locations = &_locations; + gpu::ShaderPointer skinProgram = _skinProgram; + skinLocations = &_skinLocations; + if (mode == SHADOW_RENDER_MODE) { + program = _shadowProgram; + skinProgram = _skinShadowProgram; + skinLocations = &_skinShadowLocations; + } else if (translucent && alphaThreshold == 0.0f) { + program = _translucentProgram; + locations = &_translucentLocations; + skinProgram = _skinTranslucentProgram; + skinLocations = &_skinTranslucentLocations; + + } else if (hasLightmap) { + if (hasTangents) { + if (hasSpecular) { + program = _lightmapNormalSpecularMapProgram; + locations = &_lightmapNormalSpecularMapLocations; + skinProgram.reset(nullptr); + skinLocations = NULL; + } else { + program = _lightmapNormalMapProgram; + locations = &_lightmapNormalMapLocations; + skinProgram.reset(nullptr); + skinLocations = NULL; + } + } else if (hasSpecular) { + program = _lightmapSpecularMapProgram; + locations = &_lightmapSpecularMapLocations; + skinProgram.reset(nullptr); + skinLocations = NULL; + } else { + program = _lightmapProgram; + locations = &_lightmapLocations; + skinProgram.reset(nullptr); + skinLocations = NULL; + } + } else { + if (hasTangents) { + if (hasSpecular) { + program = _normalSpecularMapProgram; + locations = &_normalSpecularMapLocations; + skinProgram = _skinNormalSpecularMapProgram; + skinLocations = &_skinNormalSpecularMapLocations; + } else { + program = _normalMapProgram; + locations = &_normalMapLocations; + skinProgram = _skinNormalMapProgram; + skinLocations = &_skinNormalMapLocations; + } + } else if (hasSpecular) { + program = _specularMapProgram; + locations = &_specularMapLocations; + skinProgram = _skinSpecularMapProgram; + skinLocations = &_skinSpecularMapLocations; + } + } + + gpu::ShaderPointer activeProgram = program; + Locations* activeLocations = locations; + + if (isSkinned) { + activeProgram = skinProgram; + activeLocations = skinLocations; + locations = skinLocations; + } + + GLuint glprogram = gpu::GLBackend::getShaderID(activeProgram); + GLBATCH(glUseProgram)(glprogram); + + + if ((activeLocations->alphaThreshold > -1) && (mode != SHADOW_RENDER_MODE)) { + GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold); + } } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 453d721962..7a7af85a8e 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -309,31 +309,49 @@ private: int _blendNumber; int _appliedBlendNumber; + /* + static ProgramObject _POprogram; + static ProgramObject _POnormalMapProgram; + static ProgramObject _POspecularMapProgram; + static ProgramObject _POnormalSpecularMapProgram; + static ProgramObject _POtranslucentProgram; - static ProgramObject _program; - static ProgramObject _normalMapProgram; - static ProgramObject _specularMapProgram; - static ProgramObject _normalSpecularMapProgram; - static ProgramObject _translucentProgram; + static ProgramObject _POlightmapProgram; + static ProgramObject _POlightmapNormalMapProgram; + static ProgramObject _POlightmapSpecularMapProgram; + static ProgramObject _POlightmapNormalSpecularMapProgram; - static ProgramObject _lightmapProgram; - static ProgramObject _lightmapNormalMapProgram; - static ProgramObject _lightmapSpecularMapProgram; - static ProgramObject _lightmapNormalSpecularMapProgram; - - static ProgramObject _shadowProgram; + static ProgramObject _POshadowProgram; - static ProgramObject _skinProgram; - static ProgramObject _skinNormalMapProgram; - static ProgramObject _skinSpecularMapProgram; - static ProgramObject _skinNormalSpecularMapProgram; - static ProgramObject _skinTranslucentProgram; + static ProgramObject _POskinProgram; + static ProgramObject _POskinNormalMapProgram; + static ProgramObject _POskinSpecularMapProgram; + static ProgramObject _POskinNormalSpecularMapProgram; + static ProgramObject _POskinTranslucentProgram; - static ProgramObject _skinShadowProgram; + static ProgramObject _POskinShadowProgram; + */ + static gpu::ShaderPointer _program; + static gpu::ShaderPointer _normalMapProgram; + static gpu::ShaderPointer _specularMapProgram; + static gpu::ShaderPointer _normalSpecularMapProgram; + static gpu::ShaderPointer _translucentProgram; - static int _normalMapTangentLocation; - static int _normalSpecularMapTangentLocation; + static gpu::ShaderPointer _lightmapProgram; + static gpu::ShaderPointer _lightmapNormalMapProgram; + static gpu::ShaderPointer _lightmapSpecularMapProgram; + static gpu::ShaderPointer _lightmapNormalSpecularMapProgram; + + static gpu::ShaderPointer _shadowProgram; + static gpu::ShaderPointer _skinProgram; + static gpu::ShaderPointer _skinNormalMapProgram; + static gpu::ShaderPointer _skinSpecularMapProgram; + static gpu::ShaderPointer _skinNormalSpecularMapProgram; + static gpu::ShaderPointer _skinTranslucentProgram; + + static gpu::ShaderPointer _skinShadowProgram; + class Locations { public: int tangent; @@ -356,8 +374,20 @@ private: static Locations _lightmapNormalMapLocations; static Locations _lightmapSpecularMapLocations; static Locations _lightmapNormalSpecularMapLocations; - +/* + static Locations _POlocations; + static Locations _POnormalMapLocations; + static Locations _POspecularMapLocations; + static Locations _POnormalSpecularMapLocations; + static Locations _POtranslucentLocations; + + static Locations _POlightmapLocations; + static Locations _POlightmapNormalMapLocations; + static Locations _POlightmapSpecularMapLocations; + static Locations _POlightmapNormalSpecularMapLocations; +*/ static void initProgram(ProgramObject& program, Locations& locations, bool link = true); + static void initProgram(gpu::ShaderPointer& program, Locations& locations); class SkinLocations : public Locations { public: @@ -372,8 +402,16 @@ private: static SkinLocations _skinNormalSpecularMapLocations; static SkinLocations _skinShadowLocations; static SkinLocations _skinTranslucentLocations; - +/* + static SkinLocations _POskinLocations; + static SkinLocations _POskinNormalMapLocations; + static SkinLocations _POskinSpecularMapLocations; + static SkinLocations _POskinNormalSpecularMapLocations; + static SkinLocations _POskinShadowLocations; + static SkinLocations _POskinTranslucentLocations; +*/ static void initSkinProgram(ProgramObject& program, SkinLocations& locations); + static void initSkinProgram(gpu::ShaderPointer& program, SkinLocations& locations); QVector<AABox> _calculatedMeshBoxes; // world coordinate AABoxes for all sub mesh boxes bool _calculatedMeshBoxesValid; From b5eb4a7f5b6fcdbae350c304eb25ffc0a973103b Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Wed, 18 Mar 2015 16:12:47 -0700 Subject: [PATCH 017/177] Since glProgramUniform is not supported on MAc we need a workaround... --- libraries/gpu/src/gpu/GLBackendShader.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 0fe1eb07f3..8391a1a7f9 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -509,6 +509,11 @@ ElementResource getFormatFromGLUniform(GLenum gltype) { int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, Shader::SlotSet& uniforms, Shader::SlotSet& textures, Shader::SlotSet& samplers) { GLint uniformsCount = 0; +#if (GPU_FEATURE_PROFILE == GPU_LEGACY) + GLuint currentProgram = glGetIntegerv(GL_CURRENT_PROGRAM); + glUseProgram(glprogram); +#endif + glGetProgramiv(glprogram, GL_ACTIVE_UNIFORMS, &uniformsCount); for (int i = 0; i < uniformsCount; i++) { @@ -551,7 +556,11 @@ int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, S if (requestedBinding != slotBindings.end()) { if (binding != (*requestedBinding)._location) { binding = (*requestedBinding)._location; +#if (GPU_FEATURE_PROFILE == GPU_LEGACY) + glUniform1i(location, binding); +#else glProgramUniform1i(glprogram, location, binding); +#endif } } @@ -561,6 +570,10 @@ int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, S } } +#if (GPU_FEATURE_PROFILE == GPU_LEGACY) + glUseProgram(currentProgram); +#endif + return uniformsCount; } From 414315b6e066c498fa8a736eda9dad6a91afaa5c Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Wed, 18 Mar 2015 16:15:06 -0700 Subject: [PATCH 018/177] Since glProgramUniform is not supported on MAc we need a workaround... --- libraries/gpu/src/gpu/GLBackendShader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 8391a1a7f9..3d9255faef 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -510,7 +510,8 @@ int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, S GLint uniformsCount = 0; #if (GPU_FEATURE_PROFILE == GPU_LEGACY) - GLuint currentProgram = glGetIntegerv(GL_CURRENT_PROGRAM); + GLuint currentProgram = 0; + glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); glUseProgram(glprogram); #endif From 0f22d648024312e77e565bbdde58b99f54609335 Mon Sep 17 00:00:00 2001 From: samcake <samuel.gateau@gmail.com> Date: Wed, 18 Mar 2015 16:28:42 -0700 Subject: [PATCH 019/177] compilation on MacOSX --- libraries/gpu/src/gpu/GLBackendShader.cpp | 2 +- libraries/gpu/src/gpu/Shader.h | 9 +- libraries/render-utils/src/Model.cpp | 176 +++++++++++----------- 3 files changed, 97 insertions(+), 90 deletions(-) diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 3d9255faef..bcfdc4f36c 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -510,7 +510,7 @@ int makeUniformSlots(GLuint glprogram, const Shader::BindingSet& slotBindings, S GLint uniformsCount = 0; #if (GPU_FEATURE_PROFILE == GPU_LEGACY) - GLuint currentProgram = 0; + GLint currentProgram = 0; glGetIntegerv(GL_CURRENT_PROGRAM, ¤tProgram); glUseProgram(glprogram); #endif diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 535faff64c..d88c2d5a87 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -51,11 +51,18 @@ public: Element _element = Element(); uint16 _resourceType = Resource::BUFFER; + Slot(const Slot& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType) {} Slot(const Slot&& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType) {} - // Slot& operator&&(const Slot&& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType) {} Slot(const std::string& name, int32 location, const Element& element, uint16 resourceType = Resource::BUFFER) : _name(name), _location(location), _element(element), _resourceType(resourceType) {} Slot(const std::string& name) : _name(name) {} + + Slot& operator= (const Slot& s) { + _name = s._name; + _location = s._location; + _element = s._element; + _resourceType = s._resourceType; + return (*this); } }; class Binding { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0be68395ca..47cb2d56f8 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -36,13 +36,13 @@ #include "Model.h" #include "model_vert.h" -#include "model_shadow_vert.h" -#include "model_normal_map_vert.h" -#include "model_lightmap_vert.h" -#include "model_lightmap_normal_map_vert.h" -#include "skin_model_vert.h" -#include "skin_model_shadow_vert.h" -#include "skin_model_normal_map_vert.h" +#include "model_shadow_vert.h" +#include "model_normal_map_vert.h" +#include "model_lightmap_vert.h" +#include "model_lightmap_normal_map_vert.h" +#include "skin_model_vert.h" +#include "skin_model_shadow_vert.h" +#include "skin_model_normal_map_vert.h" #include "model_frag.h" #include "model_shadow_frag.h" @@ -218,7 +218,7 @@ void Model::initProgram(gpu::ShaderPointer& program, Model::Locations& locations #if (GPU_FEATURE_PROFILE == GPU_CORE) locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); #else - locations.materialBuffer = program->getUniforms().findLocation("materialBuffer"); + locations.materialBufferUnit = program->getUniforms().findLocation("materialBuffer"); #endif } @@ -397,11 +397,11 @@ void Model::init() { // Programs _program = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelPixel)); - makeResult = gpu::Shader::makeProgram(*_program, slotBindings); + makeResult = gpu::Shader::makeProgram(*_program, slotBindings); initProgram(_program, _locations); _normalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelNormalMapVertex, modelNormalMapPixel)); - makeResult = gpu::Shader::makeProgram(*_normalMapProgram, slotBindings); + makeResult = gpu::Shader::makeProgram(*_normalMapProgram, slotBindings); initProgram(_normalMapProgram, _normalMapLocations); _specularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelSpecularMapPixel)); @@ -413,122 +413,122 @@ void Model::init() { initProgram(_normalSpecularMapProgram, _normalSpecularMapLocations); _translucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelVertex, modelTranslucentPixel)); - makeResult = gpu::Shader::makeProgram(*_translucentProgram, slotBindings); + makeResult = gpu::Shader::makeProgram(*_translucentProgram, slotBindings); initProgram(_translucentProgram, _translucentLocations); _shadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelShadowVertex, modelShadowPixel)); makeResult = gpu::Shader::makeProgram(*_shadowProgram, slotBindings); - Model::Locations tempShadowLoc; + Model::Locations tempShadowLoc; initProgram(_shadowProgram, tempShadowLoc); _lightmapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapPixel)); - makeResult = gpu::Shader::makeProgram(*_lightmapProgram, slotBindings); + makeResult = gpu::Shader::makeProgram(*_lightmapProgram, slotBindings); initProgram(_lightmapProgram, _lightmapLocations); _lightmapNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalMapPixel)); - makeResult = gpu::Shader::makeProgram(*_lightmapNormalMapProgram, slotBindings); - initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations); + makeResult = gpu::Shader::makeProgram(*_lightmapNormalMapProgram, slotBindings); + initProgram(_lightmapNormalMapProgram, _lightmapNormalMapLocations); _lightmapSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapVertex, modelLightmapSpecularMapPixel)); makeResult = gpu::Shader::makeProgram(*_lightmapSpecularMapProgram, slotBindings); - initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations); + initProgram(_lightmapSpecularMapProgram, _lightmapSpecularMapLocations); _lightmapNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel)); makeResult = gpu::Shader::makeProgram(*_lightmapNormalSpecularMapProgram, slotBindings); - initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations); + initProgram(_lightmapNormalSpecularMapProgram, _lightmapNormalSpecularMapLocations); _skinProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelPixel)); - makeResult = gpu::Shader::makeProgram(*_skinProgram, slotBindings); - initSkinProgram(_skinProgram, _skinLocations); + makeResult = gpu::Shader::makeProgram(*_skinProgram, slotBindings); + initSkinProgram(_skinProgram, _skinLocations); _skinNormalMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalMapPixel)); - makeResult = gpu::Shader::makeProgram(*_skinNormalMapProgram, slotBindings); - initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); + makeResult = gpu::Shader::makeProgram(*_skinNormalMapProgram, slotBindings); + initSkinProgram(_skinNormalMapProgram, _skinNormalMapLocations); _skinSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelSpecularMapPixel)); makeResult = gpu::Shader::makeProgram(*_skinSpecularMapProgram, slotBindings); - initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); + initSkinProgram(_skinSpecularMapProgram, _skinSpecularMapLocations); _skinNormalSpecularMapProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelNormalMapVertex, modelNormalSpecularMapPixel)); makeResult = gpu::Shader::makeProgram(*_skinNormalSpecularMapProgram, slotBindings); - initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations); + initSkinProgram(_skinNormalSpecularMapProgram, _skinNormalSpecularMapLocations); _skinShadowProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelShadowVertex, modelShadowPixel)); makeResult = gpu::Shader::makeProgram(*_skinShadowProgram, slotBindings); - initSkinProgram(_skinShadowProgram, _skinShadowLocations); + initSkinProgram(_skinShadowProgram, _skinShadowLocations); _skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel)); makeResult = gpu::Shader::makeProgram(*_skinTranslucentProgram, slotBindings); - initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); + initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); /* _POprogram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); _POprogram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); initProgram(_POprogram, _POlocations); - _POnormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); - _POnormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); - initProgram(_POnormalMapProgram, _POnormalMapLocations); - - _POspecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _POspecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); - initProgram(_POspecularMapProgram, _POspecularMapLocations); - - _POnormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); - _POnormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); - initProgram(_POnormalSpecularMapProgram, _POnormalSpecularMapLocations); - - _POtranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _POtranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); - initProgram(_POtranslucentProgram, _POtranslucentLocations); - - // Lightmap - _POlightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); - _POlightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag); - initProgram(_POlightmapProgram, _POlightmapLocations); - - _POlightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); - _POlightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag); - initProgram(_POlightmapNormalMapProgramddd, _POlightmapNormalMapLocations); - - _POlightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); - _POlightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag); - initProgram(_POlightmapSpecularMapProgram, _POlightmapSpecularMapLocations); - - _POlightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); - _POlightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag); - initProgram(_POlightmapNormalSpecularMapProgram, _POlightmapNormalSpecularMapLocations); - // end lightmap - - - _POshadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert); - _POshadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); - // Shadow program uses the same locations as standard rendering path but we still need to set the bindings - Model::Locations tempLoc; - initProgram(_POshadowProgram, tempLoc); - - _POskinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); - _POskinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); - initSkinProgram(_POskinProgram, _POskinLocations); - - _POskinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); - _POskinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); - initSkinProgram(_POskinNormalMapProgram, _PaOskinNormalMapLocations); - - _POskinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _POskinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); - initSkinProgram(_POskinSpecularMapProgram, _POskinSpecularMapLocations); - - _POskinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); - _POskinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); - initSkinProgram(_POskinNormalSpecularMapProgram, _POskinNormalSpecularMapLocations); - - _POskinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert); - _POskinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); - initSkinProgram(_POskinShadowProgram, _POskinShadowLocations); - - - _POskinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); + _POnormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); + _POnormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); + initProgram(_POnormalMapProgram, _POnormalMapLocations); + + _POspecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _POspecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); + initProgram(_POspecularMapProgram, _POspecularMapLocations); + + _POnormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); + _POnormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); + initProgram(_POnormalSpecularMapProgram, _POnormalSpecularMapLocations); + + _POtranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _POtranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); + initProgram(_POtranslucentProgram, _POtranslucentLocations); + + // Lightmap + _POlightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); + _POlightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag); + initProgram(_POlightmapProgram, _POlightmapLocations); + + _POlightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); + _POlightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag); + initProgram(_POlightmapNormalMapProgramddd, _POlightmapNormalMapLocations); + + _POlightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); + _POlightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag); + initProgram(_POlightmapSpecularMapProgram, _POlightmapSpecularMapLocations); + + _POlightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); + _POlightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag); + initProgram(_POlightmapNormalSpecularMapProgram, _POlightmapNormalSpecularMapLocations); + // end lightmap + + + _POshadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert); + _POshadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); + // Shadow program uses the same locations as standard rendering path but we still need to set the bindings + Model::Locations tempLoc; + initProgram(_POshadowProgram, tempLoc); + + _POskinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); + _POskinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); + initSkinProgram(_POskinProgram, _POskinLocations); + + _POskinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); + _POskinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); + initSkinProgram(_POskinNormalMapProgram, _PaOskinNormalMapLocations); + + _POskinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); + _POskinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); + initSkinProgram(_POskinSpecularMapProgram, _POskinSpecularMapLocations); + + _POskinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); + _POskinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); + initSkinProgram(_POskinNormalSpecularMapProgram, _POskinNormalSpecularMapLocations); + + _POskinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert); + _POskinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); + initSkinProgram(_POskinShadowProgram, _POskinShadowLocations); + + + _POskinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); _POskinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); initSkinProgram(_POskinTranslucentProgram, _POskinTranslucentLocations); */ From b33ba64e05018d27d9da45e8c4a21d44ab8f34b9 Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Wed, 18 Mar 2015 17:20:27 -0700 Subject: [PATCH 020/177] trying to tweek the transform equation to find the intel bug --- libraries/gpu/src/gpu/Transform.slh | 3 ++- libraries/render-utils/src/model.slv | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 93ea0ce9f6..072303a7f9 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -68,7 +68,8 @@ TransformCamera getTransformCamera() { } <@else@> -uniform vec4 transformObjectBuffer[7]; +uniform vec4 transformObjectBuffer[8]; + TransformObject getTransformObject() { TransformObject object; object._model[0] = transformObjectBuffer[0]; diff --git a/libraries/render-utils/src/model.slv b/libraries/render-utils/src/model.slv index 4f416e8f1f..679e826ef3 100755 --- a/libraries/render-utils/src/model.slv +++ b/libraries/render-utils/src/model.slv @@ -16,6 +16,7 @@ const int MAX_TEXCOORDS = 2; uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; + // the interpolated normal varying vec4 normal; @@ -30,7 +31,8 @@ void main(void) { // use standard pipeline transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - gl_Position = transformModelToClipPos(cam, obj, gl_Vertex); + + gl_Position = transformModelToClipPos(cam, obj, vec4(gl_Vertex.xyz, 1.0)); // transform and store the normal for interpolation normal = vec4(normalize(transformModelToEyeDir(cam, obj, gl_Normal)), 0.0); From cbef6e546f3d3d1adac1d560986b1ce1f1c9e03a Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Thu, 19 Mar 2015 17:25:53 +0100 Subject: [PATCH 021/177] Fix emun placement --- libraries/entities/src/EntityItemProperties.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 28c48c889b..40a9760e5c 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -93,8 +93,11 @@ enum EntityPropertyList { PROP_LOCAL_GRAVITY, PROP_PARTICLE_RADIUS, + // used by Model entities + PROP_ATTRIBUTION, + // NOTE: add new properties ABOVE this line and then modify PROP_LAST_ITEM below - PROP_LAST_ITEM = PROP_PARTICLE_RADIUS, + PROP_LAST_ITEM = PROP_ATTRIBUTION, // These properties of TextEntity piggy back off of properties of ModelEntities, the type doesn't matter // since the derived class knows how to interpret it's own properties and knows the types it expects @@ -103,9 +106,6 @@ enum EntityPropertyList { PROP_LINE_HEIGHT = PROP_ANIMATION_URL, PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS, PROP_COLLISION_MODEL_URL, - - // used by Model entities - PROP_ATTRIBUTION }; typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags; From 57011c2d4bd1fc0f423b5069460ac2e003653f42 Mon Sep 17 00:00:00 2001 From: Stojce Slavkovski <stojce@me.com> Date: Thu, 19 Mar 2015 20:55:18 +0100 Subject: [PATCH 022/177] get models from S3 --- examples/example/entities/makeHouses.js | 46 +++++++++++-------------- 1 file changed, 21 insertions(+), 25 deletions(-) diff --git a/examples/example/entities/makeHouses.js b/examples/example/entities/makeHouses.js index 12205db4ce..37bc1d5a8e 100644 --- a/examples/example/entities/makeHouses.js +++ b/examples/example/entities/makeHouses.js @@ -20,36 +20,32 @@ var sizeOfTheHouse = { x: 10, - y: 10, + y: 15, z: 10 }; - /**/ - - // - // var modelUrl = "http://localhost/~stojce/models/3-Buildings-2-SanFranciscoHouse-"; - // var modelurlExt = ".fbx"; - // var modelVariations = 100; - var houseModels = [ - "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseBlue.fbx", - "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseBlue3.fbx", - "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseGreen.fbx", - "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseGreen2.fbx", - "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseRed.fbx", - "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseRose.fbx", - "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseViolet.fbx", - "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseYellow.fbx", - "http://public.highfidelity.io/models/entities/3-Buildings-2-SanFranciscoHouseYellow2.fbx" - ]; - + var randomizeModels = false; + /**/ + + var modelUrlPrefix = "http://public.highfidelity.io/load_testing/3-Buildings-2-SanFranciscoHouse-"; + var modelurlExt = ".fbx"; + var modelVariations = 100; + var houses = []; function addHouseAt(position, rotation) { - // get random house model - //var modelNumber = 1 + Math.floor(Math.random() * (modelVariations - 1)); - //var modelUrl = modelUrl + modelNumber + modelurlExt; - //print("Model ID:" + modelNumber); - var modelUrl = houseModels[Math.floor(Math.random() * houseModels.length)]; + // get house model + var modelNumber = randomizeModels ? + 1 + Math.floor(Math.random() * (modelVariations - 1)) : + (houses.length + 1) % modelVariations; + + if (modelNumber == 0) { + modelNumber = modelVariations; + } + + var modelUrl = modelUrlPrefix + (modelNumber + "") + modelurlExt; + print("Model ID:" + modelNumber); + print("Model URL:" + modelUrl); var properties = { type: "Model", @@ -158,4 +154,4 @@ } Script.scriptEnding.connect(cleanup); -})(); \ No newline at end of file +})(); From 619a3231968ce5b930ecf7a32c3825d83d24761d Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Thu, 19 Mar 2015 14:46:50 -0700 Subject: [PATCH 023/177] Using Scribe preprocessor @func@ instead of regular glsl function to solve the intel bug with the transform stack --- libraries/gpu/src/gpu/Transform.slh | 70 ++++++++++--------- libraries/render-utils/src/model.slv | 13 ++-- libraries/render-utils/src/model_lightmap.slv | 12 ++-- .../src/model_lightmap_normal_map.slv | 15 ++-- .../render-utils/src/model_normal_map.slv | 15 ++-- libraries/render-utils/src/model_shadow.slv | 5 +- libraries/render-utils/src/skin_model.slv | 11 +-- .../src/skin_model_normal_map.slv | 19 +++-- .../render-utils/src/skin_model_shadow.slv | 5 +- 9 files changed, 90 insertions(+), 75 deletions(-) diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 072303a7f9..4988b230cc 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -10,6 +10,7 @@ <@if not GPU_TRANSFORM_STATE_SLH@> <@def GPU_TRANSFORM_STATE_SLH@> +<@func declareStandardTransform()@> struct TransformObject { mat4 _model; mat4 _modelInverse; @@ -23,48 +24,19 @@ struct TransformCamera { vec4 _viewport; }; -vec4 transformModelToClipPos(TransformCamera camera, TransformObject object, vec4 pos) { -<@if GPU_TRANSFORM_PROFILE == GPU_CORE@> - vec4 epos = (object._model * pos) + vec4(-pos.w * camera._viewInverse[3].xyz, 0.0); - return camera._projectionViewUntranslated * epos; - // Equivalent to the following but hoppefully a bit more accurate - //return camera._projection * camera._view * object._model * pos; -<@else@> - return gl_ModelViewProjectionMatrix * pos; -<@endif@> -} - -vec3 transformModelToEyeDir(TransformCamera camera, TransformObject object, vec3 dir) { -<@if GPU_TRANSFORM_PROFILE == GPU_CORE@> - vec3 mr0 = vec3(object._modelInverse[0].x, object._modelInverse[1].x, object._modelInverse[2].x); - vec3 mr1 = vec3(object._modelInverse[0].y, object._modelInverse[1].y, object._modelInverse[2].y); - vec3 mr2 = vec3(object._modelInverse[0].z, object._modelInverse[1].z, object._modelInverse[2].z); - - vec3 mvc0 = vec3(dot(camera._viewInverse[0].xyz, mr0), dot(camera._viewInverse[0].xyz, mr1), dot(camera._viewInverse[0].xyz, mr2)); - vec3 mvc1 = vec3(dot(camera._viewInverse[1].xyz, mr0), dot(camera._viewInverse[1].xyz, mr1), dot(camera._viewInverse[1].xyz, mr2)); - vec3 mvc2 = vec3(dot(camera._viewInverse[2].xyz, mr0), dot(camera._viewInverse[2].xyz, mr1), dot(camera._viewInverse[2].xyz, mr2)); - - vec3 result = vec3(dot(mvc0, dir), dot(mvc1, dir), dot(mvc2, dir)); - - return result; -<@else@> - return gl_NormalMatrix * dir; -<@endif@> -} - <@if GPU_TRANSFORM_PROFILE == GPU_CORE@> uniform transformObjectBuffer { - TransformObject object; + TransformObject _object; }; TransformObject getTransformObject() { - return object; + return _object; } uniform transformCameraBuffer { - TransformCamera camera; + TransformCamera _camera; }; TransformCamera getTransformCamera() { - return camera; + return _camera; } <@else@> @@ -114,6 +86,38 @@ TransformCamera getTransformCamera() { } <@endif@> +<@endfunc@> + +<@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@> +<@if GPU_TRANSFORM_PROFILE == GPU_CORE@> + <!// Equivalent to the following but hoppefully a tad more accurate + //return camera._projection * camera._view * object._model * pos; !> + { // transformModelToClipPos + vec4 _eyepos = (<$objectTransform$>._model * <$modelPos$>) + vec4(-<$modelPos$>.w * <$cameraTransform$>._viewInverse[3].xyz, 0.0); + <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos; + } +<@else@> + <$clippos$> = gl_ModelViewProjectionMatrix * <$modelPos$>; +<@endif@> +<@endfunc@> + +<@func transformModelToEyeDir(cameraTransform, objectTransform, modelDir, eyeDir)@> +<@if GPU_TRANSFORM_PROFILE == GPU_CORE@> + { // transformModelToEyeDir + vec3 mr0 = vec3(<$objectTransform$>._modelInverse[0].x, <$objectTransform$>._modelInverse[1].x, <$objectTransform$>._modelInverse[2].x); + vec3 mr1 = vec3(<$objectTransform$>._modelInverse[0].y, <$objectTransform$>._modelInverse[1].y, <$objectTransform$>._modelInverse[2].y); + vec3 mr2 = vec3(<$objectTransform$>._modelInverse[0].z, <$objectTransform$>._modelInverse[1].z, <$objectTransform$>._modelInverse[2].z); + + vec3 mvc0 = vec3(dot(<$cameraTransform$>._viewInverse[0].xyz, mr0), dot(<$cameraTransform$>._viewInverse[0].xyz, mr1), dot(<$cameraTransform$>._viewInverse[0].xyz, mr2)); + vec3 mvc1 = vec3(dot(<$cameraTransform$>._viewInverse[1].xyz, mr0), dot(<$cameraTransform$>._viewInverse[1].xyz, mr1), dot(<$cameraTransform$>._viewInverse[1].xyz, mr2)); + vec3 mvc2 = vec3(dot(<$cameraTransform$>._viewInverse[2].xyz, mr0), dot(<$cameraTransform$>._viewInverse[2].xyz, mr1), dot(<$cameraTransform$>._viewInverse[2].xyz, mr2)); + + <$eyeDir$> = vec3(dot(mvc0, <$modelDir$>), dot(mvc1, <$modelDir$>), dot(mvc2, <$modelDir$>)); + } +<@else@> + <$eyeDir$> = gl_NormalMatrix * <$modelDir$>; +<@endif@> +<@endfunc@> <@endif@> diff --git a/libraries/render-utils/src/model.slv b/libraries/render-utils/src/model.slv index 679e826ef3..21c9238273 100755 --- a/libraries/render-utils/src/model.slv +++ b/libraries/render-utils/src/model.slv @@ -12,6 +12,9 @@ // <@include gpu/Transform.slh@> + +<$declareStandardTransform()$> + const int MAX_TEXCOORDS = 2; uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; @@ -28,13 +31,11 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0); - // use standard pipeline transform + // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); + <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> + <$transformModelToEyeDir(cam, obj, gl_Normal, normal.xyz)$> - gl_Position = transformModelToClipPos(cam, obj, vec4(gl_Vertex.xyz, 1.0)); - - // transform and store the normal for interpolation - normal = vec4(normalize(transformModelToEyeDir(cam, obj, gl_Normal)), 0.0); - + normal = vec4(normalize(normal.xyz), 0.0); } diff --git a/libraries/render-utils/src/model_lightmap.slv b/libraries/render-utils/src/model_lightmap.slv index afe3c73549..f24ba4e53d 100755 --- a/libraries/render-utils/src/model_lightmap.slv +++ b/libraries/render-utils/src/model_lightmap.slv @@ -14,6 +14,8 @@ <@include gpu/Transform.slh@> +<$declareStandardTransform()$> + const int MAX_TEXCOORDS = 2; uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; @@ -35,12 +37,12 @@ void main(void) { // interpolatedTexcoord1 = vec2(texcoordMatrices[1] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0)).xy; interpolatedTexcoord1 = vec2(texcoordMatrices[1] * vec4(texcoord1.xy, 0.0, 1.0)).xy; - // use standard pipeline transform + // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - gl_Position = transformModelToClipPos(cam, obj, gl_Vertex); - - // transform and store the normal for interpolation - normal = vec4(normalize(transformModelToEyeDir(cam, obj, gl_Normal)), 0.0); + <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> + <$transformModelToEyeDir(cam, obj, gl_Normal, normal.xyz)$> + + normal = vec4(normalize(normal.xyz), 0.0); } diff --git a/libraries/render-utils/src/model_lightmap_normal_map.slv b/libraries/render-utils/src/model_lightmap_normal_map.slv index 6e66b28e63..a1413b1530 100755 --- a/libraries/render-utils/src/model_lightmap_normal_map.slv +++ b/libraries/render-utils/src/model_lightmap_normal_map.slv @@ -14,6 +14,8 @@ <@include gpu/Transform.slh@> +<$declareStandardTransform()$> + const int MAX_TEXCOORDS = 2; uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; @@ -44,12 +46,13 @@ void main(void) { gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0); interpolatedTexcoord1 = vec2(texcoordMatrices[1] * vec4(texcoord1.xy, 0.0, 1.0)).xy; - // use standard pipeline transform + // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - gl_Position = transformModelToClipPos(cam, obj, gl_Vertex); - - // transform and store the normal for interpolation - interpolatedNormal = vec4(normalize(transformModelToEyeDir(cam, obj, gl_Normal)), 0.0); - interpolatedTangent = vec4(normalize(transformModelToEyeDir(cam, obj, tangent)), 0.0); + <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> + <$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$> + <$transformModelToEyeDir(cam, obj, tangent, interpolatedTangent.xyz)$> + + interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); + interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0); } diff --git a/libraries/render-utils/src/model_normal_map.slv b/libraries/render-utils/src/model_normal_map.slv index 4111458464..9983310b52 100755 --- a/libraries/render-utils/src/model_normal_map.slv +++ b/libraries/render-utils/src/model_normal_map.slv @@ -13,6 +13,8 @@ // <@include gpu/Transform.slh@> + +<$declareStandardTransform()$> const int MAX_TEXCOORDS = 2; @@ -38,12 +40,13 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0); - // use standard pipeline transform + // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - gl_Position = transformModelToClipPos(cam, obj, gl_Vertex); - - // transform and store the normal for interpolation - interpolatedNormal = vec4(normalize(transformModelToEyeDir(cam, obj, gl_Normal)), 0.0); - interpolatedTangent = vec4(normalize(transformModelToEyeDir(cam, obj, tangent)), 0.0); + <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> + <$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$> + <$transformModelToEyeDir(cam, obj, tangent, interpolatedTangent.xyz)$> + + interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); + interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0); } diff --git a/libraries/render-utils/src/model_shadow.slv b/libraries/render-utils/src/model_shadow.slv index 98f6bf5104..88e597557e 100755 --- a/libraries/render-utils/src/model_shadow.slv +++ b/libraries/render-utils/src/model_shadow.slv @@ -12,10 +12,11 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // <@include gpu/Transform.slh@> +<$declareStandardTransform()$> void main(void) { - // use standard pipeline transform + // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - gl_Position = transformModelToClipPos(cam, obj, gl_Vertex); + <$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$> } diff --git a/libraries/render-utils/src/skin_model.slv b/libraries/render-utils/src/skin_model.slv index 780b72323c..f65d5a8bdc 100755 --- a/libraries/render-utils/src/skin_model.slv +++ b/libraries/render-utils/src/skin_model.slv @@ -13,6 +13,7 @@ // <@include gpu/Transform.slh@> +<$declareStandardTransform()$> const int MAX_TEXCOORDS = 2; const int MAX_CLUSTERS = 128; @@ -43,11 +44,11 @@ void main(void) { // and the texture coordinates gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0); - // use standard pipeline transform + // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - gl_Position = transformModelToClipPos(cam, obj, position); - - // transform and store the normal for interpolation - normal = vec4(normalize(transformModelToEyeDir(cam, obj, normal.xyz)), 0.0); + <$transformModelToClipPos(cam, obj, position, gl_Position)$> + <$transformModelToEyeDir(cam, obj, normal.xyz, normal.xyz)$> + + normal = vec4(normalize(normal.xyz), 0.0); } diff --git a/libraries/render-utils/src/skin_model_normal_map.slv b/libraries/render-utils/src/skin_model_normal_map.slv index 43ec9c6a9d..6a4170152d 100755 --- a/libraries/render-utils/src/skin_model_normal_map.slv +++ b/libraries/render-utils/src/skin_model_normal_map.slv @@ -13,6 +13,7 @@ // <@include gpu/Transform.slh@> +<$declareStandardTransform()$> const int MAX_TEXCOORDS = 2; const int MAX_CLUSTERS = 128; @@ -44,22 +45,20 @@ void main(void) { interpolatedNormal += clusterMatrix * vec4(gl_Normal, 0.0) * clusterWeight; interpolatedTangent += clusterMatrix * vec4(tangent, 0.0) * clusterWeight; } - // interpolatedNormal = gl_ModelViewMatrix * interpolatedNormal; - // interpolatedTangent = gl_ModelViewMatrix * interpolatedTangent; - + // pass along the diffuse color gl_FrontColor = gl_Color; // and the texture coordinates gl_TexCoord[0] = texcoordMatrices[0] * vec4(gl_MultiTexCoord0.xy, 0.0, 1.0); - gl_Position = gl_ModelViewProjectionMatrix * interpolatedPosition; - - // use standard pipeline transform + // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - gl_Position = transformModelToClipPos(cam, obj, interpolatedPosition); - - interpolatedNormal = vec4(normalize(transformModelToEyeDir(cam, obj, interpolatedNormal.xyz)), 0.0); - interpolatedTangent = vec4(normalize(transformModelToEyeDir(cam, obj, interpolatedTangent.xyz)), 0.0); + <$transformModelToClipPos(cam, obj, interpolatedPosition, gl_Position)$> + <$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$> + <$transformModelToEyeDir(cam, obj, tangent, interpolatedTangent.xyz)$> + + interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); + interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0); } diff --git a/libraries/render-utils/src/skin_model_shadow.slv b/libraries/render-utils/src/skin_model_shadow.slv index de7f8f4e9f..03b912a981 100755 --- a/libraries/render-utils/src/skin_model_shadow.slv +++ b/libraries/render-utils/src/skin_model_shadow.slv @@ -13,6 +13,7 @@ // <@include gpu/Transform.slh@> +<$declareStandardTransform()$> const int MAX_CLUSTERS = 128; const int INDICES_PER_VERTEX = 4; @@ -30,8 +31,8 @@ void main(void) { position += clusterMatrix * gl_Vertex * clusterWeight; } - // use standard pipeline transform + // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - gl_Position = transformModelToClipPos(cam, obj, position); + <$transformModelToClipPos(cam, obj, position, gl_Position)$> } From 65727dd613c9b60d9fcd2f8c5e32ddb92af673f2 Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Thu, 19 Mar 2015 15:23:50 -0700 Subject: [PATCH 024/177] clean up code --- libraries/render-utils/src/Model.cpp | 412 ++++----------------------- libraries/render-utils/src/Model.h | 42 +-- 2 files changed, 61 insertions(+), 393 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 47cb2d56f8..9fd15e6f27 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -93,46 +93,7 @@ Model::Model(QObject* parent) : Model::~Model() { deleteGeometry(); } -/* -ProgramObject Model::_POprogram; -ProgramObject Model::_POnormalMapProgram; -ProgramObject Model::_POspecularMapProgram; -ProgramObject Model::_POnormalSpecularMapProgram; -ProgramObject Model::_POtranslucentProgram; -ProgramObject Model::_POlightmapProgram; -ProgramObject Model::_POlightmapNormalMapProgram; -ProgramObject Model::_POlightmapSpecularMapProgram; -ProgramObject Model::_POlightmapNormalSpecularMapProgram; - -ProgramObject Model::_POshadowProgram; - -ProgramObject Model::_POskinProgram; -ProgramObject Model::_POskinNormalMapProgram; -ProgramObject Model::_POskinSpecularMapProgram; -ProgramObject Model::_POskinNormalSpecularMapProgram; -ProgramObject Model::_POskinTranslucentProgram; - -ProgramObject Model::_POskinShadowProgram; - -Model::Locations Model::_POlocations; -Model::Locations Model::_POnormalMapLocations; -Model::Locations Model::_POspecularMapLocations; -Model::Locations Model::_POnormalSpecularMapLocations; -Model::Locations Model::_POtranslucentLocations; - -Model::Locations Model::_POlightmapLocations; -Model::Locations Model::_POlightmapNormalMapLocations; -Model::Locations Model::_POlightmapSpecularMapLocations; -Model::Locations Model::_POlightmapNormalSpecularMapLocations; - -Model::SkinLocations Model::_POskinLocations; -Model::SkinLocations Model::_POskinNormalMapLocations; -Model::SkinLocations Model::_POskinSpecularMapLocations; -Model::SkinLocations Model::_POskinNormalSpecularMapLocations; -Model::SkinLocations Model::_POskinShadowLocations; -Model::SkinLocations Model::_POskinTranslucentLocations; -*/ gpu::ShaderPointer Model::_program; gpu::ShaderPointer Model::_normalMapProgram; gpu::ShaderPointer Model::_specularMapProgram; @@ -232,100 +193,6 @@ void Model::initSkinProgram(gpu::ShaderPointer& program, Model::SkinLocations& l locations.clusterIndices = program->getInputs().findLocation("clusterIndices");; locations.clusterWeights = program->getInputs().findLocation("clusterWeights");; } -/* -void Model::initProgram(ProgramObject& program, Model::Locations& locations, bool link) { - if (link) { - program.bindAttributeLocation("tangent", gpu::Stream::TANGENT); - program.bindAttributeLocation("texcoord1", gpu::Stream::TEXCOORD1); - program.link(); - } - program.bind(); - - locations.tangent = program.attributeLocation("tangent"); - - locations.alphaThreshold = program.uniformLocation("alphaThreshold"); - locations.texcoordMatrices = program.uniformLocation("texcoordMatrices"); - locations.emissiveParams = program.uniformLocation("emissiveParams"); - locations.glowIntensity = program.uniformLocation("glowIntensity"); - program.setUniformValue("diffuseMap", 0); - program.setUniformValue("normalMap", 1); - - int loc = program.uniformLocation("specularMap"); - if (loc >= 0) { - program.setUniformValue("specularMap", 2); - locations.specularTextureUnit = 2; - } else { - locations.specularTextureUnit = -1; - } - - loc = program.uniformLocation("emissiveMap"); - if (loc >= 0) { - program.setUniformValue("emissiveMap", 3); - locations.emissiveTextureUnit = 3; - } else { - locations.emissiveTextureUnit = -1; - } - - // bindable uniform version - -#if (GPU_FEATURE_PROFILE == GPU_CORE) - loc = glGetUniformBlockIndex(program.programId(), "materialBuffer"); - if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, MATERIAL_GPU_SLOT); - locations.materialBufferUnit = MATERIAL_GPU_SLOT; - } else { - locations.materialBufferUnit = -1; - } -#else - loc = program.uniformLocation("materialBuffer"); - if (loc >= 0) { - locations.materialBufferUnit = loc; - } else { - locations.materialBufferUnit = -1; - } -#endif - -#if (GPU_FEATURE_PROFILE == GPU_CORE) - loc = glGetUniformBlockIndex(program.programId(), "transformObjectBuffer"); - if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_OBJECT_SLOT); - // locations.materialBufferUnit = 1; - } -#endif - -#if (GPU_FEATURE_PROFILE == GPU_CORE) - loc = glGetUniformBlockIndex(program.programId(), "transformCameraBuffer"); - if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, gpu::TRANSFORM_CAMERA_SLOT); - // locations.materialBufferUnit = 1; - } -#endif - - //program.link(); - if (!program.isLinked()) { - program.release(); - } - - program.release(); -}*/ -/* -void Model::initSkinProgram(ProgramObject& program, Model::SkinLocations& locations) { - program.bindAttributeLocation("tangent", gpu::Stream::TANGENT); - program.bindAttributeLocation("texcoord1", gpu::Stream::TEXCOORD1); - program.bindAttributeLocation("clusterIndices", gpu::Stream::SKIN_CLUSTER_INDEX); - program.bindAttributeLocation("clusterWeights", gpu::Stream::SKIN_CLUSTER_WEIGHT); - program.link(); - - initProgram(program, locations, false); - - program.bind(); - - locations.clusterMatrices = program.uniformLocation("clusterMatrices"); - locations.clusterIndices = program.attributeLocation("clusterIndices"); - locations.clusterWeights = program.attributeLocation("clusterWeights"); - - program.release(); -}*/ QVector<JointState> Model::createJointStates(const FBXGeometry& geometry) { QVector<JointState> jointStates; @@ -361,8 +228,6 @@ void Model::initJointTransforms() { void Model::init() { if (_program.isNull()) { - // if (!_program.isLinked()) { - //Work in progress not used yet gpu::Shader::BindingSet slotBindings; slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT)); slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), 0)); @@ -460,78 +325,6 @@ void Model::init() { _skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel)); makeResult = gpu::Shader::makeProgram(*_skinTranslucentProgram, slotBindings); initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); - - /* - _POprogram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _POprogram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); - initProgram(_POprogram, _POlocations); - - _POnormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); - _POnormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); - initProgram(_POnormalMapProgram, _POnormalMapLocations); - - _POspecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _POspecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); - initProgram(_POspecularMapProgram, _POspecularMapLocations); - - _POnormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_normal_map_vert); - _POnormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); - initProgram(_POnormalSpecularMapProgram, _POnormalSpecularMapLocations); - - _POtranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _POtranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); - initProgram(_POtranslucentProgram, _POtranslucentLocations); - - // Lightmap - _POlightmapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); - _POlightmapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_frag); - initProgram(_POlightmapProgram, _POlightmapLocations); - - _POlightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); - _POlightmapNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_map_frag); - initProgram(_POlightmapNormalMapProgramddd, _POlightmapNormalMapLocations); - - _POlightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_vert); - _POlightmapSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_specular_map_frag); - initProgram(_POlightmapSpecularMapProgram, _POlightmapSpecularMapLocations); - - _POlightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_lightmap_normal_map_vert); - _POlightmapNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_lightmap_normal_specular_map_frag); - initProgram(_POlightmapNormalSpecularMapProgram, _POlightmapNormalSpecularMapLocations); - // end lightmap - - - _POshadowProgram.addShaderFromSourceCode(QGLShader::Vertex, model_shadow_vert); - _POshadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); - // Shadow program uses the same locations as standard rendering path but we still need to set the bindings - Model::Locations tempLoc; - initProgram(_POshadowProgram, tempLoc); - - _POskinProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); - _POskinProgram.addShaderFromSourceCode(QGLShader::Fragment, model_frag); - initSkinProgram(_POskinProgram, _POskinLocations); - - _POskinNormalMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); - _POskinNormalMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_map_frag); - initSkinProgram(_POskinNormalMapProgram, _PaOskinNormalMapLocations); - - _POskinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, model_vert); - _POskinSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_specular_map_frag); - initSkinProgram(_POskinSpecularMapProgram, _POskinSpecularMapLocations); - - _POskinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_normal_map_vert); - _POskinNormalSpecularMapProgram.addShaderFromSourceCode(QGLShader::Fragment, model_normal_specular_map_frag); - initSkinProgram(_POskinNormalSpecularMapProgram, _POskinNormalSpecularMapLocations); - - _POskinShadowProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_shadow_vert); - _POskinShadowProgram.addShaderFromSourceCode(QGLShader::Fragment, model_shadow_frag); - initSkinProgram(_POskinShadowProgram, _POskinShadowLocations); - - - _POskinTranslucentProgram.addShaderFromSourceCode(QGLShader::Vertex, skin_model_vert); - _POskinTranslucentProgram.addShaderFromSourceCode(QGLShader::Fragment, model_translucent_frag); - initSkinProgram(_POskinTranslucentProgram, _POskinTranslucentLocations); - */ } } @@ -2397,165 +2190,80 @@ QVector<int>* Model::pickMeshList(bool translucent, float alphaThreshold, bool h void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, Locations*& locations, SkinLocations*& skinLocations) { -/* if (false) - { - ProgramObject* program = &_POprogram; - locations = &_POlocations; - ProgramObject* skinProgram = &_POskinProgram; - skinLocations = &_POskinLocations; - if (mode == SHADOW_RENDER_MODE) { - program = &_POshadowProgram; - skinProgram = &_POskinShadowProgram; - skinLocations = &_POskinShadowLocations; - } else if (translucent && alphaThreshold == 0.0f) { - program = &_POtranslucentProgram; - locations = &_POtranslucentLocations; - skinProgram = &_POskinTranslucentProgram; - skinLocations = &_POskinTranslucentLocations; + gpu::ShaderPointer program = _program; + locations = &_locations; + gpu::ShaderPointer skinProgram = _skinProgram; + skinLocations = &_skinLocations; + if (mode == SHADOW_RENDER_MODE) { + program = _shadowProgram; + skinProgram = _skinShadowProgram; + skinLocations = &_skinShadowLocations; + } else if (translucent && alphaThreshold == 0.0f) { + program = _translucentProgram; + locations = &_translucentLocations; + skinProgram = _skinTranslucentProgram; + skinLocations = &_skinTranslucentLocations; - } else if (hasLightmap) { - if (hasTangents) { - if (hasSpecular) { - program = &_POlightmapNormalSpecularMapProgram; - locations = &_POlightmapNormalSpecularMapLocations; - skinProgram = NULL; - skinLocations = NULL; - } else { - program = &_POlightmapNormalMapProgram; - locations = &_POlightmapNormalMapLocations; - skinProgram = NULL; - skinLocations = NULL; - } - } else if (hasSpecular) { - program = &_POlightmapSpecularMapProgram; - locations = &_POlightmapSpecularMapLocations; - skinProgram = NULL; + } else if (hasLightmap) { + if (hasTangents) { + if (hasSpecular) { + program = _lightmapNormalSpecularMapProgram; + locations = &_lightmapNormalSpecularMapLocations; + skinProgram.reset(nullptr); skinLocations = NULL; } else { - program = &_POlightmapProgram; - locations = &_POlightmapLocations; - skinProgram = NULL; + program = _lightmapNormalMapProgram; + locations = &_lightmapNormalMapLocations; + skinProgram.reset(nullptr); skinLocations = NULL; } + } else if (hasSpecular) { + program = _lightmapSpecularMapProgram; + locations = &_lightmapSpecularMapLocations; + skinProgram.reset(nullptr); + skinLocations = NULL; } else { - if (hasTangents) { - if (hasSpecular) { - program = &_POnormalSpecularMapProgram; - locations = &_POnormalSpecularMapLocations; - skinProgram = &_POskinNormalSpecularMapProgram; - skinLocations = &_POskinNormalSpecularMapLocations; - } else { - program = &_POnormalMapProgram; - locations = &_POnormalMapLocations; - skinProgram = &_POskinNormalMapProgram; - skinLocations = &_POskinNormalMapLocations; - } - } else if (hasSpecular) { - program = &_POspecularMapProgram; - locations = &_POspecularMapLocations; - skinProgram = &_POskinSpecularMapProgram; - skinLocations = &_POskinSpecularMapLocations; + program = _lightmapProgram; + locations = &_lightmapLocations; + skinProgram.reset(nullptr); + skinLocations = NULL; + } + } else { + if (hasTangents) { + if (hasSpecular) { + program = _normalSpecularMapProgram; + locations = &_normalSpecularMapLocations; + skinProgram = _skinNormalSpecularMapProgram; + skinLocations = &_skinNormalSpecularMapLocations; + } else { + program = _normalMapProgram; + locations = &_normalMapLocations; + skinProgram = _skinNormalMapProgram; + skinLocations = &_skinNormalMapLocations; } - } - - ProgramObject* activeProgram = program; - Locations* activeLocations = locations; - - if (isSkinned) { - activeProgram = skinProgram; - activeLocations = skinLocations; - locations = skinLocations; - } - // This code replace the "bind()" on the QGLProgram - if (!activeProgram->isLinked()) { - activeProgram->link(); + } else if (hasSpecular) { + program = _specularMapProgram; + locations = &_specularMapLocations; + skinProgram = _skinSpecularMapProgram; + skinLocations = &_skinSpecularMapLocations; } + } - GLBATCH(glUseProgram)(activeProgram->programId()); - - - if ((activeLocations->alphaThreshold > -1) && (mode != SHADOW_RENDER_MODE)) { - GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold); - } + gpu::ShaderPointer activeProgram = program; + Locations* activeLocations = locations; + if (isSkinned) { + activeProgram = skinProgram; + activeLocations = skinLocations; + locations = skinLocations; } - else */ - { - gpu::ShaderPointer program = _program; - locations = &_locations; - gpu::ShaderPointer skinProgram = _skinProgram; - skinLocations = &_skinLocations; - if (mode == SHADOW_RENDER_MODE) { - program = _shadowProgram; - skinProgram = _skinShadowProgram; - skinLocations = &_skinShadowLocations; - } else if (translucent && alphaThreshold == 0.0f) { - program = _translucentProgram; - locations = &_translucentLocations; - skinProgram = _skinTranslucentProgram; - skinLocations = &_skinTranslucentLocations; - - } else if (hasLightmap) { - if (hasTangents) { - if (hasSpecular) { - program = _lightmapNormalSpecularMapProgram; - locations = &_lightmapNormalSpecularMapLocations; - skinProgram.reset(nullptr); - skinLocations = NULL; - } else { - program = _lightmapNormalMapProgram; - locations = &_lightmapNormalMapLocations; - skinProgram.reset(nullptr); - skinLocations = NULL; - } - } else if (hasSpecular) { - program = _lightmapSpecularMapProgram; - locations = &_lightmapSpecularMapLocations; - skinProgram.reset(nullptr); - skinLocations = NULL; - } else { - program = _lightmapProgram; - locations = &_lightmapLocations; - skinProgram.reset(nullptr); - skinLocations = NULL; - } - } else { - if (hasTangents) { - if (hasSpecular) { - program = _normalSpecularMapProgram; - locations = &_normalSpecularMapLocations; - skinProgram = _skinNormalSpecularMapProgram; - skinLocations = &_skinNormalSpecularMapLocations; - } else { - program = _normalMapProgram; - locations = &_normalMapLocations; - skinProgram = _skinNormalMapProgram; - skinLocations = &_skinNormalMapLocations; - } - } else if (hasSpecular) { - program = _specularMapProgram; - locations = &_specularMapLocations; - skinProgram = _skinSpecularMapProgram; - skinLocations = &_skinSpecularMapLocations; - } - } - gpu::ShaderPointer activeProgram = program; - Locations* activeLocations = locations; - - if (isSkinned) { - activeProgram = skinProgram; - activeLocations = skinLocations; - locations = skinLocations; - } - - GLuint glprogram = gpu::GLBackend::getShaderID(activeProgram); - GLBATCH(glUseProgram)(glprogram); + GLuint glprogram = gpu::GLBackend::getShaderID(activeProgram); + GLBATCH(glUseProgram)(glprogram); - if ((activeLocations->alphaThreshold > -1) && (mode != SHADOW_RENDER_MODE)) { - GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold); - } + if ((activeLocations->alphaThreshold > -1) && (mode != SHADOW_RENDER_MODE)) { + GLBATCH(glUniform1f)(activeLocations->alphaThreshold, alphaThreshold); } } diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 4004b4dad7..b7861889fb 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -315,28 +315,6 @@ private: int _blendNumber; int _appliedBlendNumber; - /* - static ProgramObject _POprogram; - static ProgramObject _POnormalMapProgram; - static ProgramObject _POspecularMapProgram; - static ProgramObject _POnormalSpecularMapProgram; - static ProgramObject _POtranslucentProgram; - - static ProgramObject _POlightmapProgram; - static ProgramObject _POlightmapNormalMapProgram; - static ProgramObject _POlightmapSpecularMapProgram; - static ProgramObject _POlightmapNormalSpecularMapProgram; - - static ProgramObject _POshadowProgram; - - static ProgramObject _POskinProgram; - static ProgramObject _POskinNormalMapProgram; - static ProgramObject _POskinSpecularMapProgram; - static ProgramObject _POskinNormalSpecularMapProgram; - static ProgramObject _POskinTranslucentProgram; - - static ProgramObject _POskinShadowProgram; - */ static gpu::ShaderPointer _program; static gpu::ShaderPointer _normalMapProgram; static gpu::ShaderPointer _specularMapProgram; @@ -380,18 +358,7 @@ private: static Locations _lightmapNormalMapLocations; static Locations _lightmapSpecularMapLocations; static Locations _lightmapNormalSpecularMapLocations; -/* - static Locations _POlocations; - static Locations _POnormalMapLocations; - static Locations _POspecularMapLocations; - static Locations _POnormalSpecularMapLocations; - static Locations _POtranslucentLocations; - static Locations _POlightmapLocations; - static Locations _POlightmapNormalMapLocations; - static Locations _POlightmapSpecularMapLocations; - static Locations _POlightmapNormalSpecularMapLocations; -*/ static void initProgram(ProgramObject& program, Locations& locations, bool link = true); static void initProgram(gpu::ShaderPointer& program, Locations& locations); @@ -408,14 +375,7 @@ private: static SkinLocations _skinNormalSpecularMapLocations; static SkinLocations _skinShadowLocations; static SkinLocations _skinTranslucentLocations; -/* - static SkinLocations _POskinLocations; - static SkinLocations _POskinNormalMapLocations; - static SkinLocations _POskinSpecularMapLocations; - static SkinLocations _POskinNormalSpecularMapLocations; - static SkinLocations _POskinShadowLocations; - static SkinLocations _POskinTranslucentLocations; -*/ + static void initSkinProgram(ProgramObject& program, SkinLocations& locations); static void initSkinProgram(gpu::ShaderPointer& program, SkinLocations& locations); From 3cd2ce82d4238e39b88f132cda19738e31028a93 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Thu, 19 Mar 2015 15:31:34 -0700 Subject: [PATCH 025/177] tuning character so it can walk up ledges --- libraries/physics/src/CharacterController.cpp | 424 ++++++++++-------- libraries/physics/src/CharacterController.h | 14 +- 2 files changed, 241 insertions(+), 197 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 6fdf55abed..2c01e2ae32 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -107,6 +107,91 @@ protected: btScalar m_minSlopeDot; }; +class StepDownConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { + // special convex sweep callback for character during the stepDown() phase + public: + StepDownConvexResultCallback(btCollisionObject* me, + const btVector3& up, + btScalar minSlopeDot, + const btVector3& start, + const btVector3& step, + btScalar radius, + btScalar halfHeight, + btVector3 pushDirection) + : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) + , m_me(me) + , m_up(up) + , m_minSlopeDot(minSlopeDot) + , m_start(start) + , m_step(step) + , m_radius(radius) + , m_halfHeight(halfHeight) + , m_pushDirection(pushDirection) + { + } + + virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace) { + if (convexResult.m_hitCollisionObject == m_me) { + return btScalar(1.0); + } + + if (!convexResult.m_hitCollisionObject->hasContactResponse()) { + return btScalar(1.0); + } + + btVector3 hitNormalWorld; + if (normalInWorldSpace) { + hitNormalWorld = convexResult.m_hitNormalLocal; + } else { + ///need to transform normal into worldspace + hitNormalWorld = convexResult.m_hitCollisionObject->getWorldTransform().getBasis() * convexResult.m_hitNormalLocal; + } + + // Note: hitNormalWorld points into character, away from object + // and m_up points opposite to movement + + btScalar dotUp = m_up.dot(hitNormalWorld); + if (dotUp < m_minSlopeDot) { + if (hitNormalWorld.dot(m_pushDirection) > 0.0f) { + // ignore hits that push in same direction as character is moving + // which helps character NOT snag when stepping off ledges + return btScalar(1.0f); + } + + // compute the angle between "down" and the line from character center to "hit" point + btVector3 fractionalStep = convexResult.m_hitFraction * m_step; + btVector3 localHit = convexResult.m_hitPointLocal - m_start + fractionalStep; + btScalar angle = localHit.angle(-m_up); + + // compute a maxAngle based on size of m_step + btVector3 side(m_radius, - (m_halfHeight - m_step.length() + fractionalStep.dot(m_up)), 0.0f); + btScalar maxAngle = side.angle(-m_up); + + // Ignore hits that are larger than maxAngle. Effectively what is happening here is: + // we're ignoring hits at contacts that have non-vertical normals... if they hit higher + // than the character's "feet". Ignoring the contact allows the character to slide down + // for these hits. In other words, vertical walls against the character's torso will + // not prevent them from "stepping down" to find the floor. + if (angle > maxAngle) { + return btScalar(1.0f); + } + } + + btScalar fraction = ClosestConvexResultCallback::addSingleResult(convexResult, normalInWorldSpace); + return fraction; + } + +protected: + btCollisionObject* m_me; + const btVector3 m_up; + btScalar m_minSlopeDot; + btVector3 m_start; + btVector3 m_step; + btScalar m_radius; + btScalar m_halfHeight; + btVector3 m_pushDirection; +}; + /* * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal' * @@ -146,7 +231,6 @@ CharacterController::CharacterController(AvatarData* avatarData) { m_addedMargin = 0.02f; m_walkDirection.setValue(0.0f,0.0f,0.0f); - m_useGhostObjectSweepTest = true; m_turnAngle = btScalar(0.0f); m_useWalkDirection = true; // use walk direction by default, legacy behavior m_velocityTimeInterval = 0.0f; @@ -159,7 +243,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { m_wasJumping = false; m_interpolateUp = true; setMaxSlope(btRadians(45.0f)); - m_currentStepOffset = 0.0f; + m_lastStepUp = 0.0f; // internal state data members full_drop = false; @@ -194,6 +278,9 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher()); m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); + btVector3 up = getUpAxisDirections()[m_upAxis]; + + btVector3 currentPosition = m_currentPosition; btScalar maxPen = btScalar(0.0); for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) { @@ -214,23 +301,52 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl for (int j = 0;j < m_manifoldArray.size(); j++) { btPersistentManifold* manifold = m_manifoldArray[j]; - btScalar directionSign = (manifold->getBody0() == m_ghostObject) ? btScalar(-1.0) : btScalar(1.0); + btScalar directionSign = (manifold->getBody0() == m_ghostObject) ? btScalar(1.0) : btScalar(-1.0); for (int p = 0;p < manifold->getNumContacts(); p++) { const btManifoldPoint&pt = manifold->getContactPoint(p); btScalar dist = pt.getDistance(); if (dist < 0.0) { - if (dist < maxPen) { - maxPen = dist; - m_touchingNormal = pt.m_normalWorldOnB * directionSign;//?? + bool useContact = true; + btVector3 normal = pt.m_normalWorldOnB; + normal *= directionSign; // always points from object to character + + btScalar normalDotUp = normal.dot(up); + if (normalDotUp < m_maxSlopeCosine) { + // this contact has a non-vertical normal... might need to ignored + btVector3 collisionPoint; + if (directionSign > 0.0) { + collisionPoint = pt.getPositionWorldOnB(); + } else { + collisionPoint = pt.getPositionWorldOnA(); + } + + // we do math in frame where character base is origin + btVector3 characterBase = currentPosition - (m_radius + m_halfHeight) * up; + collisionPoint -= characterBase; + btScalar collisionHeight = collisionPoint.dot(up); + + if (collisionHeight < m_lastStepUp) { + // This contact is below the lastStepUp, so we ignore it for penetration resolution, + // otherwise it may prevent the character from getting close enough to find any available + // horizontal foothold that would allow it to climbe the ledge. In other words, we're + // making the character's "feet" soft for collisions against steps, but not floors. + useContact = false; + } + } + if (useContact) { + + if (dist < maxPen) { + maxPen = dist; + m_floorNormal = normal; + } + const btScalar INCREMENTAL_RESOLUTION_FACTOR = 0.2f; + m_currentPosition += normal * (fabsf(dist) * INCREMENTAL_RESOLUTION_FACTOR); + penetration = true; } - m_currentPosition += pt.m_normalWorldOnB * directionSign * dist * btScalar(0.2); - penetration = true; } } - - //manifold->clearManifold(); } } btTransform newTrans = m_ghostObject->getWorldTransform(); @@ -241,43 +357,44 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl void CharacterController::stepUp( btCollisionWorld* world) { // phase 1: up + + // compute start and end btTransform start, end; - m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.0f ? m_verticalOffset : 0.0f)); - start.setIdentity(); - end.setIdentity(); - - /* FIXME: Handle penetration properly */ start.setOrigin(m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_convexShape->getMargin() + m_addedMargin)); + + //m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.0f ? m_verticalOffset : 0.0f)); + m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * m_stepHeight; + end.setIdentity(); end.setOrigin(m_targetPosition); - btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, -getUpAxisDirections()[m_upAxis], btScalar(0.7071)); + // sweep up + btVector3 sweepDirNegative = -getUpAxisDirections()[m_upAxis]; + btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, sweepDirNegative, btScalar(0.7071)); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; - - if (m_useGhostObjectSweepTest) { - m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration); - } - else { - world->convexSweepTest(m_convexShape, start, end, callback); - } + m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration); if (callback.hasHit()) { + // we hit something, so zero our vertical velocity + m_verticalVelocity = 0.0; + m_verticalOffset = 0.0; + // Only modify the position if the hit was a slope and not a wall or ceiling. if (callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > 0.0) { - // we moved up only a fraction of the step height - m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction; + m_lastStepUp = m_stepHeight * callback.m_closestHitFraction; if (m_interpolateUp == true) { m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); } else { m_currentPosition = m_targetPosition; } + } else { + m_lastStepUp = m_stepHeight; + m_currentPosition = m_targetPosition; } - m_verticalVelocity = 0.0; - m_verticalOffset = 0.0; } else { - m_currentStepOffset = m_stepHeight; m_currentPosition = m_targetPosition; + m_lastStepUp = m_stepHeight; } } @@ -309,194 +426,124 @@ void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& } } -void CharacterController::stepForwardAndStrafe( btCollisionWorld* collisionWorld, const btVector3& walkMove) { - // m_normalizedDirection[0], m_normalizedDirection[1], m_normalizedDirection[2]); - // phase 2: forward and strafe - btTransform start, end; - m_targetPosition = m_currentPosition + walkMove; +void CharacterController::stepForward( btCollisionWorld* collisionWorld, const btVector3& movement) { + // phase 2: forward + m_targetPosition = m_currentPosition + movement; + btTransform start, end; start.setIdentity(); end.setIdentity(); - btScalar fraction = 1.0; - btScalar distance2 = (m_currentPosition-m_targetPosition).length2(); - + /* TODO: experiment with this to see if we can use this to help direct motion when a floor is available if (m_touchingContact) { - if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0)) { - //interferes with step movement - //updateTargetPositionBasedOnCollision(m_touchingNormal); + if (m_normalizedDirection.dot(m_floorNormal) < btScalar(0.0)) { + updateTargetPositionBasedOnCollision(m_floorNormal, 1.0f, 1.0f); } - } + }*/ + // modify shape's margin for the sweeps + btScalar margin = m_convexShape->getMargin(); + m_convexShape->setMargin(margin + m_addedMargin); + + const btScalar MIN_STEP_DISTANCE = 0.0001f; + btVector3 step = m_targetPosition - m_currentPosition; + btScalar stepLength2 = step.length2(); int maxIter = 10; - while (fraction > btScalar(0.01) && maxIter-- > 0) { + while (stepLength2 > MIN_STEP_DISTANCE && maxIter-- > 0) { start.setOrigin(m_currentPosition); end.setOrigin(m_targetPosition); - btVector3 sweepDirNegative(m_currentPosition - m_targetPosition); + // sweep forward + btVector3 sweepDirNegative(m_currentPosition - m_targetPosition); btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, sweepDirNegative, btScalar(0.0)); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; - - btScalar margin = m_convexShape->getMargin(); - m_convexShape->setMargin(margin + m_addedMargin); - - if (m_useGhostObjectSweepTest) { - m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - } else { - collisionWorld->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - } - - m_convexShape->setMargin(margin); - - fraction -= callback.m_closestHitFraction; + m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); if (callback.hasHit()) { - // we moved only a fraction - //btScalar hitDistance; - //hitDistance = (callback.m_hitPointWorld - m_currentPosition).length(); + // we hit soemthing! + // Compute new target position by removing portion cut-off by collision, which will produce a new target + // that is the closest approach of the the obstacle plane to the original target. + step = m_targetPosition - m_currentPosition; + btScalar stepDotNormal = step.dot(callback.m_hitNormalWorld); // we expect this dot to be negative + step += (stepDotNormal * (1.0f - callback.m_closestHitFraction)) * callback.m_hitNormalWorld; + m_targetPosition = m_currentPosition + step; - //m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); - - updateTargetPositionBasedOnCollision(callback.m_hitNormalWorld); - btVector3 currentDir = m_targetPosition - m_currentPosition; - distance2 = currentDir.length2(); - if (distance2 > SIMD_EPSILON) { - currentDir.normalize(); - /* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */ - if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0)) { - break; - } - } else { - break; - } + stepLength2 = step.length2(); } else { - // we moved whole way + // we swept to the end without hitting anything m_currentPosition = m_targetPosition; + break; } - - //if (callback.m_closestHitFraction == 0.0f) { - // break; - //} - } + + // restore shape's margin + m_convexShape->setMargin(margin); } void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar dt) { - btTransform start, end, end_double; - bool runOnce = false; - // phase 3: down - /*btScalar additionalDownStep = (m_wasOnGround && !onGround()) ? m_stepHeight : 0.0; - btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + additionalDownStep); - btScalar downSpeed = (additionalDownStep == 0.0 && m_verticalVelocity < 0.0 ? -m_verticalVelocity : 0.0); - btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * downSpeed; - m_targetPosition -= (step_drop + gravity_drop);*/ - - btVector3 orig_position = m_targetPosition; + // + // The "stepDown" phase first makes a normal sweep down that cancels the lift from the "stepUp" phase. + // If it hits a ledge then it stops otherwise it makes another sweep down in search of a floor within + // reach of the character's feet. btScalar downSpeed = (m_verticalVelocity < 0.0f) ? -m_verticalVelocity : 0.0f; if (downSpeed > 0.0f && downSpeed > m_maxFallSpeed && (m_wasOnGround || !m_wasJumping)) { downSpeed = m_maxFallSpeed; } - btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + downSpeed * dt); - m_targetPosition -= step_drop; + // first sweep for ledge + btVector3 step = getUpAxisDirections()[m_upAxis] * (-(m_lastStepUp + downSpeed * dt)); - btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine); + StepDownConvexResultCallback callback(m_ghostObject, + getUpAxisDirections()[m_upAxis], + m_maxSlopeCosine, m_currentPosition, + step, m_radius, m_halfHeight, m_walkDirection); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; - btKinematicClosestNotMeConvexResultCallback callback2 (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine); - callback2.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; - callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; + btTransform start, end; + start.setIdentity(); + end.setIdentity(); - while (1) { - start.setIdentity(); - end.setIdentity(); + start.setOrigin(m_currentPosition); + m_targetPosition = m_currentPosition + step; + end.setOrigin(m_targetPosition); + m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - end_double.setIdentity(); + if (callback.hasHit()) { + m_currentPosition += callback.m_closestHitFraction * step; + m_verticalVelocity = 0.0f; + m_verticalOffset = 0.0f; + m_wasJumping = false; + } else { + // sweep again for floor within downStep threshold + StepDownConvexResultCallback callback2 (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine, m_currentPosition, step, m_radius, m_halfHeight, m_walkDirection); + + callback2.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; + callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; + + m_currentPosition = m_targetPosition; + btVector3 oldPosition = m_currentPosition; + step = (- m_stepHeight) * getUpAxisDirections()[m_upAxis]; + m_targetPosition = m_currentPosition + step; start.setOrigin(m_currentPosition); end.setOrigin(m_targetPosition); + m_ghostObject->convexSweepTest(m_convexShape, start, end, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - //set double test for 2x the step drop, to check for a large drop vs small drop - end_double.setOrigin(m_targetPosition - step_drop); - - if (m_useGhostObjectSweepTest) { - m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - - if (!callback.hasHit()) { - //test a double fall height, to see if the character should interpolate it's fall (full) or not (partial) - m_ghostObject->convexSweepTest(m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - } + if (callback2.hasHit()) { + m_currentPosition += callback2.m_closestHitFraction * step; + m_verticalVelocity = 0.0f; + m_verticalOffset = 0.0f; + m_wasJumping = false; } else { - collisionWorld->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - - if (!callback.hasHit()) { - //test a double fall height, to see if the character should interpolate it's fall (large) or not (small) - collisionWorld->convexSweepTest(m_convexShape, start, end_double, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); - } + // nothing to step down on, so remove the stepUp effect + m_currentPosition = oldPosition - m_lastStepUp * getUpAxisDirections()[m_upAxis]; + m_lastStepUp = 0.0f; } - - btScalar downDistance = (m_verticalVelocity < 0.0f ? -m_verticalVelocity : 0.0f) * dt; - bool has_hit = false; - if (bounce_fix == true) { - has_hit = callback.hasHit() || callback2.hasHit(); - } else { - has_hit = callback2.hasHit(); - } - - if (downDistance > 0.0 && downDistance < m_stepHeight && has_hit == true && runOnce == false - && (m_wasOnGround || !m_wasJumping)) { - //redo the velocity calculation when falling a small amount, for fast stairs motion - //for larger falls, use the smoother/slower interpolated movement by not touching the target position - - m_targetPosition = orig_position; - btVector3 step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + m_stepHeight); - m_targetPosition -= step_drop; - runOnce = true; - continue; //re-run previous tests - } - break; - } - - if (callback.hasHit() || runOnce == true) { - // we dropped a fraction of the height -> hit floor - - btScalar fraction = (m_currentPosition.getY() - callback.m_hitPointWorld.getY()) / 2; - - if (bounce_fix == true) { - if (full_drop == true) { - m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); - } else { - //due to errors in the closestHitFraction variable when used with large polygons, calculate the hit fraction manually - m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, fraction); - } - } else { - m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); - } - - full_drop = false; - - m_verticalVelocity = 0.0; - m_verticalOffset = 0.0; - m_wasJumping = false; - } else { - // we dropped the full height - full_drop = true; - - if (bounce_fix == true) { - downSpeed = (m_verticalVelocity < 0.0f) ? -m_verticalVelocity : 0.0f; - if (downSpeed > m_maxFallSpeed && (m_wasOnGround || !m_wasJumping)) { - m_targetPosition += step_drop; //undo previous target change - // use fallSpeed instead of downSpeed - step_drop = getUpAxisDirections()[m_upAxis] * (m_currentStepOffset + m_maxFallSpeed * dt); - m_targetPosition -= step_drop; - } - } - m_currentPosition = m_targetPosition; } } @@ -576,11 +623,11 @@ void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScala // the algorithm is as follows: // (1) step the character up a little bit so that its forward step doesn't hit the floor // (2) step the character forward - // (3) step the character down so that its back in contact with the ground + // (3) step the character down looking for new ledges, the original floor, or a floor one step below where we started - stepUp (collisionWorld); + stepUp(collisionWorld); if (m_useWalkDirection) { - stepForwardAndStrafe(collisionWorld, m_walkDirection); + stepForward(collisionWorld, m_walkDirection); } else { // compute substep and decrement total interval btScalar dtMoving = (dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval; @@ -588,7 +635,7 @@ void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScala // stepForward substep btVector3 move = m_walkDirection * dtMoving; - stepForwardAndStrafe(collisionWorld, move); + stepForward(collisionWorld, move); } stepDown(collisionWorld, dt); @@ -678,19 +725,23 @@ void CharacterController::createShapeAndGhost() { m_avatarData->unlock(); const glm::vec3& diagonal = box.getScale(); - float radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); - float halfHeight = 0.5f * diagonal.y - radius; + m_radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); + m_halfHeight = 0.5f * diagonal.y - m_radius; float MIN_HALF_HEIGHT = 0.1f; - if (halfHeight < MIN_HALF_HEIGHT) { - halfHeight = MIN_HALF_HEIGHT; + if (m_halfHeight < MIN_HALF_HEIGHT) { + m_halfHeight = MIN_HALF_HEIGHT; } glm::vec3 offset = box.getCorner() + 0.5f * diagonal; m_shapeLocalOffset = offset; - m_stepHeight = 0.1f; + // stepHeight affects the heights of ledges that the character can ascend + // however the actual ledge height is some function of m_stepHeight + // due to character shape and this CharacterController algorithm + // (the function is approximately 2*m_stepHeight) + m_stepHeight = 0.1f * (m_radius + m_halfHeight) + 0.1f; // create new shape - m_convexShape = new btCapsuleShape(radius, 2.0f * halfHeight); + m_convexShape = new btCapsuleShape(m_radius, 2.0f * m_halfHeight); m_ghostObject->setCollisionShape(m_convexShape); m_ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); } @@ -710,14 +761,9 @@ bool CharacterController::needsShapeUpdate() { } glm::vec3 offset = box.getCorner() + 0.5f * diagonal; - // get old dimensions from shape - btCapsuleShape* capsule = static_cast<btCapsuleShape*>(m_convexShape); - btScalar oldRadius = capsule->getRadius(); - btScalar oldHalfHeight = capsule->getHalfHeight(); - // compare dimensions (and offset) - float radiusDelta = glm::abs(radius - oldRadius); - float heightDelta = glm::abs(halfHeight - oldHalfHeight); + float radiusDelta = glm::abs(radius - m_radius); + float heightDelta = glm::abs(halfHeight - m_halfHeight); if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) { // shape hasn't changed --> nothing to do float offsetDelta = glm::distance(offset, m_shapeLocalOffset); diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 1805dcba74..7969fffd9d 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -46,9 +46,11 @@ protected: glm::vec3 m_shapeLocalOffset; btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast + btScalar m_radius; + btScalar m_halfHeight; btScalar m_verticalVelocity; - btScalar m_verticalOffset; + btScalar m_verticalOffset; // fall distance from velocity this frame btScalar m_maxFallSpeed; btScalar m_jumpSpeed; btScalar m_maxJumpHeight; @@ -68,19 +70,18 @@ protected: //some internal variables btVector3 m_currentPosition; - btScalar m_currentStepOffset; btVector3 m_targetPosition; + btScalar m_lastStepUp; ///keep track of the contact manifolds btManifoldArray m_manifoldArray; bool m_touchingContact; - btVector3 m_touchingNormal; // points from character to object + btVector3 m_floorNormal; // points from object to character bool m_enabled; bool m_wasOnGround; bool m_wasJumping; - bool m_useGhostObjectSweepTest; bool m_useWalkDirection; btScalar m_velocityTimeInterval; int m_upAxis; @@ -97,7 +98,7 @@ protected: bool recoverFromPenetration(btCollisionWorld* collisionWorld); void stepUp(btCollisionWorld* collisionWorld); void updateTargetPositionBasedOnCollision(const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0)); - void stepForwardAndStrafe(btCollisionWorld* collisionWorld, const btVector3& walkMove); + void stepForward(btCollisionWorld* collisionWorld, const btVector3& walkMove); void stepDown(btCollisionWorld* collisionWorld, btScalar dt); void createShapeAndGhost(); public: @@ -162,9 +163,6 @@ public: btScalar getMaxSlope() const; btPairCachingGhostObject* getGhostObject(); - void setUseGhostSweepTest(bool useGhostObjectSweepTest) { - m_useGhostObjectSweepTest = useGhostObjectSweepTest; - } bool onGround() const; void setUpInterpolate(bool value); From d2868bcafcd1bc0e0f5c69e572ef54f4da5f7615 Mon Sep 17 00:00:00 2001 From: samcake <samuel.gateau@gmail.com> Date: Thu, 19 Mar 2015 16:00:47 -0700 Subject: [PATCH 026/177] fixing the shader for mac --- libraries/gpu/src/gpu/Transform.slh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 4988b230cc..9019ec928c 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -88,7 +88,7 @@ TransformCamera getTransformCamera() { <@endif@> <@endfunc@> - + <@func transformModelToClipPos(cameraTransform, objectTransform, modelPos, clipPos)@> <@if GPU_TRANSFORM_PROFILE == GPU_CORE@> <!// Equivalent to the following but hoppefully a tad more accurate @@ -98,7 +98,7 @@ TransformCamera getTransformCamera() { <$clipPos$> = <$cameraTransform$>._projectionViewUntranslated * _eyepos; } <@else@> - <$clippos$> = gl_ModelViewProjectionMatrix * <$modelPos$>; + <$clipPos$> = gl_ModelViewProjectionMatrix * <$modelPos$>; <@endif@> <@endfunc@> From ab9d8eb345b2801f1d85b5e25b212281162ad6c0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Fri, 20 Mar 2015 08:42:35 -0700 Subject: [PATCH 027/177] reorder arguments to StepDownConvexResultCallback ctor --- libraries/physics/src/CharacterController.cpp | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 2c01e2ae32..fb200b2c57 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -112,21 +112,21 @@ class StepDownConvexResultCallback : public btCollisionWorld::ClosestConvexResul public: StepDownConvexResultCallback(btCollisionObject* me, const btVector3& up, - btScalar minSlopeDot, const btVector3& start, const btVector3& step, + const btVector3& pushDirection, + btScalar minSlopeDot, btScalar radius, - btScalar halfHeight, - btVector3 pushDirection) + btScalar halfHeight) : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) , m_me(me) , m_up(up) - , m_minSlopeDot(minSlopeDot) , m_start(start) , m_step(step) + , m_pushDirection(pushDirection) + , m_minSlopeDot(minSlopeDot) , m_radius(radius) , m_halfHeight(halfHeight) - , m_pushDirection(pushDirection) { } @@ -184,12 +184,12 @@ class StepDownConvexResultCallback : public btCollisionWorld::ClosestConvexResul protected: btCollisionObject* m_me; const btVector3 m_up; - btScalar m_minSlopeDot; btVector3 m_start; btVector3 m_step; + btVector3 m_pushDirection; + btScalar m_minSlopeDot; btScalar m_radius; btScalar m_halfHeight; - btVector3 m_pushDirection; }; /* @@ -499,8 +499,10 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d StepDownConvexResultCallback callback(m_ghostObject, getUpAxisDirections()[m_upAxis], - m_maxSlopeCosine, m_currentPosition, - step, m_radius, m_halfHeight, m_walkDirection); + m_currentPosition, step, + m_walkDirection, + m_maxSlopeCosine, + m_radius, m_halfHeight); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; @@ -520,7 +522,12 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d m_wasJumping = false; } else { // sweep again for floor within downStep threshold - StepDownConvexResultCallback callback2 (m_ghostObject, getUpAxisDirections()[m_upAxis], m_maxSlopeCosine, m_currentPosition, step, m_radius, m_halfHeight, m_walkDirection); + StepDownConvexResultCallback callback2 (m_ghostObject, + getUpAxisDirections()[m_upAxis], + m_currentPosition, step, + m_walkDirection, + m_maxSlopeCosine, + m_radius, m_halfHeight); callback2.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; From 63c51673de39b747c24889e61566293b5d97961a Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Fri, 20 Mar 2015 17:28:00 +0100 Subject: [PATCH 028/177] Move PROP_COLLISION_MODEL_URL to the right spot --- libraries/entities/src/EntityItemProperties.h | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 40a9760e5c..469b6067a8 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -93,7 +93,7 @@ enum EntityPropertyList { PROP_LOCAL_GRAVITY, PROP_PARTICLE_RADIUS, - // used by Model entities + PROP_COLLISION_MODEL_URL, PROP_ATTRIBUTION, // NOTE: add new properties ABOVE this line and then modify PROP_LAST_ITEM below @@ -104,8 +104,7 @@ enum EntityPropertyList { PROP_TEXT_COLOR = PROP_COLOR, PROP_TEXT = PROP_MODEL_URL, PROP_LINE_HEIGHT = PROP_ANIMATION_URL, - PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS, - PROP_COLLISION_MODEL_URL, + PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS }; typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags; From e4e0e2fd6b2a214d3709c67e434214b08b151633 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Fri, 20 Mar 2015 18:04:05 +0100 Subject: [PATCH 029/177] Update Edit.js HTML to display attribution property --- examples/html/entityProperties.html | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index 596bf5c9d5..dc632d76fd 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -140,6 +140,7 @@ var elLifetime = document.getElementById("property-lifetime"); var elScriptURL = document.getElementById("property-script-url"); var elUserData = document.getElementById("property-user-data"); + var elAttribution = document.getElementById("property-attribution"); var elBoxSections = document.querySelectorAll(".box-section"); var elBoxColorRed = document.getElementById("property-box-red"); @@ -263,6 +264,7 @@ elLifetime.value = properties.lifetime; elScriptURL.value = properties.script; elUserData.value = properties.userData; + elAttribution.value = properties.attribution; if (properties.type != "Box") { for (var i = 0; i < elBoxSections.length; i++) { @@ -393,6 +395,7 @@ elLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifetime')); elScriptURL.addEventListener('change', createEmitTextPropertyUpdateFunction('script')); elUserData.addEventListener('change', createEmitTextPropertyUpdateFunction('userData')); + elAttribution.addEventListener('change', createEmitTextPropertyUpdateFunction('attribution')); var boxColorChangeFunction = createEmitColorPropertyUpdateFunction( 'color', elBoxColorRed, elBoxColorGreen, elBoxColorBlue); @@ -627,6 +630,13 @@ </div> </div> + <div class="property"> + <div class="label">Attribution</div> + <div class="value"> + <textarea id="property-attribution"></textarea> + </div> + </div> + <div class="box-section property"> <div class="label">Color</div> From ad833b76c885295161ced47d7a28404693910d08 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Fri, 20 Mar 2015 11:43:01 -0700 Subject: [PATCH 030/177] fix PROP index mismatch --- libraries/entities/src/EntityItemProperties.h | 12 ++++++++++-- libraries/entities/src/ModelEntityItem.cpp | 2 ++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 469b6067a8..d821c82e89 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -96,15 +96,23 @@ enum EntityPropertyList { PROP_COLLISION_MODEL_URL, PROP_ATTRIBUTION, - // NOTE: add new properties ABOVE this line and then modify PROP_LAST_ITEM below + //////////////////////////////////////////////////////////////////////////////////////////////////// + // ATTENTION: add new properties ABOVE this line and then modify PROP_LAST_ITEM below PROP_LAST_ITEM = PROP_ATTRIBUTION, + //////////////////////////////////////////////////////////////////////////////////////////////////// + + //////////////////////////////////////////////////////////////////////////////////////////////////// + // WARNING! Do not add props here unless you intentionally mean to reuse PROP_ indexes + // // These properties of TextEntity piggy back off of properties of ModelEntities, the type doesn't matter // since the derived class knows how to interpret it's own properties and knows the types it expects PROP_TEXT_COLOR = PROP_COLOR, PROP_TEXT = PROP_MODEL_URL, PROP_LINE_HEIGHT = PROP_ANIMATION_URL, - PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS + PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS, + PROP_COLLISION_MODEL_URL_OLD_VERSION + // WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above }; typedef PropertyFlags<EntityPropertyList> EntityPropertyFlags; diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index ce009988b1..a2364f9e17 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -98,6 +98,8 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL); if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) { setCollisionModelURL(""); + } else if (args.bitstreamVersion < VERSION_ENTITIES_HAS_ATTRIBUTION) { + READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL_OLD_VERSION, setCollisionModelURL); } else { READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL, setCollisionModelURL); } From fdbf4e5288b685bbf7a730a6969600dc571a3ffd Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Fri, 20 Mar 2015 11:55:00 -0700 Subject: [PATCH 031/177] cleaning code for review --- libraries/gpu/src/gpu/Shader.h | 18 +++++++++--------- libraries/model/src/model/Light.h | 18 +++++++++--------- libraries/model/src/model/Material.h | 14 +++++++------- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index d88c2d5a87..5ac9b3a173 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -41,18 +41,18 @@ public: Language _lang = GLSL; }; - static const uint32 INVALID_LOCATION = -1; + static const int32 INVALID_LOCATION = -1; class Slot { public: - std::string _name = (""); - int32 _location = INVALID_LOCATION; - Element _element = Element(); - uint16 _resourceType = Resource::BUFFER; + std::string _name; + int32 _location{INVALID_LOCATION}; + Element _element; + uint16 _resourceType{Resource::BUFFER}; Slot(const Slot& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType) {} - Slot(const Slot&& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType) {} + Slot(Slot&& s) : _name(s._name), _location(s._location), _element(s._element), _resourceType(s._resourceType) {} Slot(const std::string& name, int32 location, const Element& element, uint16 resourceType = Resource::BUFFER) : _name(name), _location(location), _element(element), _resourceType(resourceType) {} Slot(const std::string& name) : _name(name) {} @@ -79,13 +79,13 @@ public: class SlotSet : public std::set<Slot, Less<Slot>> { public: - const Slot&& findSlot(const std::string& name) const { + Slot findSlot(const std::string& name) const { auto key = Slot(name); auto found = static_cast<const std::set<Slot, Less<Slot>>*>(this)->find(key); if (found != end()) { - return std::move((*found)); + return (*found); } - return std::move(key); + return key; } int32 findLocation(const std::string& name) const { return findSlot(name)._location; diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index 2c76714740..8f6c663668 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -252,16 +252,16 @@ public: // Schema to access the attribute values of the light class Schema { public: - Vec4 _position = Vec4(0.0f, 0.0f, 0.0f, 1.0f); - Vec3 _direction = Vec3(0.0f, 0.0f, -1.0f); - float _spare0 = 0.0f; - Color _color = Color(1.0f); - float _intensity = 1.0f; - Vec4 _attenuation = Vec4(1.0f); - Vec4 _spot = Vec4(0.0f, 0.0f, 0.0f, 3.0f); - Vec4 _shadow = Vec4(0.0f); + Vec4 _position{0.0f, 0.0f, 0.0f, 1.0f}; + Vec3 _direction{0.0f, 0.0f, -1.0f}; + float _spare0{0.0f}; + Color _color{1.0f}; + float _intensity{1.0f}; + Vec4 _attenuation{1.0f}; + Vec4 _spot{0.0f, 0.0f, 0.0f, 3.0f}; + Vec4 _shadow{0.0f}; - Vec4 _control = Vec4(0.0f); + Vec4 _control{0.0f}; Schema() {} }; diff --git a/libraries/model/src/model/Material.h b/libraries/model/src/model/Material.h index 865fd6dfb1..9262f23746 100755 --- a/libraries/model/src/model/Material.h +++ b/libraries/model/src/model/Material.h @@ -79,13 +79,13 @@ public: class Schema { public: - Color _diffuse = Color(0.5f); - float _opacity = 1.f; - Color _specular = Color(0.03f); - float _shininess = 0.1f; - Color _emissive = Color(0.0f); - float _spare0 = 0.0f; - glm::vec4 _spareVec4 = glm::vec4(0.0f); // for alignment beauty, Mat size == Mat4x4 + Color _diffuse{0.5f}; + float _opacity{1.f}; + Color _specular{0.03f}; + float _shininess{0.1f}; + Color _emissive{0.0f}; + float _spare0{0.0f}; + glm::vec4 _spareVec4{0.0f}; // for alignment beauty, Material size == Mat4x4 Schema() {} }; From 50631595815cb778d7cbf65e4fed2281f710f997 Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Fri, 20 Mar 2015 12:00:16 -0700 Subject: [PATCH 032/177] cleaning code for review --- libraries/gpu/src/gpu/Shader.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/Shader.h b/libraries/gpu/src/gpu/Shader.h index 5ac9b3a173..c8db7cfd39 100755 --- a/libraries/gpu/src/gpu/Shader.h +++ b/libraries/gpu/src/gpu/Shader.h @@ -69,7 +69,7 @@ public: public: std::string _name; int32 _location; - Binding(const std::string&& name, int32 loc = INVALID_LOCATION) : _name(name), _location(loc) {} + Binding(const std::string& name, int32 loc = INVALID_LOCATION) : _name(name), _location(loc) {} }; template <typename T> class Less { From 6454149536921dee807cfce03388ba3a1bd85262 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Fri, 20 Mar 2015 12:45:29 -0700 Subject: [PATCH 033/177] formatting and comments --- libraries/physics/src/CharacterController.cpp | 25 +++++++++++++------ libraries/physics/src/CharacterController.h | 2 -- libraries/physics/src/PhysicsEngine.cpp | 4 ++- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index fb200b2c57..256c83357a 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -231,7 +231,6 @@ CharacterController::CharacterController(AvatarData* avatarData) { m_addedMargin = 0.02f; m_walkDirection.setValue(0.0f,0.0f,0.0f); - m_turnAngle = btScalar(0.0f); m_useWalkDirection = true; // use walk direction by default, legacy behavior m_velocityTimeInterval = 0.0f; m_verticalVelocity = 0.0f; @@ -797,19 +796,31 @@ void CharacterController::updateShape() { } void CharacterController::preSimulation(btScalar timeStep) { + bool wasEnabled = m_enabled; + + // lock avatarData, get everything we need from it ASAP, then unlock m_avatarData->lockForRead(); - - // cache the "PhysicsEnabled" state of m_avatarData here - // and use the cached value for the rest of the simulation step m_enabled = m_avatarData->isPhysicsEnabled(); - glm::quat rotation = m_avatarData->getOrientation(); glm::vec3 position = m_avatarData->getPosition() + rotation * m_shapeLocalOffset; - m_ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); + // TODO: Andrew to implement: harvest jump event here btVector3 walkVelocity = glmToBullet(m_avatarData->getVelocity()); - setVelocityForTimeInterval(walkVelocity, timeStep); m_avatarData->unlock(); + + if (wasEnabled != m_enabled) { + if (m_enabled) { + // TODO: Andrew to implement: add collision shape back into world + } else { + // TODO: Andrew to implement: remove collision shape from world, + // otherwise things will continue to collide with it + } + } + + if (m_enabled) { + m_ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); + setVelocityForTimeInterval(walkVelocity, timeStep); + } } void CharacterController::postSimulation() { diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 7969fffd9d..b84662a389 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -58,8 +58,6 @@ protected: btScalar m_maxSlopeCosine; // Cosine equivalent of m_maxSlopeRadians (calculated once when set, for optimization) btScalar m_gravity; - btScalar m_turnAngle; - btScalar m_stepHeight; // height of stepUp prior to stepForward btScalar m_addedMargin;//@todo: remove this and fix the code diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index a46ba9f819..447a3ab6f1 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -294,16 +294,18 @@ void PhysicsEngine::stepSimulation() { _clock.reset(); float timeStep = btMin(dt, MAX_TIMESTEP); - // This is step (2). + // TODO: move character->preSimulation() into relayIncomingChanges if (_characterController) { _characterController->preSimulation(timeStep); } + // This is step (2). int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); _numSubsteps += (uint32_t)numSubsteps; stepNonPhysicalKinematics(usecTimestampNow()); unlock(); + // TODO: make all of this harvest stuff into one function: relayOutgoingChanges() if (numSubsteps > 0) { // This is step (3) which is done outside of stepSimulation() so we can lock _entityTree. // From 68de91c80aeb23e90e829bce16c9d96d4bb5c0fe Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Fri, 20 Mar 2015 13:17:32 -0700 Subject: [PATCH 034/177] cleaning code for review --- libraries/render-utils/src/Model.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 9fd15e6f27..0e0f081ec8 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -2209,23 +2209,23 @@ void Model::pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, f if (hasSpecular) { program = _lightmapNormalSpecularMapProgram; locations = &_lightmapNormalSpecularMapLocations; - skinProgram.reset(nullptr); + skinProgram.reset(); skinLocations = NULL; } else { program = _lightmapNormalMapProgram; locations = &_lightmapNormalMapLocations; - skinProgram.reset(nullptr); + skinProgram.reset(); skinLocations = NULL; } } else if (hasSpecular) { program = _lightmapSpecularMapProgram; locations = &_lightmapSpecularMapLocations; - skinProgram.reset(nullptr); + skinProgram.reset(); skinLocations = NULL; } else { program = _lightmapProgram; locations = &_lightmapLocations; - skinProgram.reset(nullptr); + skinProgram.reset(); skinLocations = NULL; } } else { From 0164de80fe5d235d5a44d05489841b2df194dabc Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Fri, 20 Mar 2015 13:19:24 -0700 Subject: [PATCH 035/177] apply coding standard to CharacterController --- libraries/physics/src/CharacterController.cpp | 514 +++++++++--------- libraries/physics/src/CharacterController.h | 65 ++- 2 files changed, 285 insertions(+), 294 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 256c83357a..f7f8ab4d53 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -48,18 +48,18 @@ class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::Closes public: btKinematicClosestNotMeRayResultCallback(btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) { -m_me = me; +_me = me; } virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) { -if (rayResult.m_collisionObject == m_me) +if (rayResult.m_collisionObject == _me) return 1.0; return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); } protected: -btCollisionObject* m_me; +btCollisionObject* _me; }; */ @@ -67,14 +67,14 @@ class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::Clo public: btKinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot) : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) - , m_me(me) - , m_up(up) - , m_minSlopeDot(minSlopeDot) + , _me(me) + , _up(up) + , _minSlopeDot(minSlopeDot) { } virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace) { - if (convexResult.m_hitCollisionObject == m_me) { + if (convexResult.m_hitCollisionObject == _me) { return btScalar(1.0); } @@ -91,10 +91,10 @@ class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::Clo } // Note: hitNormalWorld points into character, away from object - // and m_up points opposite to movement + // and _up points opposite to movement - btScalar dotUp = m_up.dot(hitNormalWorld); - if (dotUp < m_minSlopeDot) { + btScalar dotUp = _up.dot(hitNormalWorld); + if (dotUp < _minSlopeDot) { return btScalar(1.0); } @@ -102,9 +102,9 @@ class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::Clo } protected: - btCollisionObject* m_me; - const btVector3 m_up; - btScalar m_minSlopeDot; + btCollisionObject* _me; + const btVector3 _up; + btScalar _minSlopeDot; }; class StepDownConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { @@ -119,19 +119,19 @@ class StepDownConvexResultCallback : public btCollisionWorld::ClosestConvexResul btScalar radius, btScalar halfHeight) : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) - , m_me(me) - , m_up(up) - , m_start(start) - , m_step(step) - , m_pushDirection(pushDirection) - , m_minSlopeDot(minSlopeDot) - , m_radius(radius) - , m_halfHeight(halfHeight) + , _me(me) + , _up(up) + , _start(start) + , _step(step) + , _pushDirection(pushDirection) + , _minSlopeDot(minSlopeDot) + , _radius(radius) + , _halfHeight(halfHeight) { } virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult, bool normalInWorldSpace) { - if (convexResult.m_hitCollisionObject == m_me) { + if (convexResult.m_hitCollisionObject == _me) { return btScalar(1.0); } @@ -148,24 +148,24 @@ class StepDownConvexResultCallback : public btCollisionWorld::ClosestConvexResul } // Note: hitNormalWorld points into character, away from object - // and m_up points opposite to movement + // and _up points opposite to movement - btScalar dotUp = m_up.dot(hitNormalWorld); - if (dotUp < m_minSlopeDot) { - if (hitNormalWorld.dot(m_pushDirection) > 0.0f) { + btScalar dotUp = _up.dot(hitNormalWorld); + if (dotUp < _minSlopeDot) { + if (hitNormalWorld.dot(_pushDirection) > 0.0f) { // ignore hits that push in same direction as character is moving // which helps character NOT snag when stepping off ledges return btScalar(1.0f); } // compute the angle between "down" and the line from character center to "hit" point - btVector3 fractionalStep = convexResult.m_hitFraction * m_step; - btVector3 localHit = convexResult.m_hitPointLocal - m_start + fractionalStep; - btScalar angle = localHit.angle(-m_up); + btVector3 fractionalStep = convexResult.m_hitFraction * _step; + btVector3 localHit = convexResult.m_hitPointLocal - _start + fractionalStep; + btScalar angle = localHit.angle(-_up); - // compute a maxAngle based on size of m_step - btVector3 side(m_radius, - (m_halfHeight - m_step.length() + fractionalStep.dot(m_up)), 0.0f); - btScalar maxAngle = side.angle(-m_up); + // compute a maxAngle based on size of _step + btVector3 side(_radius, - (_halfHeight - _step.length() + fractionalStep.dot(_up)), 0.0f); + btScalar maxAngle = side.angle(-_up); // Ignore hits that are larger than maxAngle. Effectively what is happening here is: // we're ignoring hits at contacts that have non-vertical normals... if they hit higher @@ -182,14 +182,14 @@ class StepDownConvexResultCallback : public btCollisionWorld::ClosestConvexResul } protected: - btCollisionObject* m_me; - const btVector3 m_up; - btVector3 m_start; - btVector3 m_step; - btVector3 m_pushDirection; - btScalar m_minSlopeDot; - btScalar m_radius; - btScalar m_halfHeight; + btCollisionObject* _me; + const btVector3 _up; + btVector3 _start; + btVector3 _step; + btVector3 _pushDirection; + btScalar _minSlopeDot; + btScalar _radius; + btScalar _halfHeight; }; /* @@ -218,42 +218,37 @@ btVector3 CharacterController::perpindicularComponent(const btVector3& direction CharacterController::CharacterController(AvatarData* avatarData) { assert(avatarData); - m_avatarData = avatarData; + _avatarData = avatarData; - // cache the "PhysicsEnabled" state of m_avatarData - m_avatarData->lockForRead(); - m_enabled = m_avatarData->isPhysicsEnabled(); - m_avatarData->unlock(); + // cache the "PhysicsEnabled" state of _avatarData + _avatarData->lockForRead(); + _enabled = _avatarData->isPhysicsEnabled(); + _avatarData->unlock(); createShapeAndGhost(); - m_upAxis = 1; // HACK: hard coded to be 1 for now (yAxis) + _upAxis = 1; // HACK: hard coded to be 1 for now (yAxis) - m_addedMargin = 0.02f; - m_walkDirection.setValue(0.0f,0.0f,0.0f); - m_useWalkDirection = true; // use walk direction by default, legacy behavior - m_velocityTimeInterval = 0.0f; - m_verticalVelocity = 0.0f; - m_verticalOffset = 0.0f; - m_gravity = 9.8f; - m_maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s. - m_jumpSpeed = 10.0f; // ? - m_wasOnGround = false; - m_wasJumping = false; - m_interpolateUp = true; + _addedMargin = 0.02f; + _walkDirection.setValue(0.0f,0.0f,0.0f); + _useWalkDirection = true; // use walk direction by default, legacy behavior + _velocityTimeInterval = 0.0f; + _verticalVelocity = 0.0f; + _verticalOffset = 0.0f; + _gravity = 9.8f; + _maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s. + _jumpSpeed = 10.0f; // ? + _wasOnGround = false; + _wasJumping = false; setMaxSlope(btRadians(45.0f)); - m_lastStepUp = 0.0f; - - // internal state data members - full_drop = false; - bounce_fix = false; + _lastStepUp = 0.0f; } CharacterController::~CharacterController() { } btPairCachingGhostObject* CharacterController::getGhostObject() { - return m_ghostObject; + return _ghostObject; } bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorld) { @@ -266,26 +261,26 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl // paircache and the ghostobject's internal paircache at the same time. /BW btVector3 minAabb, maxAabb; - m_convexShape->getAabb(m_ghostObject->getWorldTransform(), minAabb, maxAabb); - collisionWorld->getBroadphase()->setAabb(m_ghostObject->getBroadphaseHandle(), + _convexShape->getAabb(_ghostObject->getWorldTransform(), minAabb, maxAabb); + collisionWorld->getBroadphase()->setAabb(_ghostObject->getBroadphaseHandle(), minAabb, maxAabb, collisionWorld->getDispatcher()); bool penetration = false; - collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher()); + collisionWorld->getDispatcher()->dispatchAllCollisionPairs(_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher()); - m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); - btVector3 up = getUpAxisDirections()[m_upAxis]; + _currentPosition = _ghostObject->getWorldTransform().getOrigin(); + btVector3 up = getUpAxisDirections()[_upAxis]; - btVector3 currentPosition = m_currentPosition; + btVector3 currentPosition = _currentPosition; btScalar maxPen = btScalar(0.0); - for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) { - m_manifoldArray.resize(0); + for (int i = 0; i < _ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) { + _manifoldArray.resize(0); - btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; + btBroadphasePair* collisionPair = &_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; btCollisionObject* obj0 = static_cast<btCollisionObject*>(collisionPair->m_pProxy0->m_clientObject); btCollisionObject* obj1 = static_cast<btCollisionObject*>(collisionPair->m_pProxy1->m_clientObject); @@ -295,12 +290,12 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl } if (collisionPair->m_algorithm) { - collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray); + collisionPair->m_algorithm->getAllContactManifolds(_manifoldArray); } - for (int j = 0;j < m_manifoldArray.size(); j++) { - btPersistentManifold* manifold = m_manifoldArray[j]; - btScalar directionSign = (manifold->getBody0() == m_ghostObject) ? btScalar(1.0) : btScalar(-1.0); + for (int j = 0;j < _manifoldArray.size(); j++) { + btPersistentManifold* manifold = _manifoldArray[j]; + btScalar directionSign = (manifold->getBody0() == _ghostObject) ? btScalar(1.0) : btScalar(-1.0); for (int p = 0;p < manifold->getNumContacts(); p++) { const btManifoldPoint&pt = manifold->getContactPoint(p); @@ -312,7 +307,7 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl normal *= directionSign; // always points from object to character btScalar normalDotUp = normal.dot(up); - if (normalDotUp < m_maxSlopeCosine) { + if (normalDotUp < _maxSlopeCosine) { // this contact has a non-vertical normal... might need to ignored btVector3 collisionPoint; if (directionSign > 0.0) { @@ -322,11 +317,11 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl } // we do math in frame where character base is origin - btVector3 characterBase = currentPosition - (m_radius + m_halfHeight) * up; + btVector3 characterBase = currentPosition - (_radius + _halfHeight) * up; collisionPoint -= characterBase; btScalar collisionHeight = collisionPoint.dot(up); - if (collisionHeight < m_lastStepUp) { + if (collisionHeight < _lastStepUp) { // This contact is below the lastStepUp, so we ignore it for penetration resolution, // otherwise it may prevent the character from getting close enough to find any available // horizontal foothold that would allow it to climbe the ledge. In other words, we're @@ -338,19 +333,19 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl if (dist < maxPen) { maxPen = dist; - m_floorNormal = normal; + _floorNormal = normal; } const btScalar INCREMENTAL_RESOLUTION_FACTOR = 0.2f; - m_currentPosition += normal * (fabsf(dist) * INCREMENTAL_RESOLUTION_FACTOR); + _currentPosition += normal * (fabsf(dist) * INCREMENTAL_RESOLUTION_FACTOR); penetration = true; } } } } } - btTransform newTrans = m_ghostObject->getWorldTransform(); - newTrans.setOrigin(m_currentPosition); - m_ghostObject->setWorldTransform(newTrans); + btTransform newTrans = _ghostObject->getWorldTransform(); + newTrans.setOrigin(_currentPosition); + _ghostObject->setWorldTransform(newTrans); return penetration; } @@ -360,45 +355,40 @@ void CharacterController::stepUp( btCollisionWorld* world) { // compute start and end btTransform start, end; start.setIdentity(); - start.setOrigin(m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_convexShape->getMargin() + m_addedMargin)); + start.setOrigin(_currentPosition + getUpAxisDirections()[_upAxis] * (_convexShape->getMargin() + _addedMargin)); - //m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * (m_stepHeight + (m_verticalOffset > 0.0f ? m_verticalOffset : 0.0f)); - m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * m_stepHeight; + _targetPosition = _currentPosition + getUpAxisDirections()[_upAxis] * _stepHeight; end.setIdentity(); - end.setOrigin(m_targetPosition); + end.setOrigin(_targetPosition); // sweep up - btVector3 sweepDirNegative = -getUpAxisDirections()[m_upAxis]; - btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, sweepDirNegative, btScalar(0.7071)); + btVector3 sweepDirNegative = -getUpAxisDirections()[_upAxis]; + btKinematicClosestNotMeConvexResultCallback callback(_ghostObject, sweepDirNegative, btScalar(0.7071)); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; - m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration); + _ghostObject->convexSweepTest(_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration); if (callback.hasHit()) { // we hit something, so zero our vertical velocity - m_verticalVelocity = 0.0; - m_verticalOffset = 0.0; + _verticalVelocity = 0.0; + _verticalOffset = 0.0; // Only modify the position if the hit was a slope and not a wall or ceiling. - if (callback.m_hitNormalWorld.dot(getUpAxisDirections()[m_upAxis]) > 0.0) { - m_lastStepUp = m_stepHeight * callback.m_closestHitFraction; - if (m_interpolateUp == true) { - m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); - } else { - m_currentPosition = m_targetPosition; - } + if (callback.m_hitNormalWorld.dot(getUpAxisDirections()[_upAxis]) > 0.0) { + _lastStepUp = _stepHeight * callback.m_closestHitFraction; + _currentPosition.setInterpolate3(_currentPosition, _targetPosition, callback.m_closestHitFraction); } else { - m_lastStepUp = m_stepHeight; - m_currentPosition = m_targetPosition; + _lastStepUp = _stepHeight; + _currentPosition = _targetPosition; } } else { - m_currentPosition = m_targetPosition; - m_lastStepUp = m_stepHeight; + _currentPosition = _targetPosition; + _lastStepUp = _stepHeight; } } void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag) { - btVector3 movementDirection = m_targetPosition - m_currentPosition; + btVector3 movementDirection = _targetPosition - _currentPosition; btScalar movementLength = movementDirection.length(); if (movementLength > SIMD_EPSILON) { movementDirection.normalize(); @@ -411,74 +401,74 @@ void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& parallelDir = parallelComponent(reflectDir, hitNormal); perpindicularDir = perpindicularComponent(reflectDir, hitNormal); - m_targetPosition = m_currentPosition; + _targetPosition = _currentPosition; //if (tangentMag != 0.0) { if (0) { btVector3 parComponent = parallelDir * btScalar(tangentMag * movementLength); - m_targetPosition += parComponent; + _targetPosition += parComponent; } if (normalMag != 0.0) { btVector3 perpComponent = perpindicularDir * btScalar(normalMag * movementLength); - m_targetPosition += perpComponent; + _targetPosition += perpComponent; } } } void CharacterController::stepForward( btCollisionWorld* collisionWorld, const btVector3& movement) { // phase 2: forward - m_targetPosition = m_currentPosition + movement; + _targetPosition = _currentPosition + movement; btTransform start, end; start.setIdentity(); end.setIdentity(); /* TODO: experiment with this to see if we can use this to help direct motion when a floor is available - if (m_touchingContact) { - if (m_normalizedDirection.dot(m_floorNormal) < btScalar(0.0)) { - updateTargetPositionBasedOnCollision(m_floorNormal, 1.0f, 1.0f); + if (_touchingContact) { + if (_normalizedDirection.dot(_floorNormal) < btScalar(0.0)) { + updateTargetPositionBasedOnCollision(_floorNormal, 1.0f, 1.0f); } }*/ // modify shape's margin for the sweeps - btScalar margin = m_convexShape->getMargin(); - m_convexShape->setMargin(margin + m_addedMargin); + btScalar margin = _convexShape->getMargin(); + _convexShape->setMargin(margin + _addedMargin); const btScalar MIN_STEP_DISTANCE = 0.0001f; - btVector3 step = m_targetPosition - m_currentPosition; + btVector3 step = _targetPosition - _currentPosition; btScalar stepLength2 = step.length2(); int maxIter = 10; while (stepLength2 > MIN_STEP_DISTANCE && maxIter-- > 0) { - start.setOrigin(m_currentPosition); - end.setOrigin(m_targetPosition); + start.setOrigin(_currentPosition); + end.setOrigin(_targetPosition); // sweep forward - btVector3 sweepDirNegative(m_currentPosition - m_targetPosition); - btKinematicClosestNotMeConvexResultCallback callback(m_ghostObject, sweepDirNegative, btScalar(0.0)); + btVector3 sweepDirNegative(_currentPosition - _targetPosition); + btKinematicClosestNotMeConvexResultCallback callback(_ghostObject, sweepDirNegative, btScalar(0.0)); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; - m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); + _ghostObject->convexSweepTest(_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); if (callback.hasHit()) { // we hit soemthing! // Compute new target position by removing portion cut-off by collision, which will produce a new target // that is the closest approach of the the obstacle plane to the original target. - step = m_targetPosition - m_currentPosition; + step = _targetPosition - _currentPosition; btScalar stepDotNormal = step.dot(callback.m_hitNormalWorld); // we expect this dot to be negative step += (stepDotNormal * (1.0f - callback.m_closestHitFraction)) * callback.m_hitNormalWorld; - m_targetPosition = m_currentPosition + step; + _targetPosition = _currentPosition + step; stepLength2 = step.length2(); } else { // we swept to the end without hitting anything - m_currentPosition = m_targetPosition; + _currentPosition = _targetPosition; break; } } // restore shape's margin - m_convexShape->setMargin(margin); + _convexShape->setMargin(margin); } void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar dt) { @@ -488,20 +478,20 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d // If it hits a ledge then it stops otherwise it makes another sweep down in search of a floor within // reach of the character's feet. - btScalar downSpeed = (m_verticalVelocity < 0.0f) ? -m_verticalVelocity : 0.0f; - if (downSpeed > 0.0f && downSpeed > m_maxFallSpeed && (m_wasOnGround || !m_wasJumping)) { - downSpeed = m_maxFallSpeed; + btScalar downSpeed = (_verticalVelocity < 0.0f) ? -_verticalVelocity : 0.0f; + if (downSpeed > 0.0f && downSpeed > _maxFallSpeed && (_wasOnGround || !_wasJumping)) { + downSpeed = _maxFallSpeed; } // first sweep for ledge - btVector3 step = getUpAxisDirections()[m_upAxis] * (-(m_lastStepUp + downSpeed * dt)); + btVector3 step = getUpAxisDirections()[_upAxis] * (-(_lastStepUp + downSpeed * dt)); - StepDownConvexResultCallback callback(m_ghostObject, - getUpAxisDirections()[m_upAxis], - m_currentPosition, step, - m_walkDirection, - m_maxSlopeCosine, - m_radius, m_halfHeight); + StepDownConvexResultCallback callback(_ghostObject, + getUpAxisDirections()[_upAxis], + _currentPosition, step, + _walkDirection, + _maxSlopeCosine, + _radius, _halfHeight); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; @@ -509,75 +499,77 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d start.setIdentity(); end.setIdentity(); - start.setOrigin(m_currentPosition); - m_targetPosition = m_currentPosition + step; - end.setOrigin(m_targetPosition); - m_ghostObject->convexSweepTest(m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); + start.setOrigin(_currentPosition); + _targetPosition = _currentPosition + step; + end.setOrigin(_targetPosition); + _ghostObject->convexSweepTest(_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); if (callback.hasHit()) { - m_currentPosition += callback.m_closestHitFraction * step; - m_verticalVelocity = 0.0f; - m_verticalOffset = 0.0f; - m_wasJumping = false; + _currentPosition += callback.m_closestHitFraction * step; + _verticalVelocity = 0.0f; + _verticalOffset = 0.0f; + _wasJumping = false; } else { // sweep again for floor within downStep threshold - StepDownConvexResultCallback callback2 (m_ghostObject, - getUpAxisDirections()[m_upAxis], - m_currentPosition, step, - m_walkDirection, - m_maxSlopeCosine, - m_radius, m_halfHeight); + StepDownConvexResultCallback callback2 (_ghostObject, + getUpAxisDirections()[_upAxis], + _currentPosition, step, + _walkDirection, + _maxSlopeCosine, + _radius, _halfHeight); callback2.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; - m_currentPosition = m_targetPosition; - btVector3 oldPosition = m_currentPosition; - step = (- m_stepHeight) * getUpAxisDirections()[m_upAxis]; - m_targetPosition = m_currentPosition + step; + _currentPosition = _targetPosition; + btVector3 oldPosition = _currentPosition; + step = (- _stepHeight) * getUpAxisDirections()[_upAxis]; + _targetPosition = _currentPosition + step; - start.setOrigin(m_currentPosition); - end.setOrigin(m_targetPosition); - m_ghostObject->convexSweepTest(m_convexShape, start, end, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); + start.setOrigin(_currentPosition); + end.setOrigin(_targetPosition); + _ghostObject->convexSweepTest(_convexShape, start, end, callback2, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); if (callback2.hasHit()) { - m_currentPosition += callback2.m_closestHitFraction * step; - m_verticalVelocity = 0.0f; - m_verticalOffset = 0.0f; - m_wasJumping = false; + _currentPosition += callback2.m_closestHitFraction * step; + _verticalVelocity = 0.0f; + _verticalOffset = 0.0f; + _wasJumping = false; } else { // nothing to step down on, so remove the stepUp effect - m_currentPosition = oldPosition - m_lastStepUp * getUpAxisDirections()[m_upAxis]; - m_lastStepUp = 0.0f; + _currentPosition = oldPosition - _lastStepUp * getUpAxisDirections()[_upAxis]; + _lastStepUp = 0.0f; } } } void CharacterController::setWalkDirection(const btVector3& walkDirection) { - m_useWalkDirection = true; - m_walkDirection = walkDirection; - m_normalizedDirection = getNormalizedVector(m_walkDirection); + _useWalkDirection = true; + _walkDirection = walkDirection; + _normalizedDirection = getNormalizedVector(_walkDirection); } void CharacterController::setVelocityForTimeInterval(const btVector3& velocity, btScalar timeInterval) { - m_useWalkDirection = false; - m_walkDirection = velocity; - m_normalizedDirection = getNormalizedVector(m_walkDirection); - m_velocityTimeInterval += timeInterval; + _useWalkDirection = false; + _walkDirection = velocity; + _normalizedDirection = getNormalizedVector(_walkDirection); + _velocityTimeInterval += timeInterval; } void CharacterController::reset( btCollisionWorld* collisionWorld ) { - m_verticalVelocity = 0.0; - m_verticalOffset = 0.0; - m_wasOnGround = false; - m_wasJumping = false; - m_walkDirection.setValue(0,0,0); - m_velocityTimeInterval = 0.0; + _verticalVelocity = 0.0; + _verticalOffset = 0.0; + _wasOnGround = false; + _wasJumping = false; + _walkDirection.setValue(0,0,0); + _velocityTimeInterval = 0.0; //clear pair cache - btHashedOverlappingPairCache *cache = m_ghostObject->getOverlappingPairCache(); + btHashedOverlappingPairCache *cache = _ghostObject->getOverlappingPairCache(); while (cache->getOverlappingPairArray().size() > 0) { - cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher()); + cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, + cache->getOverlappingPairArray()[0].m_pProxy1, + collisionWorld->getDispatcher()); } } @@ -585,46 +577,46 @@ void CharacterController::warp(const btVector3& origin) { btTransform xform; xform.setIdentity(); xform.setOrigin(origin); - m_ghostObject->setWorldTransform(xform); + _ghostObject->setWorldTransform(xform); } void CharacterController::preStep( btCollisionWorld* collisionWorld) { - if (!m_enabled) { + if (!_enabled) { return; } int numPenetrationLoops = 0; - m_touchingContact = false; + _touchingContact = false; while (recoverFromPenetration(collisionWorld)) { numPenetrationLoops++; - m_touchingContact = true; + _touchingContact = true; if (numPenetrationLoops > 4) { break; } } - m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); - m_targetPosition = m_currentPosition; + _currentPosition = _ghostObject->getWorldTransform().getOrigin(); + _targetPosition = _currentPosition; } void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScalar dt) { - if (!m_enabled || (!m_useWalkDirection && m_velocityTimeInterval <= 0.0)) { + if (!_enabled || (!_useWalkDirection && _velocityTimeInterval <= 0.0)) { return; // no motion } - m_wasOnGround = onGround(); + _wasOnGround = onGround(); // Update fall velocity. - m_verticalVelocity -= m_gravity * dt; - if (m_verticalVelocity > m_jumpSpeed) { - m_verticalVelocity = m_jumpSpeed; - } else if (m_verticalVelocity < -m_maxFallSpeed) { - m_verticalVelocity = -m_maxFallSpeed; + _verticalVelocity -= _gravity * dt; + if (_verticalVelocity > _jumpSpeed) { + _verticalVelocity = _jumpSpeed; + } else if (_verticalVelocity < -_maxFallSpeed) { + _verticalVelocity = -_maxFallSpeed; } - m_verticalOffset = m_verticalVelocity * dt; + _verticalOffset = _verticalVelocity * dt; btTransform xform; - xform = m_ghostObject->getWorldTransform(); + xform = _ghostObject->getWorldTransform(); // the algorithm is as follows: // (1) step the character up a little bit so that its forward step doesn't hit the floor @@ -632,33 +624,33 @@ void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScala // (3) step the character down looking for new ledges, the original floor, or a floor one step below where we started stepUp(collisionWorld); - if (m_useWalkDirection) { - stepForward(collisionWorld, m_walkDirection); + if (_useWalkDirection) { + stepForward(collisionWorld, _walkDirection); } else { // compute substep and decrement total interval - btScalar dtMoving = (dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval; - m_velocityTimeInterval -= dt; + btScalar dtMoving = (dt < _velocityTimeInterval) ? dt : _velocityTimeInterval; + _velocityTimeInterval -= dt; // stepForward substep - btVector3 move = m_walkDirection * dtMoving; + btVector3 move = _walkDirection * dtMoving; stepForward(collisionWorld, move); } stepDown(collisionWorld, dt); - xform.setOrigin(m_currentPosition); - m_ghostObject->setWorldTransform(xform); + xform.setOrigin(_currentPosition); + _ghostObject->setWorldTransform(xform); } void CharacterController::setMaxFallSpeed(btScalar speed) { - m_maxFallSpeed = speed; + _maxFallSpeed = speed; } void CharacterController::setJumpSpeed(btScalar jumpSpeed) { - m_jumpSpeed = jumpSpeed; + _jumpSpeed = jumpSpeed; } void CharacterController::setMaxJumpHeight(btScalar maxJumpHeight) { - m_maxJumpHeight = maxJumpHeight; + _maxJumpHeight = maxJumpHeight; } bool CharacterController::canJump() const { @@ -670,39 +662,39 @@ void CharacterController::jump() { return; } - m_verticalVelocity = m_jumpSpeed; - m_wasJumping = true; + _verticalVelocity = _jumpSpeed; + _wasJumping = true; #if 0 currently no jumping. btTransform xform; - m_rigidBody->getMotionState()->getWorldTransform(xform); + _rigidBody->getMotionState()->getWorldTransform(xform); btVector3 up = xform.getBasis()[1]; up.normalize(); - btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0); - m_rigidBody->applyCentralImpulse (up * magnitude); + btScalar magnitude = (btScalar(1.0)/_rigidBody->getInvMass()) * btScalar(8.0); + _rigidBody->applyCentralImpulse (up * magnitude); #endif } void CharacterController::setGravity(btScalar gravity) { - m_gravity = gravity; + _gravity = gravity; } btScalar CharacterController::getGravity() const { - return m_gravity; + return _gravity; } void CharacterController::setMaxSlope(btScalar slopeRadians) { - m_maxSlopeRadians = slopeRadians; - m_maxSlopeCosine = btCos(slopeRadians); + _maxSlopeRadians = slopeRadians; + _maxSlopeCosine = btCos(slopeRadians); } btScalar CharacterController::getMaxSlope() const { - return m_maxSlopeRadians; + return _maxSlopeRadians; } bool CharacterController::onGround() const { - return m_enabled && m_verticalVelocity == 0.0 && m_verticalOffset == 0.0; + return _enabled && _verticalVelocity == 0.0 && _verticalOffset == 0.0; } btVector3* CharacterController::getUpAxisDirections() { @@ -715,48 +707,50 @@ void CharacterController::debugDraw(btIDebugDraw* debugDrawer) { } void CharacterController::setUpInterpolate(bool value) { - m_interpolateUp = value; + // This method is required by btCharacterControllerInterface, but it does nothing. + // What it used to do was determine whether stepUp() would: stop where it hit the ceiling + // (interpolate = true, and now default behavior) or happily penetrate objects above the avatar. } // protected void CharacterController::createShapeAndGhost() { // get new dimensions from avatar - m_avatarData->lockForRead(); - AABox box = m_avatarData->getLocalAABox(); + _avatarData->lockForRead(); + AABox box = _avatarData->getLocalAABox(); // create new ghost - m_ghostObject = new btPairCachingGhostObject(); - m_ghostObject->setWorldTransform(btTransform(glmToBullet(m_avatarData->getOrientation()), - glmToBullet(m_avatarData->getPosition()))); - m_avatarData->unlock(); + _ghostObject = new btPairCachingGhostObject(); + _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), + glmToBullet(_avatarData->getPosition()))); + _avatarData->unlock(); const glm::vec3& diagonal = box.getScale(); - m_radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); - m_halfHeight = 0.5f * diagonal.y - m_radius; + _radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); + _halfHeight = 0.5f * diagonal.y - _radius; float MIN_HALF_HEIGHT = 0.1f; - if (m_halfHeight < MIN_HALF_HEIGHT) { - m_halfHeight = MIN_HALF_HEIGHT; + if (_halfHeight < MIN_HALF_HEIGHT) { + _halfHeight = MIN_HALF_HEIGHT; } glm::vec3 offset = box.getCorner() + 0.5f * diagonal; - m_shapeLocalOffset = offset; + _shapeLocalOffset = offset; // stepHeight affects the heights of ledges that the character can ascend - // however the actual ledge height is some function of m_stepHeight + // however the actual ledge height is some function of _stepHeight // due to character shape and this CharacterController algorithm - // (the function is approximately 2*m_stepHeight) - m_stepHeight = 0.1f * (m_radius + m_halfHeight) + 0.1f; + // (the function is approximately 2*_stepHeight) + _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; // create new shape - m_convexShape = new btCapsuleShape(m_radius, 2.0f * m_halfHeight); - m_ghostObject->setCollisionShape(m_convexShape); - m_ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); + _ghostObject->setCollisionShape(_convexShape); + _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); } bool CharacterController::needsShapeUpdate() { // get new dimensions from avatar - m_avatarData->lockForRead(); - AABox box = m_avatarData->getLocalAABox(); - m_avatarData->unlock(); + _avatarData->lockForRead(); + AABox box = _avatarData->getLocalAABox(); + _avatarData->unlock(); const glm::vec3& diagonal = box.getScale(); float radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); @@ -768,14 +762,14 @@ bool CharacterController::needsShapeUpdate() { glm::vec3 offset = box.getCorner() + 0.5f * diagonal; // compare dimensions (and offset) - float radiusDelta = glm::abs(radius - m_radius); - float heightDelta = glm::abs(halfHeight - m_halfHeight); + float radiusDelta = glm::abs(radius - _radius); + float heightDelta = glm::abs(halfHeight - _halfHeight); if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) { // shape hasn't changed --> nothing to do - float offsetDelta = glm::distance(offset, m_shapeLocalOffset); + float offsetDelta = glm::distance(offset, _shapeLocalOffset); if (offsetDelta > FLT_EPSILON) { // if only the offset changes then we can update it --> no need to rebuild shape - m_shapeLocalOffset = offset; + _shapeLocalOffset = offset; } return false; } @@ -787,29 +781,29 @@ void CharacterController::updateShape() { // the PhysicsEngine before calling this. // delete shape and GhostObject - delete m_ghostObject; - m_ghostObject = NULL; - delete m_convexShape; - m_convexShape = NULL; + delete _ghostObject; + _ghostObject = NULL; + delete _convexShape; + _convexShape = NULL; createShapeAndGhost(); } void CharacterController::preSimulation(btScalar timeStep) { - bool wasEnabled = m_enabled; + bool wasEnabled = _enabled; // lock avatarData, get everything we need from it ASAP, then unlock - m_avatarData->lockForRead(); - m_enabled = m_avatarData->isPhysicsEnabled(); - glm::quat rotation = m_avatarData->getOrientation(); - glm::vec3 position = m_avatarData->getPosition() + rotation * m_shapeLocalOffset; + _avatarData->lockForRead(); + _enabled = _avatarData->isPhysicsEnabled(); + glm::quat rotation = _avatarData->getOrientation(); + glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset; // TODO: Andrew to implement: harvest jump event here - btVector3 walkVelocity = glmToBullet(m_avatarData->getVelocity()); + btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity()); - m_avatarData->unlock(); + _avatarData->unlock(); - if (wasEnabled != m_enabled) { - if (m_enabled) { + if (wasEnabled != _enabled) { + if (_enabled) { // TODO: Andrew to implement: add collision shape back into world } else { // TODO: Andrew to implement: remove collision shape from world, @@ -817,21 +811,21 @@ void CharacterController::preSimulation(btScalar timeStep) { } } - if (m_enabled) { - m_ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); + if (_enabled) { + _ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); setVelocityForTimeInterval(walkVelocity, timeStep); } } void CharacterController::postSimulation() { - if (m_enabled) { - m_avatarData->lockForWrite(); - const btTransform& avatarTransform = m_ghostObject->getWorldTransform(); + if (_enabled) { + _avatarData->lockForWrite(); + const btTransform& avatarTransform = _ghostObject->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); - glm::vec3 offset = rotation * m_shapeLocalOffset; - m_avatarData->setOrientation(rotation); - m_avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); - m_avatarData->unlock(); + glm::vec3 offset = rotation * _shapeLocalOffset; + _avatarData->setOrientation(rotation); + _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); + _avatarData->unlock(); } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index b84662a389..23c338412c 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -41,53 +41,50 @@ ATTRIBUTE_ALIGNED16(class) CharacterController : public btCharacterControllerInt { protected: - AvatarData* m_avatarData = NULL; - btPairCachingGhostObject* m_ghostObject; - glm::vec3 m_shapeLocalOffset; + AvatarData* _avatarData = NULL; + btPairCachingGhostObject* _ghostObject; + glm::vec3 _shapeLocalOffset; - btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast - btScalar m_radius; - btScalar m_halfHeight; + btConvexShape* _convexShape;//is also in _ghostObject, but it needs to be convex, so we store it here to avoid upcast + btScalar _radius; + btScalar _halfHeight; - btScalar m_verticalVelocity; - btScalar m_verticalOffset; // fall distance from velocity this frame - btScalar m_maxFallSpeed; - btScalar m_jumpSpeed; - btScalar m_maxJumpHeight; - btScalar m_maxSlopeRadians; // Slope angle that is set (used for returning the exact value) - btScalar m_maxSlopeCosine; // Cosine equivalent of m_maxSlopeRadians (calculated once when set, for optimization) - btScalar m_gravity; + btScalar _verticalVelocity; + btScalar _verticalOffset; // fall distance from velocity this frame + btScalar _maxFallSpeed; + btScalar _jumpSpeed; + btScalar _maxJumpHeight; + btScalar _maxSlopeRadians; // Slope angle that is set (used for returning the exact value) + btScalar _maxSlopeCosine; // Cosine equivalent of _maxSlopeRadians (calculated once when set, for optimization) + btScalar _gravity; - btScalar m_stepHeight; // height of stepUp prior to stepForward + btScalar _stepHeight; // height of stepUp prior to stepForward - btScalar m_addedMargin;//@todo: remove this and fix the code + btScalar _addedMargin;//@todo: remove this and fix the code ///this is the desired walk direction, set by the user - btVector3 m_walkDirection; - btVector3 m_normalizedDirection; + btVector3 _walkDirection; + btVector3 _normalizedDirection; //some internal variables - btVector3 m_currentPosition; - btVector3 m_targetPosition; - btScalar m_lastStepUp; + btVector3 _currentPosition; + btVector3 _targetPosition; + btScalar _lastStepUp; ///keep track of the contact manifolds - btManifoldArray m_manifoldArray; + btManifoldArray _manifoldArray; - bool m_touchingContact; - btVector3 m_floorNormal; // points from object to character + bool _touchingContact; + btVector3 _floorNormal; // points from object to character - bool m_enabled; - bool m_wasOnGround; - bool m_wasJumping; - bool m_useWalkDirection; - btScalar m_velocityTimeInterval; - int m_upAxis; + bool _enabled; + bool _wasOnGround; + bool _wasJumping; + bool _useWalkDirection; + btScalar _velocityTimeInterval; + int _upAxis; static btVector3* getUpAxisDirections(); - bool m_interpolateUp; - bool full_drop; - bool bounce_fix; btVector3 computeReflectionDirection(const btVector3& direction, const btVector3& normal); btVector3 parallelComponent(const btVector3& direction, const btVector3& normal); @@ -121,7 +118,7 @@ public: axis = 0; if (axis > 2) axis = 2; - m_upAxis = axis; + _upAxis = axis; } /// This should probably be called setPositionIncrementPerSimulatorStep. From 34ab47062420f0cad7a4aa8b293fc0d6c19eab07 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Fri, 20 Mar 2015 21:21:18 +0100 Subject: [PATCH 036/177] lightController first draft --- examples/entityScripts/lightController.js | 119 ++++++++++++++++++++++ 1 file changed, 119 insertions(+) create mode 100644 examples/entityScripts/lightController.js diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js new file mode 100644 index 0000000000..50e32e30f3 --- /dev/null +++ b/examples/entityScripts/lightController.js @@ -0,0 +1,119 @@ +(function() { + this.entityID = null; + this.lightID = null; + this.sound = null; + + function checkEntity(entityID) { + return entityID && Entities.identifyEntity(entityID).isKnownID; + } + function getUserData(entityID) { + var properties = Entities.getEntityProperties(entityID); + if (properties.userData) { + return JSON.parse(properties.userData); + } + print("Warning: light controller has no user data."); + // TODO: Remove before merge + this.DO_NOT_MERGE(); + return getUserData(entityID); + //////////////////////////// + return null; + } + // Download sound if needed + this.maybeDownloadSound = function() { + if (this.sound === null) { + this.sound = SoundCache.getSound("http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav"); + } + } + // Play switch sound + this.playSound = function() { + if (this.sound && this.sound.downloaded) { + Audio.playSound(this.sound, { position: Entities.getEntityProperties(this.entityID).position }); + } else { + print("Warning: Couldn't play sound."); + } + } + // Toggles the associated light entity + this.toggleLight = function() { + if (this.lightID) { + var lightProperties = Entities.getEntityProperties(this.lightID); + Entities.editEntity(this.lightID, { visible: !lightProperties.visible }); + } else { + print("Warning: No light to turn on/off"); + } + } + + this.createLight = function() { + var lightProperties = getUserData(this.entityID).lightDefaultProperties; + if (lightProperties) { + var properties = Entities.getEntityProperties(this.entityID); + + lightProperties.rotation = Quat.multiply(properties.rotation, lightProperties.rotation); + lightProperties.position = Vec3.sum(properties.position, + Vec3.multiplyQbyV(properties.rotation, lightProperties.position)); + print("Created light"); + return Entities.addEntity(lightProperties); + } else { + print("Warning: light controller has no default light."); + return null; + } + } + + this.updateLight = function() { + // Find valid light + if (!checkEntity(this.lightID)) { + var userData = getUserData(this.entityID); + if (userData.lightID && checkEntity(userData.lightID)) { + this.lightID = userData.lightID; + } else { + this.lightID = null; + } + } + + // No valid light, create one + if (!this.lightID) { + this.lightID = this.createLight(); + } + } + + this.preload = function(entityID) { + this.entityID = entityID; + this.maybeDownloadSound(); + }; + + this.clickReleaseOnEntity = function(entityID, mouseEvent) { + if (mouseEvent.isLeftButton) { + this.updateLight(); + this.toggleLight(); + this.playSound(); + } else if (mouseEvent.isRightButton) { + print("Right button"); + } + }; + + this.DO_NOT_MERGE = function() { + var userData = { + lightID: null, + lightDefaultProperties: { + type: "Light", + position: { x: 0, y: 0.5, z: 0 }, + dimensions: { x: 2, y: 2, z: 2 }, + angularVelocity: { x: 0, y: 0, z: 0 }, + angularDamping: 0, + + isSpotlight: true, + color: { red: 255, green: 0, blue: 0 }, + diffuseColor: { red: 255, green: 0, blue: 0 }, + ambientColor: { red: 0, green: 0, blue: 255 }, + specularColor: { red: 0, green: 255, blue: 0 }, + + intensity: 10, + constantAttenuation: 0, + linearAttenuation: 1, + quadraticAttenuation: 0, + exponent: 0, + cutoff: 180, // in degrees + } + }; + Entities.editEntity(this.entityID, { userData: JSON.stringify(userData) }); + } +}) \ No newline at end of file From 81bf7138a42337077e49372e4643d0a910dc29d5 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Fri, 20 Mar 2015 13:21:29 -0700 Subject: [PATCH 037/177] also attempt to clean up placement of PROP_ATTRIBUTION in the stream --- libraries/entities/src/EntityItem.cpp | 20 +++++++++++++++---- libraries/entities/src/EntityItemProperties.h | 2 +- libraries/entities/src/ModelEntityItem.cpp | 6 +++--- libraries/networking/src/PacketHeaders.h | 3 ++- 4 files changed, 22 insertions(+), 9 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 1b3b3d877b..d54e7e6cc1 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -240,6 +240,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, getUserData()); + APPEND_ENTITY_PROPERTY(PROP_ATTRIBUTION, appendValue, getAttribution()); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -247,8 +248,6 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet propertiesDidntFit, propertyCount, appendState); - - APPEND_ENTITY_PROPERTY(PROP_ATTRIBUTION, appendValue, getAttribution()); } if (propertyCount > 0) { @@ -556,9 +555,22 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked); READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA, setUserData); + if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_ATTRIBUTION) { + READ_ENTITY_PROPERTY_STRING(PROP_ATTRIBUTION, setAttribution); + } + bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); - - READ_ENTITY_PROPERTY_STRING(PROP_ATTRIBUTION, setAttribution); + + //////////////////////////////////// + // WARNING: Do not add stream content here after the subclass. Always add it before the subclass + // + // NOTE: we had a bad version of the stream that we added stream data after the subclass. We can attempt to recover + // by doing this parsing here... but it's not likely going to fully recover the content. + // + // TODO: Remove this conde once we've sufficiently migrated content past this damaged version + if (args.bitstreamVersion == VERSION_ENTITIES_HAS_ATTRIBUTION_DAMAGED) { + READ_ENTITY_PROPERTY_STRING(PROP_ATTRIBUTION, setAttribution); + } if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) { // NOTE: This code is attempting to "repair" the old data we just got from the server to make it more diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index d821c82e89..39e290e602 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -111,7 +111,7 @@ enum EntityPropertyList { PROP_TEXT = PROP_MODEL_URL, PROP_LINE_HEIGHT = PROP_ANIMATION_URL, PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS, - PROP_COLLISION_MODEL_URL_OLD_VERSION + PROP_COLLISION_MODEL_URL_OLD_VERSION = PROP_ANIMATION_FPS + 1 // WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above }; diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index a2364f9e17..181f537daa 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -93,18 +93,18 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesRead = 0; const unsigned char* dataAt = data; - + READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color); READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL); if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) { setCollisionModelURL(""); - } else if (args.bitstreamVersion < VERSION_ENTITIES_HAS_ATTRIBUTION) { + } else if (args.bitstreamVersion == VERSION_ENTITIES_HAS_COLLISION_MODEL) { READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL_OLD_VERSION, setCollisionModelURL); } else { READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL, setCollisionModelURL); } READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL); - + // Because we're using AnimationLoop which will reset the frame index if you change it's running state // we want to read these values in the order they appear in the buffer, but call our setters in an // order that allows AnimationLoop to preserve the correct frame rate. diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 81195d13d4..5822f2af3a 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -132,7 +132,8 @@ const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10; const PacketVersion VERSION_ENTITIES_USE_METERS_AND_RADIANS = 11; const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 12; -const PacketVersion VERSION_ENTITIES_HAS_ATTRIBUTION = 13; +const PacketVersion VERSION_ENTITIES_HAS_ATTRIBUTION_DAMAGED = 13; +const PacketVersion VERSION_ENTITIES_HAS_ATTRIBUTION = 14; const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; #endif // hifi_PacketHeaders_h From 07bcd115c210ba58d33db8615fb4db7b3009558b Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Fri, 20 Mar 2015 13:28:42 -0700 Subject: [PATCH 038/177] trying to remove useless glsl code for Legacy path --- libraries/gpu/src/gpu/Transform.slh | 12 ++++++------ .../render-utils/src/DeferredLightingEffect.cpp | 10 ++++++---- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 9019ec928c..042964f0f7 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -40,11 +40,11 @@ TransformCamera getTransformCamera() { } <@else@> -uniform vec4 transformObjectBuffer[8]; +//uniform vec4 transformObjectBuffer[8]; TransformObject getTransformObject() { TransformObject object; - object._model[0] = transformObjectBuffer[0]; + /* object._model[0] = transformObjectBuffer[0]; object._model[1] = transformObjectBuffer[1]; object._model[2] = transformObjectBuffer[2]; object._model[3] = transformObjectBuffer[3]; @@ -53,14 +53,14 @@ TransformObject getTransformObject() { object._modelInverse[1] = transformObjectBuffer[5]; object._modelInverse[2] = transformObjectBuffer[6]; object._modelInverse[3] = transformObjectBuffer[7]; - +*/ return object; } -uniform vec4 transformCameraBuffer[17]; +//uniform vec4 transformCameraBuffer[17]; TransformCamera getTransformCamera() { TransformCamera camera; - camera._view[0] = transformCameraBuffer[0]; +/* camera._view[0] = transformCameraBuffer[0]; camera._view[1] = transformCameraBuffer[1]; camera._view[2] = transformCameraBuffer[2]; camera._view[3] = transformCameraBuffer[3]; @@ -81,7 +81,7 @@ TransformCamera getTransformCamera() { camera._projection[3] = transformCameraBuffer[15]; camera._viewport = transformCameraBuffer[16]; - +*/ return camera; } diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 5b1ad44c69..13bf947d71 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -496,10 +496,11 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit GLint loc = -1; #if (GPU_FEATURE_PROFILE == GPU_CORE) + const GLint LIGHT_GPU_SLOT = 3; loc = glGetUniformBlockIndex(program.programId(), "lightBuffer"); if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, 3); - locations.lightBufferUnit = 3; + glUniformBlockBinding(program.programId(), loc, LIGHT_GPU_SLOT); + locations.lightBufferUnit = LIGHT_GPU_SLOT; } else { locations.lightBufferUnit = -1; } @@ -513,10 +514,11 @@ void DeferredLightingEffect::loadLightProgram(const char* fragSource, bool limit #endif #if (GPU_FEATURE_PROFILE == GPU_CORE) + const GLint ATMOSPHERE_GPU_SLOT = 4; loc = glGetUniformBlockIndex(program.programId(), "atmosphereBufferUnit"); if (loc >= 0) { - glUniformBlockBinding(program.programId(), loc, 4); - locations.atmosphereBufferUnit = 4; + glUniformBlockBinding(program.programId(), loc, ATMOSPHERE_GPU_SLOT); + locations.atmosphereBufferUnit = ATMOSPHERE_GPU_SLOT; } else { locations.atmosphereBufferUnit = -1; } From 769194f046fd35d00070782b1ab911e4ea2bfaa3 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Fri, 20 Mar 2015 13:41:14 -0700 Subject: [PATCH 039/177] first stab at compound hull collisions --- .../src/RenderableModelEntityItem.cpp | 9 ++++--- .../src/RenderableModelEntityItem.h | 2 +- libraries/physics/src/ShapeInfoUtil.cpp | 24 +++++++++++++++---- libraries/shared/src/ShapeInfo.cpp | 2 +- libraries/shared/src/ShapeInfo.h | 8 +++---- 5 files changed, 31 insertions(+), 14 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index d4eefc0986..6d32b78689 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -295,12 +295,13 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { const FBXGeometry& fbxGeometry = collisionNetworkGeometry->getFBXGeometry(); _points.clear(); + unsigned int i = 0; foreach (const FBXMesh& mesh, fbxGeometry.meshes) { - _points << mesh.vertices; + _points[i++] << mesh.vertices; } info.setParams(getShapeType(), 0.5f * getDimensions(), _collisionModelURL); - info.setConvexHull(_points); + info.setConvexHulls(_points); } } @@ -308,7 +309,9 @@ ShapeType RenderableModelEntityItem::getShapeType() const { // XXX make hull an option in edit.js ? if (!_model || _model->getCollisionURL().isEmpty()) { return _shapeType; - } else { + } else if (_points.size() == 1) { return SHAPE_TYPE_CONVEX_HULL; + } else { + return SHAPE_TYPE_COMPOUND; } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index f02dd537fb..63249f136c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -66,7 +66,7 @@ private: QString _currentTextures; QStringList _originalTextures; bool _originalTexturesRead; - QVector<glm::vec3> _points; + QVector<QVector<glm::vec3>> _points; }; #endif // hifi_RenderableModelEntityItem_h diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp index 116be984b9..2f7c0c59bd 100644 --- a/libraries/physics/src/ShapeInfoUtil.cpp +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -70,12 +70,12 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf const btConvexHullShape* convexHullShape = static_cast<const btConvexHullShape*>(shape); const int numPoints = convexHullShape->getNumPoints(); const btVector3* btPoints = convexHullShape->getUnscaledPoints(); - QVector<glm::vec3> points; + QVector<QVector<glm::vec3>> points; for (int i = 0; i < numPoints; i++) { glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ()); - points << point; + points[0] << point; } - info.setConvexHull(points); + info.setConvexHulls(points); } break; default: { @@ -109,13 +109,27 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { break; case SHAPE_TYPE_CONVEX_HULL: { shape = new btConvexHullShape(); - const QVector<glm::vec3>& points = info.getPoints(); - foreach (glm::vec3 point, points) { + const QVector<QVector<glm::vec3>>& points = info.getPoints(); + foreach (glm::vec3 point, points[0]) { btVector3 btPoint(point[0], point[1], point[2]); static_cast<btConvexHullShape*>(shape)->addPoint(btPoint); } } break; + case SHAPE_TYPE_COMPOUND: { + shape = new btCompoundShape(); + const QVector<QVector<glm::vec3>>& points = info.getPoints(); + foreach (QVector<glm::vec3> hullPoints, info.getPoints()) { + auto hull = new btConvexHullShape(); + foreach (glm::vec3 point, hullPoints) { + btVector3 btPoint(point[0], point[1], point[2]); + hull->addPoint(btPoint); + } + btTransform trans; + static_cast<btCompoundShape*>(shape)->addChildShape (trans, hull); + } + } + break; } return shape; } diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 61432830e7..afa19bcd24 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -64,7 +64,7 @@ void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) { _doubleHashKey.clear(); } -void ShapeInfo::setConvexHull(const QVector<glm::vec3>& points) { +void ShapeInfo::setConvexHulls(const QVector<QVector<glm::vec3>>& points) { _type = SHAPE_TYPE_CONVEX_HULL; _points = points; } diff --git a/libraries/shared/src/ShapeInfo.h b/libraries/shared/src/ShapeInfo.h index 0a55f7c51d..4dce121d64 100644 --- a/libraries/shared/src/ShapeInfo.h +++ b/libraries/shared/src/ShapeInfo.h @@ -44,14 +44,14 @@ public: void setBox(const glm::vec3& halfExtents); void setSphere(float radius); void setEllipsoid(const glm::vec3& halfExtents); - void setConvexHull(const QVector<glm::vec3>& points); + void setConvexHulls(const QVector<QVector<glm::vec3>>& points); void setCapsuleY(float radius, float halfHeight); const int getType() const { return _type; } const glm::vec3& getHalfExtents() const { return _halfExtents; } - const QVector<glm::vec3>& getPoints() const { return _points; } + const QVector<QVector<glm::vec3>>& getPoints() const { return _points; } void clearPoints () { _points.clear(); } void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; } @@ -64,8 +64,8 @@ protected: ShapeType _type = SHAPE_TYPE_NONE; glm::vec3 _halfExtents = glm::vec3(0.0f); DoubleHashKey _doubleHashKey; - QVector<glm::vec3> _points; // points for convex collision hull - QUrl _url; // url for model of convex collision hull + QVector<QVector<glm::vec3>> _points; // points for convex collision hulls + QUrl _url; // url for model of convex collision hulls }; #endif // hifi_ShapeInfo_h From 49f5de2b944a59556beb53abede24fb8caa49b5c Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Fri, 20 Mar 2015 16:39:38 -0700 Subject: [PATCH 040/177] make character's "up" axis depend on orientation --- libraries/physics/src/CharacterController.cpp | 40 +++++++++---------- libraries/physics/src/CharacterController.h | 12 +----- 2 files changed, 20 insertions(+), 32 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index f7f8ab4d53..d0b083fc01 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -216,6 +216,8 @@ btVector3 CharacterController::perpindicularComponent(const btVector3& direction return direction - parallelComponent(direction, normal); } +const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f); + CharacterController::CharacterController(AvatarData* avatarData) { assert(avatarData); _avatarData = avatarData; @@ -227,8 +229,6 @@ CharacterController::CharacterController(AvatarData* avatarData) { createShapeAndGhost(); - _upAxis = 1; // HACK: hard coded to be 1 for now (yAxis) - _addedMargin = 0.02f; _walkDirection.setValue(0.0f,0.0f,0.0f); _useWalkDirection = true; // use walk direction by default, legacy behavior @@ -272,7 +272,7 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl collisionWorld->getDispatcher()->dispatchAllCollisionPairs(_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher()); _currentPosition = _ghostObject->getWorldTransform().getOrigin(); - btVector3 up = getUpAxisDirections()[_upAxis]; + btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); btVector3 currentPosition = _currentPosition; @@ -355,14 +355,15 @@ void CharacterController::stepUp( btCollisionWorld* world) { // compute start and end btTransform start, end; start.setIdentity(); - start.setOrigin(_currentPosition + getUpAxisDirections()[_upAxis] * (_convexShape->getMargin() + _addedMargin)); + btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); + start.setOrigin(_currentPosition + up * (_convexShape->getMargin() + _addedMargin)); - _targetPosition = _currentPosition + getUpAxisDirections()[_upAxis] * _stepHeight; + _targetPosition = _currentPosition + up * _stepHeight; end.setIdentity(); end.setOrigin(_targetPosition); // sweep up - btVector3 sweepDirNegative = -getUpAxisDirections()[_upAxis]; + btVector3 sweepDirNegative = - up; btKinematicClosestNotMeConvexResultCallback callback(_ghostObject, sweepDirNegative, btScalar(0.7071)); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; @@ -370,11 +371,11 @@ void CharacterController::stepUp( btCollisionWorld* world) { if (callback.hasHit()) { // we hit something, so zero our vertical velocity - _verticalVelocity = 0.0; - _verticalOffset = 0.0; + _verticalVelocity = 0.0f; + _verticalOffset = 0.0f; // Only modify the position if the hit was a slope and not a wall or ceiling. - if (callback.m_hitNormalWorld.dot(getUpAxisDirections()[_upAxis]) > 0.0) { + if (callback.m_hitNormalWorld.dot(up) > 0.0f) { _lastStepUp = _stepHeight * callback.m_closestHitFraction; _currentPosition.setInterpolate3(_currentPosition, _targetPosition, callback.m_closestHitFraction); } else { @@ -484,10 +485,11 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d } // first sweep for ledge - btVector3 step = getUpAxisDirections()[_upAxis] * (-(_lastStepUp + downSpeed * dt)); + btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); + btVector3 step = up * (-(_lastStepUp + downSpeed * dt)); StepDownConvexResultCallback callback(_ghostObject, - getUpAxisDirections()[_upAxis], + up, _currentPosition, step, _walkDirection, _maxSlopeCosine, @@ -512,7 +514,7 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d } else { // sweep again for floor within downStep threshold StepDownConvexResultCallback callback2 (_ghostObject, - getUpAxisDirections()[_upAxis], + up, _currentPosition, step, _walkDirection, _maxSlopeCosine, @@ -523,7 +525,7 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d _currentPosition = _targetPosition; btVector3 oldPosition = _currentPosition; - step = (- _stepHeight) * getUpAxisDirections()[_upAxis]; + step = (- _stepHeight) * up; _targetPosition = _currentPosition + step; start.setOrigin(_currentPosition); @@ -537,7 +539,7 @@ void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar d _wasJumping = false; } else { // nothing to step down on, so remove the stepUp effect - _currentPosition = oldPosition - _lastStepUp * getUpAxisDirections()[_upAxis]; + _currentPosition = oldPosition - _lastStepUp * up; _lastStepUp = 0.0f; } } @@ -595,7 +597,9 @@ void CharacterController::preStep( btCollisionWorld* collisionWorld) { } } - _currentPosition = _ghostObject->getWorldTransform().getOrigin(); + const btTransform& transform = _ghostObject->getWorldTransform(); + _currentRotation = transform.getRotation(); + _currentPosition = transform.getOrigin(); _targetPosition = _currentPosition; } @@ -697,12 +701,6 @@ bool CharacterController::onGround() const { return _enabled && _verticalVelocity == 0.0 && _verticalOffset == 0.0; } -btVector3* CharacterController::getUpAxisDirections() { - static btVector3 sUpAxisDirection[3] = { btVector3(1.0f, 0.0f, 0.0f), btVector3(0.0f, 1.0f, 0.0f), btVector3(0.0f, 0.0f, 1.0f) }; - - return sUpAxisDirection; -} - void CharacterController::debugDraw(btIDebugDraw* debugDrawer) { } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 23c338412c..b6109eb0ff 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -68,6 +68,7 @@ protected: //some internal variables btVector3 _currentPosition; + btQuaternion _currentRotation; btVector3 _targetPosition; btScalar _lastStepUp; @@ -82,9 +83,6 @@ protected: bool _wasJumping; bool _useWalkDirection; btScalar _velocityTimeInterval; - int _upAxis; - - static btVector3* getUpAxisDirections(); btVector3 computeReflectionDirection(const btVector3& direction, const btVector3& normal); btVector3 parallelComponent(const btVector3& direction, const btVector3& normal); @@ -113,14 +111,6 @@ public: ///btActionInterface interface void debugDraw(btIDebugDraw* debugDrawer); - void setUpAxis(int axis) { - if (axis < 0) - axis = 0; - if (axis > 2) - axis = 2; - _upAxis = axis; - } - /// This should probably be called setPositionIncrementPerSimulatorStep. /// This is neither a direction nor a velocity, but the amount to /// increment the position each simulation iteration, regardless From 86d09a1607a2fee57fee73c2a01026be71560620 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 21 Mar 2015 08:55:49 -0700 Subject: [PATCH 041/177] more compound shape stuff --- .../src/RenderableModelEntityItem.cpp | 2 ++ libraries/physics/src/ShapeInfoUtil.cpp | 26 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 6d32b78689..fed01883bd 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -297,6 +297,8 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { _points.clear(); unsigned int i = 0; foreach (const FBXMesh& mesh, fbxGeometry.meshes) { + QVector<glm::vec3> newMeshPoints; + _points << newMeshPoints; _points[i++] << mesh.vertices; } diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp index 2f7c0c59bd..a5834f407a 100644 --- a/libraries/physics/src/ShapeInfoUtil.cpp +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -29,6 +29,9 @@ int ShapeInfoUtil::toBulletShapeType(int shapeInfoType) { case SHAPE_TYPE_CONVEX_HULL: bulletShapeType = CONVEX_HULL_SHAPE_PROXYTYPE; break; + case SHAPE_TYPE_COMPOUND: + bulletShapeType = COMPOUND_SHAPE_PROXYTYPE; + break; } return bulletShapeType; } @@ -48,6 +51,9 @@ int ShapeInfoUtil::fromBulletShapeType(int bulletShapeType) { case CONVEX_HULL_SHAPE_PROXYTYPE: shapeInfoType = SHAPE_TYPE_CONVEX_HULL; break; + case COMPOUND_SHAPE_PROXYTYPE: + shapeInfoType = SHAPE_TYPE_COMPOUND; + break; } return shapeInfoType; } @@ -78,6 +84,26 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf info.setConvexHulls(points); } break; + case SHAPE_TYPE_COMPOUND: { + const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shape); + const int numChildShapes = compoundShape->getNumChildShapes(); + QVector<QVector<glm::vec3>> points; + for (int i = 0; i < numChildShapes; i ++) { + const btCollisionShape* childShape = compoundShape->getChildShape(i); + const btConvexHullShape* convexHullShape = static_cast<const btConvexHullShape*>(childShape); + const int numPoints = convexHullShape->getNumPoints(); + const btVector3* btPoints = convexHullShape->getUnscaledPoints(); + + QVector<glm::vec3> childPoints; + for (int j = 0; j < numPoints; j++) { + glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ()); + childPoints << point; + } + points << childPoints; + } + info.setConvexHulls(points); + } + break; default: { info.clear(); } From 7dbe92f56fb516486f9bfda20814bd495d0d0d50 Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Sat, 21 Mar 2015 14:22:09 -0700 Subject: [PATCH 042/177] Building with Sixense build requires four of the SDK libraries --- interface/external/sixense/readme.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/external/sixense/readme.txt b/interface/external/sixense/readme.txt index 29d1bbc2f9..a4790caa5e 100644 --- a/interface/external/sixense/readme.txt +++ b/interface/external/sixense/readme.txt @@ -2,7 +2,7 @@ Instructions for adding the Sixense driver to Interface Andrzej Kapolka, November 18, 2013 -1. Copy the Sixense sdk folders (lib, include) into the interface/external/Sixense folder. This readme.txt should be there as well. +1. Copy the Sixense sdk folders (bin, include, lib, and samples) into the interface/external/Sixense folder. This readme.txt should be there as well. You may optionally choose to copy the SDK folders to a location outside the repository (so you can re-use with different checkouts and different projects). If so our CMake find module expects you to set the ENV variable 'HIFI_LIB_DIR' to a directory containing a subfolder 'sixense' that contains the folders mentioned above. From bfc5cf99d6ef92de7ee6734394483fa90a416b95 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 21 Mar 2015 16:11:47 -0700 Subject: [PATCH 043/177] more code for compound hull collisions --- .../src/RenderableModelEntityItem.cpp | 31 +++++++++++++++++-- libraries/physics/src/ShapeInfoUtil.cpp | 12 +++++++ libraries/shared/src/ShapeInfo.cpp | 10 +++++- 3 files changed, 49 insertions(+), 4 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index fed01883bd..86332c8c07 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -297,9 +297,34 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { _points.clear(); unsigned int i = 0; foreach (const FBXMesh& mesh, fbxGeometry.meshes) { - QVector<glm::vec3> newMeshPoints; - _points << newMeshPoints; - _points[i++] << mesh.vertices; + + foreach (const FBXMeshPart &meshPart, mesh.parts) { + QVector<glm::vec3> pointsInPart; + unsigned int triangleCount = meshPart.triangleIndices.size() / 3; + for (unsigned int i = 0; i < triangleCount; i++) { + unsigned int p0Index = meshPart.triangleIndices[i*3]; + unsigned int p1Index = meshPart.triangleIndices[i*3+1]; + unsigned int p2Index = meshPart.triangleIndices[i*3+2]; + + glm::vec3 p0 = mesh.vertices[p0Index]; + glm::vec3 p1 = mesh.vertices[p1Index]; + glm::vec3 p2 = mesh.vertices[p2Index]; + + if (!pointsInPart.contains(p0)) { + pointsInPart << p0; + } + if (!pointsInPart.contains(p1)) { + pointsInPart << p1; + } + if (!pointsInPart.contains(p2)) { + pointsInPart << p2; + } + } + + QVector<glm::vec3> newMeshPoints; + _points << newMeshPoints; + _points[i++] << pointsInPart; + } } info.setParams(getShapeType(), 0.5f * getDimensions(), _collisionModelURL); diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp index a5834f407a..b48bff763c 100644 --- a/libraries/physics/src/ShapeInfoUtil.cpp +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -116,6 +116,9 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; + + qDebug() << "\n\nHERE" << info.getType(); + switch(info.getType()) { case SHAPE_TYPE_BOX: { shape = new btBoxShape(glmToBullet(info.getHalfExtents())); @@ -145,8 +148,14 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { case SHAPE_TYPE_COMPOUND: { shape = new btCompoundShape(); const QVector<QVector<glm::vec3>>& points = info.getPoints(); + + qDebug() << "\n\nSHAPE_TYPE_COMPOUND" << info.getPoints().size() << "hulls."; + foreach (QVector<glm::vec3> hullPoints, info.getPoints()) { auto hull = new btConvexHullShape(); + + qDebug() << " SHAPE_TYPE_COMPOUND" << hullPoints.size() << "points in hull."; + foreach (glm::vec3 point, hullPoints) { btVector3 btPoint(point[0], point[1], point[2]); hull->addPoint(btPoint); @@ -155,6 +164,9 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { static_cast<btCompoundShape*>(shape)->addChildShape (trans, hull); } } + + qDebug() << "DONE, getNumChildShapes =" << static_cast<btCompoundShape*>(shape)->getNumChildShapes(); + break; } return shape; diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index afa19bcd24..09677cf36c 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -40,6 +40,10 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString _url = QUrl(url); _halfExtents = halfExtents; break; + case SHAPE_TYPE_COMPOUND: + _url = QUrl(url); + _halfExtents = halfExtents; + break; default: _halfExtents = halfExtents; break; @@ -65,7 +69,11 @@ void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) { } void ShapeInfo::setConvexHulls(const QVector<QVector<glm::vec3>>& points) { - _type = SHAPE_TYPE_CONVEX_HULL; + if (points.size() == 1) { + _type = SHAPE_TYPE_CONVEX_HULL; + } else { + _type = SHAPE_TYPE_COMPOUND; + } _points = points; } From 19c8e526e1fb630095f6ff4d0763b20ebacef784 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Mon, 23 Mar 2015 08:47:06 -0700 Subject: [PATCH 044/177] add guards to _jointStates array size --- interface/src/avatar/FaceModel.cpp | 2 +- libraries/render-utils/src/Model.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index c80772ef49..6dd97f067a 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -87,7 +87,7 @@ void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentSta void FaceModel::updateJointState(int index) { JointState& state = _jointStates[index]; const FBXJoint& joint = state.getFBXJoint(); - if (joint.parentIndex != -1) { + if (joint.parentIndex != -1 && joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) { const JointState& parentState = _jointStates.at(joint.parentIndex); const FBXGeometry& geometry = _geometry->getFBXGeometry(); if (index == geometry.neckJointIndex) { diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0e0f081ec8..f7a4257de7 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1306,8 +1306,10 @@ void Model::updateJointState(int index) { glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; state.computeTransform(parentTransform); } else { - const JointState& parentState = _jointStates.at(parentIndex); - state.computeTransform(parentState.getTransform(), parentState.getTransformChanged()); + if (joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) { + const JointState& parentState = _jointStates.at(parentIndex); + state.computeTransform(parentState.getTransform(), parentState.getTransformChanged()); + } } } From 6b4845abf3dea25ba982333c644e52610c6a3fc7 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Mon, 23 Mar 2015 16:47:24 +0100 Subject: [PATCH 045/177] Some improvements to lightController --- examples/entityScripts/lightController.js | 179 +++++++++++++++------- 1 file changed, 126 insertions(+), 53 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 50e32e30f3..76d0b33eb3 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -1,23 +1,31 @@ (function() { this.entityID = null; + this.properties = null; this.lightID = null; this.sound = null; - function checkEntity(entityID) { - return entityID && Entities.identifyEntity(entityID).isKnownID; + function copyObject(object) { + return JSON.parse(JSON.stringify(object)); + } + function didEntityExist(entityID) { + return entityID && entityID.isKnownID; + } + function doesEntityExistNow(entityID) { + return entityID && Entities.getEntityProperties(entityID).isKnownID; } function getUserData(entityID) { var properties = Entities.getEntityProperties(entityID); if (properties.userData) { return JSON.parse(properties.userData); + } else { + print("Warning: light controller has no user data."); + return null; } - print("Warning: light controller has no user data."); - // TODO: Remove before merge - this.DO_NOT_MERGE(); - return getUserData(entityID); - //////////////////////////// - return null; } + function updateUserData(entityID, userData) { + Entities.editEntity(entityID, { userData: JSON.stringify(userData) }); + } + // Download sound if needed this.maybeDownloadSound = function() { if (this.sound === null) { @@ -32,6 +40,7 @@ print("Warning: Couldn't play sound."); } } + // Toggles the associated light entity this.toggleLight = function() { if (this.lightID) { @@ -42,39 +51,126 @@ } } - this.createLight = function() { - var lightProperties = getUserData(this.entityID).lightDefaultProperties; + this.createLight = function(userData) { + var lightProperties = copyObject(userData.lightDefaultProperties); if (lightProperties) { - var properties = Entities.getEntityProperties(this.entityID); + var entityProperties = Entities.getEntityProperties(this.entityID); - lightProperties.rotation = Quat.multiply(properties.rotation, lightProperties.rotation); - lightProperties.position = Vec3.sum(properties.position, - Vec3.multiplyQbyV(properties.rotation, lightProperties.position)); - print("Created light"); - return Entities.addEntity(lightProperties); + lightProperties.visible = false; + lightProperties.position = Vec3.sum(entityProperties.position, + Vec3.multiplyQbyV(entityProperties.rotation, + lightProperties.position)); + + print(lightProperties); + print(JSON.stringify(lightProperties)); + var newLight = Entities.addEntity(lightProperties); + print(newLight); + print(JSON.stringify(newLight)); + return newLight; } else { print("Warning: light controller has no default light."); return null; } } - this.updateLight = function() { + this.updateLightID = function() { + var userData = getUserData(this.entityID); + if (!userData) { + userData = { + lightID: null, + lightDefaultProperties: { + type: "Light", + position: { x: 0, y: 0, z: 0 }, + dimensions: { x: 2, y: 2, z: 2 }, + isSpotlight: false, + color: { red: 255, green: 48, blue: 0 }, + diffuseColor: { red: 255, green: 255, blue: 255 }, + ambientColor: { red: 255, green: 255, blue: 255 }, + specularColor: { red: 0, green: 0, blue: 0 }, + constantAttenuation: 1, + linearAttenuation: 0, + quadraticAttenuation: 0, + intensity: 10, + exponent: 0, + cutoff: 180, // in degrees + } + }; + updateUserData(this.entityID, userData); + } + // Find valid light - if (!checkEntity(this.lightID)) { - var userData = getUserData(this.entityID); - if (userData.lightID && checkEntity(userData.lightID)) { - this.lightID = userData.lightID; - } else { - this.lightID = null; + if (doesEntityExistNow(this.lightID)) { + if (!didEntityExist(this.lightID)) { + // Light now has an ID, so update it in userData + this.lightID = Entities.identifyEntity(this.lightID); + userData.lightID = this.lightID.id; + updateUserData(this.entityID, userData); } + return; + } + + if (doesEntityExistNow(userData.lightID)) { + this.lightID = Entities.identifyEntity(userData.lightID); + return; } // No valid light, create one - if (!this.lightID) { - this.lightID = this.createLight(); + this.lightID = this.createLight(userData); + print("Created new light entity"); + + // Update user data with new ID + userData.lightID = this.lightID.id; + updateUserData(this.entityID, userData); + } + + this.maybeMoveLight = function() { + var entityProperties = Entities.getEntityProperties(this.entityID); + var lightProperties = Entities.getEntityProperties(this.lightID); + var lightDefaultProperties = getUserData(this.entityID).lightDefaultProperties; + + var position = Vec3.sum(entityProperties.position, + Vec3.multiplyQbyV(entityProperties.rotation, + lightDefaultProperties.position)); + + if (!Vec3.equal(position, lightProperties.position)) { + print("Lamp entity moved, moving light entity as well"); + Entities.editEntity(this.lightID, { position: position }); } } + this.updateRelativeLightPosition = function() { + if (!doesEntityExistNow(this.entityID) || !doesEntityExistNow(this.lightID)) { + print("Warning: ID invalid, couldn't save relative position."); + return; + } + + var entityProperties = Entities.getEntityProperties(this.entityID); + var lightProperties = Entities.getEntityProperties(this.lightID); + var newProperties = {}; + + newProperties.position = Quat.multiply(Quat.inverse(entityProperties.rotation), + Vec3.subtract(lightProperties.position, + entityProperties.position)); + // inverse "visible" because right after we loaded the properties, the light entity is toggled. + newProperties.visible = !lightProperties.visible; + + // Copy only meaningful properties (trying to save space in userData here) + newProperties.dimensions = lightProperties.dimensions; + newProperties.color = lightProperties.color; + newProperties.lifetime = lightProperties.lifetime; + newProperties.isSpotlight = lightProperties.isSpotlight; + newProperties.intensity = lightProperties.intensity; + newProperties.exponent = lightProperties.exponent; + newProperties.cutoff = lightProperties.cutoff; + + var userData = getUserData(this.entityID); + userData.lightDefaultProperties = copyObject(lightProperties); + updateUserData(this.entityID, userData); + + print("Relative properties of light entity saved."); + print(JSON.stringify(userData)); + } + this.preload = function(entityID) { this.entityID = entityID; this.maybeDownloadSound(); @@ -82,38 +178,15 @@ this.clickReleaseOnEntity = function(entityID, mouseEvent) { if (mouseEvent.isLeftButton) { - this.updateLight(); + this.updateLightID(); + this.maybeMoveLight(); this.toggleLight(); this.playSound(); } else if (mouseEvent.isRightButton) { - print("Right button"); + this.updateRelativeLightPosition(); } }; - this.DO_NOT_MERGE = function() { - var userData = { - lightID: null, - lightDefaultProperties: { - type: "Light", - position: { x: 0, y: 0.5, z: 0 }, - dimensions: { x: 2, y: 2, z: 2 }, - angularVelocity: { x: 0, y: 0, z: 0 }, - angularDamping: 0, - - isSpotlight: true, - color: { red: 255, green: 0, blue: 0 }, - diffuseColor: { red: 255, green: 0, blue: 0 }, - ambientColor: { red: 0, green: 0, blue: 255 }, - specularColor: { red: 0, green: 255, blue: 0 }, - - intensity: 10, - constantAttenuation: 0, - linearAttenuation: 1, - quadraticAttenuation: 0, - exponent: 0, - cutoff: 180, // in degrees - } - }; - Entities.editEntity(this.entityID, { userData: JSON.stringify(userData) }); - } + // file:///Users/clement/hifi/examples/entityScripts/lightController.js + // file:///Users/clement/Downloads/japan-lamp.fbx }) \ No newline at end of file From 5fadcbe7d9c4a3051f845a26f91631c08425f2ea Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Mon, 23 Mar 2015 17:05:46 +0100 Subject: [PATCH 046/177] Prints cleanup --- examples/entityScripts/lightController.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 76d0b33eb3..68844b5605 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -60,13 +60,7 @@ lightProperties.position = Vec3.sum(entityProperties.position, Vec3.multiplyQbyV(entityProperties.rotation, lightProperties.position)); - - print(lightProperties); - print(JSON.stringify(lightProperties)); - var newLight = Entities.addEntity(lightProperties); - print(newLight); - print(JSON.stringify(newLight)); - return newLight; + return Entities.addEntity(lightProperties); } else { print("Warning: light controller has no default light."); return null; @@ -168,7 +162,6 @@ updateUserData(this.entityID, userData); print("Relative properties of light entity saved."); - print(JSON.stringify(userData)); } this.preload = function(entityID) { From 66f954142a6d290124a0087250a32175fa917caf Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Mon, 23 Mar 2015 17:06:12 +0100 Subject: [PATCH 047/177] Fix light multiple creations --- examples/entityScripts/lightController.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 68844b5605..7086cc1ce8 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -97,7 +97,7 @@ if (!didEntityExist(this.lightID)) { // Light now has an ID, so update it in userData this.lightID = Entities.identifyEntity(this.lightID); - userData.lightID = this.lightID.id; + userData.lightID = this.lightID; updateUserData(this.entityID, userData); } return; @@ -113,7 +113,7 @@ print("Created new light entity"); // Update user data with new ID - userData.lightID = this.lightID.id; + userData.lightID = this.lightID; updateUserData(this.entityID, userData); } From 3de7222007e3431232ee25962156aa6070427c04 Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Mon, 23 Mar 2015 09:06:15 -0700 Subject: [PATCH 048/177] Make Sixense emulate mouse only if controllers aren't at the base --- interface/src/devices/SixenseManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/devices/SixenseManager.cpp b/interface/src/devices/SixenseManager.cpp index ce6ca57c69..0a89ad0e37 100644 --- a/interface/src/devices/SixenseManager.cpp +++ b/interface/src/devices/SixenseManager.cpp @@ -223,7 +223,7 @@ void SixenseManager::update(float deltaTime) { palm->setJoystick(data->joystick_x, data->joystick_y); // Emulate the mouse so we can use scripts - if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput)) { + if (Menu::getInstance()->isOptionChecked(MenuOption::SixenseMouseInput) && !_controllersAtBase) { emulateMouse(palm, numActiveControllers - 1); } From efd177d80d79bb4cf4d043741dd7a144462fac2b Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Mon, 23 Mar 2015 17:06:34 +0100 Subject: [PATCH 049/177] Fix property save --- examples/entityScripts/lightController.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 7086cc1ce8..d8dfd36c38 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -158,7 +158,7 @@ newProperties.cutoff = lightProperties.cutoff; var userData = getUserData(this.entityID); - userData.lightDefaultProperties = copyObject(lightProperties); + userData.lightDefaultProperties = copyObject(newProperties); updateUserData(this.entityID, userData); print("Relative properties of light entity saved."); From 30ea2eb722892b5bbcf57444cd1a9606fe7fbd52 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Mon, 23 Mar 2015 17:20:21 +0100 Subject: [PATCH 050/177] Nicer way to update light Properties --- examples/entityScripts/lightController.js | 24 +++++++++++------------ 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index d8dfd36c38..44350da277 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -138,29 +138,27 @@ return; } + var userData = getUserData(this.entityID); + var newProperties = {}; + + // Copy only meaningful properties (trying to save space in userData here) + for (var key in userData.lightDefaultProperties) { + if (userData.lightDefaultProperties.hasOwnProperty(key)) { + newProperties[key] = userData.lightDefaultProperties[key]; + } + } + + // Compute new relative position var entityProperties = Entities.getEntityProperties(this.entityID); var lightProperties = Entities.getEntityProperties(this.lightID); - var newProperties = {}; - newProperties.position = Quat.multiply(Quat.inverse(entityProperties.rotation), Vec3.subtract(lightProperties.position, entityProperties.position)); // inverse "visible" because right after we loaded the properties, the light entity is toggled. newProperties.visible = !lightProperties.visible; - - // Copy only meaningful properties (trying to save space in userData here) - newProperties.dimensions = lightProperties.dimensions; - newProperties.color = lightProperties.color; - newProperties.lifetime = lightProperties.lifetime; - newProperties.isSpotlight = lightProperties.isSpotlight; - newProperties.intensity = lightProperties.intensity; - newProperties.exponent = lightProperties.exponent; - newProperties.cutoff = lightProperties.cutoff; - var userData = getUserData(this.entityID); userData.lightDefaultProperties = copyObject(newProperties); updateUserData(this.entityID, userData); - print("Relative properties of light entity saved."); } From 40ed0146e2a533e7738c7ea465e26ef55710c5c2 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Mon, 23 Mar 2015 17:26:43 +0100 Subject: [PATCH 051/177] Better handling of erased lights --- examples/entityScripts/lightController.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 44350da277..a012ff45f8 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -11,7 +11,11 @@ return entityID && entityID.isKnownID; } function doesEntityExistNow(entityID) { - return entityID && Entities.getEntityProperties(entityID).isKnownID; + return entityID && getTrueID(entityID).isKnownID; + } + function getTrueID(entityID) { + var properties = Entities.getEntityProperties(entityID); + return { id: properties.id, creatorTokenID: properties.creatorTokenID, isKnownID: properties.isKnownID }; } function getUserData(entityID) { var properties = Entities.getEntityProperties(entityID); @@ -96,7 +100,7 @@ if (doesEntityExistNow(this.lightID)) { if (!didEntityExist(this.lightID)) { // Light now has an ID, so update it in userData - this.lightID = Entities.identifyEntity(this.lightID); + this.lightID = getTrueID(this.lightID); userData.lightID = this.lightID; updateUserData(this.entityID, userData); } @@ -104,7 +108,7 @@ } if (doesEntityExistNow(userData.lightID)) { - this.lightID = Entities.identifyEntity(userData.lightID); + this.lightID = getTrueID(userData.lightID); return; } From 963be820d059da0b7a75129a5a6b28d8cbb062b0 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Mon, 23 Mar 2015 17:28:11 +0100 Subject: [PATCH 052/177] Remove comments --- examples/entityScripts/lightController.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index a012ff45f8..981099377c 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -181,7 +181,4 @@ this.updateRelativeLightPosition(); } }; - - // file:///Users/clement/hifi/examples/entityScripts/lightController.js - // file:///Users/clement/Downloads/japan-lamp.fbx }) \ No newline at end of file From fdfdba5d2d36a40b7d81b0dc5ffce216884ab106 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Mon, 23 Mar 2015 17:46:57 +0100 Subject: [PATCH 053/177] Couple tweaks --- examples/entityScripts/lightController.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 981099377c..dd1a50cd84 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -79,7 +79,7 @@ lightDefaultProperties: { type: "Light", position: { x: 0, y: 0, z: 0 }, - dimensions: { x: 2, y: 2, z: 2 }, + dimensions: { x: 5, y: 5, z: 5 }, isSpotlight: false, color: { red: 255, green: 48, blue: 0 }, diffuseColor: { red: 255, green: 255, blue: 255 }, @@ -172,6 +172,9 @@ }; this.clickReleaseOnEntity = function(entityID, mouseEvent) { + this.entityID = entityID; + this.maybeDownloadSound(); + if (mouseEvent.isLeftButton) { this.updateLightID(); this.maybeMoveLight(); From ea0f3f05e7e1fdccb2c38618048c2b8c57f45c8c Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Mon, 23 Mar 2015 17:55:23 +0100 Subject: [PATCH 054/177] Tune sound down --- examples/entityScripts/lightController.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index dd1a50cd84..ba4fd60b03 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -39,7 +39,10 @@ // Play switch sound this.playSound = function() { if (this.sound && this.sound.downloaded) { - Audio.playSound(this.sound, { position: Entities.getEntityProperties(this.entityID).position }); + Audio.playSound(this.sound, { + position: Entities.getEntityProperties(this.entityID).position, + volume: 0.2 + }); } else { print("Warning: Couldn't play sound."); } From fe8ad9517f788bbadb9c13b95d4a9c4983ae2130 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Mon, 23 Mar 2015 10:08:08 -0700 Subject: [PATCH 055/177] added debugging for model mesh boxes --- libraries/render-utils/src/Model.cpp | 59 +++++++++++++++++++++++++++- libraries/render-utils/src/Model.h | 3 ++ 2 files changed, 61 insertions(+), 1 deletion(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index f7a4257de7..d91c972c45 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -842,10 +842,67 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { args->_translucentMeshPartsRendered = translucentMeshPartsRendered; args->_opaqueMeshPartsRendered = opaqueMeshPartsRendered; } - + + #ifdef WANT_DEBUG_MESHBOXES + renderDebugMeshBoxes(); + #endif + return true; } +void Model::renderDebugMeshBoxes() { + int colorNdx = 0; + foreach(AABox box, _calculatedMeshBoxes) { + if (_debugMeshBoxesID == GeometryCache::UNKNOWN_ID) { + _debugMeshBoxesID = DependencyManager::get<GeometryCache>()->allocateID(); + } + QVector<glm::vec3> points; + + glm::vec3 brn = box.getCorner(); + glm::vec3 bln = brn + glm::vec3(box.getDimensions().x, 0, 0); + glm::vec3 brf = brn + glm::vec3(0, 0, box.getDimensions().z); + glm::vec3 blf = brn + glm::vec3(box.getDimensions().x, 0, box.getDimensions().z); + + glm::vec3 trn = brn + glm::vec3(0, box.getDimensions().y, 0); + glm::vec3 tln = bln + glm::vec3(0, box.getDimensions().y, 0); + glm::vec3 trf = brf + glm::vec3(0, box.getDimensions().y, 0); + glm::vec3 tlf = blf + glm::vec3(0, box.getDimensions().y, 0); + + points << brn << bln; + points << brf << blf; + points << brn << brf; + points << bln << blf; + + points << trn << tln; + points << trf << tlf; + points << trn << trf; + points << tln << tlf; + + points << brn << trn; + points << brf << trf; + points << bln << tln; + points << blf << tlf; + + glm::vec4 color[] = { + { 1.0f, 0.0f, 0.0f, 1.0f }, // red + { 0.0f, 1.0f, 0.0f, 1.0f }, // green + { 0.0f, 0.0f, 1.0f, 1.0f }, // blue + { 1.0f, 0.0f, 1.0f, 1.0f }, // purple + { 1.0f, 1.0f, 0.0f, 1.0f }, // yellow + { 0.0f, 1.0f, 1.0f, 1.0f }, // cyan + { 1.0f, 1.0f, 1.0f, 1.0f }, // white + { 0.0f, 0.5f, 0.0f, 1.0f }, + { 0.0f, 0.0f, 0.5f, 1.0f }, + { 0.5f, 0.0f, 0.5f, 1.0f }, + { 0.5f, 0.5f, 0.0f, 1.0f }, + { 0.0f, 0.5f, 0.5f, 1.0f } }; + + DependencyManager::get<GeometryCache>()->updateVertices(_debugMeshBoxesID, points, color[colorNdx]); + DependencyManager::get<GeometryCache>()->renderVertices(gpu::LINES, _debugMeshBoxesID); + colorNdx++; + } +} + Extents Model::getBindExtents() const { if (!isActive()) { return Extents(); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 5114ef1c9f..e7cb0aa8e5 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -444,6 +444,9 @@ private: QVector<int> _meshesOpaqueLightmapTangentsSpecular; QVector<int> _meshesOpaqueLightmapSpecular; + // debug rendering support + void renderDebugMeshBoxes(); + int _debugMeshBoxesID = GeometryCache::UNKNOWN_ID; // Scene rendering support static QVector<Model*> _modelsInScene; From c26f17e16b6fee518912880c13dfe0923a979b8f Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Mon, 23 Mar 2015 18:36:40 +0100 Subject: [PATCH 056/177] Update from light properties --- examples/entityScripts/lightController.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index ba4fd60b03..624fc929b3 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -146,23 +146,23 @@ } var userData = getUserData(this.entityID); + var entityProperties = Entities.getEntityProperties(this.entityID); + var lightProperties = Entities.getEntityProperties(this.lightID); var newProperties = {}; - + // Copy only meaningful properties (trying to save space in userData here) for (var key in userData.lightDefaultProperties) { if (userData.lightDefaultProperties.hasOwnProperty(key)) { - newProperties[key] = userData.lightDefaultProperties[key]; + newProperties[key] = lightProperties[key]; } } - + // Compute new relative position - var entityProperties = Entities.getEntityProperties(this.entityID); - var lightProperties = Entities.getEntityProperties(this.lightID); newProperties.position = Quat.multiply(Quat.inverse(entityProperties.rotation), Vec3.subtract(lightProperties.position, entityProperties.position)); - // inverse "visible" because right after we loaded the properties, the light entity is toggled. - newProperties.visible = !lightProperties.visible; + // inverse "visible" because right after we loaded the properties, the light entity is toggled. + newProperties.visible = !lightProperties.visible; userData.lightDefaultProperties = copyObject(newProperties); updateUserData(this.entityID, userData); From b705d7633685c7f4ff81af45ffed3364632cb13b Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Mon, 23 Mar 2015 10:43:21 -0700 Subject: [PATCH 057/177] total hack to ignore frustum culling in case of avatar mesh parts with no transform --- libraries/render-utils/src/Model.cpp | 49 ++++++++++++++++++---------- libraries/render-utils/src/Model.h | 7 ++-- 2 files changed, 36 insertions(+), 20 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index d91c972c45..0b7fd3dcbf 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -727,19 +727,19 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { //renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, book isSkinned, args); int opaqueMeshPartsRendered = 0; - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, false, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, true, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, false, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, true, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, false, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, true, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, false, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, true, args); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, true, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, true, true, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, false, true, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, true, true, true, args, true); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, false, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, false, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, false, args); - opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, false, args); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, false, true, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, false, false, args, true); + opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, true, true, true, false, args, true); // render translucent meshes afterwards //DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(false, true, true); @@ -2358,7 +2358,8 @@ int Model::renderMeshesForModelsInScene(gpu::Batch& batch, RenderMode mode, bool } int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args) { + bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, + bool forceRenderSomeMeshes) { PROFILE_RANGE(__FUNCTION__); int meshPartsRendered = 0; @@ -2378,8 +2379,10 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl Locations* locations; SkinLocations* skinLocations; - pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, args, locations, skinLocations); - meshPartsRendered = renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, args, locations, skinLocations); + pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, + args, locations, skinLocations); + meshPartsRendered = renderMeshesFromList(list, batch, mode, translucent, alphaThreshold, + args, locations, skinLocations, forceRenderSomeMeshes); GLBATCH(glUseProgram)(0); return meshPartsRendered; @@ -2387,7 +2390,7 @@ int Model::renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, fl int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, RenderArgs* args, - Locations* locations, SkinLocations* skinLocations) { + Locations* locations, SkinLocations* skinLocations, bool forceRenderSomeMeshes) { PROFILE_RANGE(__FUNCTION__); auto textureCache = DependencyManager::get<TextureCache>(); @@ -2423,11 +2426,21 @@ int Model::renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMod // if we got here, then check to see if this mesh is in view if (args) { bool shouldRender = true; + bool forceRender = false; args->_meshesConsidered++; if (args->_viewFrustum) { - shouldRender = args->_viewFrustum->boxInFrustum(_calculatedMeshBoxes.at(i)) != ViewFrustum::OUTSIDE; - if (shouldRender) { + + // NOTE: This is a hack to address the fact that for avatar meshes, the _calculatedMeshBoxes can be wrong + // for some meshes. Those meshes where the mesh's modelTransform is the identity matrix, and will have + // incorrectly calculated mesh boxes. In this case, we will ignore the box and assume it's visible. + if (forceRenderSomeMeshes && (geometry.meshes.at(i).modelTransform == glm::mat4())) { + forceRender = true; + } + + shouldRender = forceRender || args->_viewFrustum->boxInFrustum(_calculatedMeshBoxes.at(i)) != ViewFrustum::OUTSIDE; + + if (shouldRender && !forceRender) { float distance = args->_viewFrustum->distanceToCamera(_calculatedMeshBoxes.at(i).calcCenter()); shouldRender = !_viewState ? false : _viewState->shouldRenderMesh(_calculatedMeshBoxes.at(i).getLargestDimension(), distance); diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index e7cb0aa8e5..05db20b056 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -459,12 +459,15 @@ private: void renderSetup(RenderArgs* args); bool renderCore(float alpha, RenderMode mode, RenderArgs* args); int renderMeshes(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, - bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL); + bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args = NULL, + bool forceRenderSomeMeshes = false); + void setupBatchTransform(gpu::Batch& batch); QVector<int>* pickMeshList(bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned); int renderMeshesFromList(QVector<int>& list, gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, - RenderArgs* args, Locations* locations, SkinLocations* skinLocations); + RenderArgs* args, Locations* locations, SkinLocations* skinLocations, + bool forceRenderSomeMeshes = false); static void pickPrograms(gpu::Batch& batch, RenderMode mode, bool translucent, float alphaThreshold, bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, RenderArgs* args, From 3e8508f1493c654fde86d917facf68af35a70da3 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Mon, 23 Mar 2015 11:13:35 -0700 Subject: [PATCH 058/177] CR feedback --- libraries/render-utils/src/Model.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 0b7fd3dcbf..d640876086 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -1363,6 +1363,7 @@ void Model::updateJointState(int index) { glm::mat4 parentTransform = glm::scale(_scale) * glm::translate(_offset) * geometry.offset; state.computeTransform(parentTransform); } else { + // guard against out-of-bounds access to _jointStates if (joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) { const JointState& parentState = _jointStates.at(parentIndex); state.computeTransform(parentState.getTransform(), parentState.getTransformChanged()); From 9fb53e3d72e8618401a80424f97e5756ecb6500f Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Mon, 23 Mar 2015 11:13:42 -0700 Subject: [PATCH 059/177] CR feedback --- interface/src/avatar/FaceModel.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/avatar/FaceModel.cpp b/interface/src/avatar/FaceModel.cpp index 6dd97f067a..722f998f86 100644 --- a/interface/src/avatar/FaceModel.cpp +++ b/interface/src/avatar/FaceModel.cpp @@ -87,6 +87,7 @@ void FaceModel::maybeUpdateEyeRotation(Model* model, const JointState& parentSta void FaceModel::updateJointState(int index) { JointState& state = _jointStates[index]; const FBXJoint& joint = state.getFBXJoint(); + // guard against out-of-bounds access to _jointStates if (joint.parentIndex != -1 && joint.parentIndex >= 0 && joint.parentIndex < _jointStates.size()) { const JointState& parentState = _jointStates.at(joint.parentIndex); const FBXGeometry& geometry = _geometry->getFBXGeometry(); From cb6abfb2e6fbd6a53f8aafa8345831e18bed01d5 Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Mon, 23 Mar 2015 12:05:56 -0700 Subject: [PATCH 060/177] Display notification if domain connection refused --- examples/notifications.js | 9 ++++++++- interface/src/Application.cpp | 11 ++++++++++- interface/src/Application.h | 6 ++++++ interface/src/DatagramProcessor.cpp | 1 + interface/src/scripting/WindowScriptingInterface.cpp | 1 + interface/src/scripting/WindowScriptingInterface.h | 1 + 6 files changed, 27 insertions(+), 2 deletions(-) diff --git a/examples/notifications.js b/examples/notifications.js index 0c2a06c878..f6819f60b7 100644 --- a/examples/notifications.js +++ b/examples/notifications.js @@ -91,10 +91,12 @@ var NotificationType = { MUTE_TOGGLE: 1, SNAPSHOT: 2, WINDOW_RESIZE: 3, + CONNECTION_REFUSED: 4, properties: [ { text: "Mute Toggle" }, { text: "Snapshot" }, - { text: "Window Resize" } + { text: "Window Resize" }, + { text: "Connection Refused" } ], getTypeFromMenuItem: function(menuItemName) { if (menuItemName.substr(menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length) !== NOTIFICATION_MENU_ITEM_POST) { @@ -489,6 +491,10 @@ function onMuteStateChanged() { createNotification(muteString, NotificationType.MUTE_TOGGLE); } +function onDomainConnectionRefused(reason) { + createNotification("Connection refused: " + reason, NotificationType.CONNECTION_REFUSED ); +} + // handles mouse clicks on buttons function mousePressEvent(event) { var pickRay, @@ -582,5 +588,6 @@ Controller.keyReleaseEvent.connect(keyReleaseEvent); Script.update.connect(update); Script.scriptEnding.connect(scriptEnding); Menu.menuItemEvent.connect(menuItemEvent); +Window.domainConnectionRefused.connect(onDomainConnectionRefused); setup(); diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4ff41e1b6f..70b99f7daa 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -297,7 +297,8 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : _lastSendDownstreamAudioStats(usecTimestampNow()), _isVSyncOn(true), _aboutToQuit(false), - _notifiedPacketVersionMismatchThisDomain(false) + _notifiedPacketVersionMismatchThisDomain(false), + _domainConnectionRefusals(QList<QString>()) { #ifdef Q_OS_WIN installNativeEventFilter(&MyNativeEventFilter::getInstance()); @@ -3288,6 +3289,14 @@ void Application::clearDomainOctreeDetails() { void Application::domainChanged(const QString& domainHostname) { updateWindowTitle(); clearDomainOctreeDetails(); + _domainConnectionRefusals.clear(); +} + +void Application::domainConnectionDenied(const QString& reason) { + if (!_domainConnectionRefusals.contains(reason)) { + _domainConnectionRefusals.append(reason); + emit domainConnectionRefused(reason); + } } void Application::connectedToDomain(const QString& hostname) { diff --git a/interface/src/Application.h b/interface/src/Application.h index 4038b21739..b0e7690f0a 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -332,6 +332,8 @@ signals: void svoImportRequested(const QString& url); + void domainConnectionRefused(const QString& reason); + public slots: void domainChanged(const QString& domainHostname); void updateWindowTitle(); @@ -382,6 +384,8 @@ public slots: void setActiveFaceTracker(); + void domainConnectionDenied(const QString& reason); + private slots: void clearDomainOctreeDetails(); void checkFPS(); @@ -606,6 +610,8 @@ private: int _menuBarHeight; QHash<QString, AcceptURLMethod> _acceptedExtensions; + + QList<QString> _domainConnectionRefusals; }; #endif // hifi_Application_h diff --git a/interface/src/DatagramProcessor.cpp b/interface/src/DatagramProcessor.cpp index 475ce406bb..9ac2b51097 100644 --- a/interface/src/DatagramProcessor.cpp +++ b/interface/src/DatagramProcessor.cpp @@ -127,6 +127,7 @@ void DatagramProcessor::processDatagrams() { // and check and signal for an access token so that we can make sure they are logged in qDebug() << "The domain-server denied a connection request: " << reason; qDebug() << "You may need to re-log to generate a keypair so you can provide a username signature."; + application->domainConnectionDenied(reason); AccountManager::getInstance().checkAndSignalForAccessToken(); break; } diff --git a/interface/src/scripting/WindowScriptingInterface.cpp b/interface/src/scripting/WindowScriptingInterface.cpp index 7f4b5ddf45..a5b8128d1e 100644 --- a/interface/src/scripting/WindowScriptingInterface.cpp +++ b/interface/src/scripting/WindowScriptingInterface.cpp @@ -33,6 +33,7 @@ WindowScriptingInterface::WindowScriptingInterface() : const DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler(); connect(&domainHandler, &DomainHandler::hostnameChanged, this, &WindowScriptingInterface::domainChanged); connect(Application::getInstance(), &Application::svoImportRequested, this, &WindowScriptingInterface::svoImportRequested); + connect(Application::getInstance(), &Application::domainConnectionRefused, this, &WindowScriptingInterface::domainConnectionRefused); } WebWindowClass* WindowScriptingInterface::doCreateWebWindow(const QString& title, const QString& url, int width, int height, bool isToolWindow) { diff --git a/interface/src/scripting/WindowScriptingInterface.h b/interface/src/scripting/WindowScriptingInterface.h index 6a812f14e3..9bc8a834bd 100644 --- a/interface/src/scripting/WindowScriptingInterface.h +++ b/interface/src/scripting/WindowScriptingInterface.h @@ -62,6 +62,7 @@ signals: void inlineButtonClicked(const QString& name); void nonBlockingFormClosed(); void svoImportRequested(const QString& url); + void domainConnectionRefused(const QString& reason); private slots: QScriptValue showAlert(const QString& message); From 61dc31ffe76fafea99fa20177311bd256910ab98 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Mon, 23 Mar 2015 14:09:45 -0700 Subject: [PATCH 061/177] Update export entities to export as JSON --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4ff41e1b6f..840e8388c7 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1751,7 +1751,7 @@ bool Application::exportEntities(const QString& filename, const QVector<EntityIt exportTree.addEntity(entityItem->getEntityItemID(), properties); } - exportTree.writeToSVOFile(filename.toLocal8Bit().constData()); + exportTree.writeToJSONFile(filename.toLocal8Bit().constData()); // restore the main window's active state _window->activateWindow(); From f31ac8b968238f795e9c6b4f18f44122a757f0a9 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Mon, 23 Mar 2015 15:10:28 -0700 Subject: [PATCH 062/177] compound covex hull collisions work --- libraries/physics/src/ShapeInfoUtil.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp index b48bff763c..07fedb35ad 100644 --- a/libraries/physics/src/ShapeInfoUtil.cpp +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -161,6 +161,7 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { hull->addPoint(btPoint); } btTransform trans; + trans.setIdentity(); static_cast<btCompoundShape*>(shape)->addChildShape (trans, hull); } } From fa122a227b085f7ddaab53d02c12067229604a61 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Mon, 23 Mar 2015 16:44:07 -0700 Subject: [PATCH 063/177] tweaks to the LOD Tools UI --- interface/src/Application.cpp | 2 +- interface/src/LODManager.cpp | 200 ++++++++++++++++++---------- interface/src/LODManager.h | 46 ++++--- interface/src/Menu.cpp | 1 - interface/src/Menu.h | 1 - interface/src/ui/LodToolsDialog.cpp | 161 ++++++++++------------ interface/src/ui/LodToolsDialog.h | 19 ++- 7 files changed, 241 insertions(+), 189 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4ff41e1b6f..ad6a0d86ce 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1969,7 +1969,7 @@ bool Application::isLookingAtMyAvatar(Avatar* avatar) { void Application::updateLOD() { PerformanceTimer perfTimer("LOD"); // adjust it unless we were asked to disable this feature, or if we're currently in throttleRendering mode - if (!Menu::getInstance()->isOptionChecked(MenuOption::DisableAutoAdjustLOD) && !isThrottleRendering()) { + if (!isThrottleRendering()) { DependencyManager::get<LODManager>()->autoAdjustLOD(_fps); } else { DependencyManager::get<LODManager>()->resetLODAdjust(); diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 063ba13492..739e5f280a 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -17,15 +17,34 @@ #include "LODManager.h" -Setting::Handle<bool> automaticAvatarLOD("automaticAvatarLOD", true); -Setting::Handle<float> avatarLODDecreaseFPS("avatarLODDecreaseFPS", DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS); -Setting::Handle<float> avatarLODIncreaseFPS("avatarLODIncreaseFPS", ADJUST_LOD_UP_FPS); +Setting::Handle<bool> automaticLODAdjust("automaticLODAdjust", true); +Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS); +Setting::Handle<float> desktopLODIncreaseFPS("desktopLODIncreaseFPS", DEFAULT_DESKTOP_LOD_UP_FPS); +Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS); +Setting::Handle<float> hmdLODIncreaseFPS("hmdLODIncreaseFPS", DEFAULT_HMD_LOD_UP_FPS); + + Setting::Handle<float> avatarLODDistanceMultiplier("avatarLODDistanceMultiplier", DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER); Setting::Handle<int> boundaryLevelAdjust("boundaryLevelAdjust", 0); Setting::Handle<float> octreeSizeScale("octreeSizeScale", DEFAULT_OCTREE_SIZE_SCALE); +float LODManager::getLODDecreaseFPS() { + if (Application::getInstance()->isHMDMode()) { + return getHMDLODDecreaseFPS(); + } + return getDesktopLODDecreaseFPS(); +} + +float LODManager::getLODIncreaseFPS() { + if (Application::getInstance()->isHMDMode()) { + return getHMDLODIncreaseFPS(); + } + return getDesktopLODIncreaseFPS(); +} + + void LODManager::autoAdjustLOD(float currentFPS) { // NOTE: our first ~100 samples at app startup are completely all over the place, and we don't // really want to count them in our average, so we will ignore the real frame rates and stuff @@ -39,66 +58,93 @@ void LODManager::autoAdjustLOD(float currentFPS) { _fastFPSAverage.updateAverage(currentFPS); quint64 now = usecTimestampNow(); - - const quint64 ADJUST_AVATAR_LOD_DOWN_DELAY = 1000 * 1000; - if (_automaticAvatarLOD) { - if (_fastFPSAverage.getAverage() < _avatarLODDecreaseFPS) { - if (now - _lastAvatarDetailDrop > ADJUST_AVATAR_LOD_DOWN_DELAY) { - // attempt to lower the detail in proportion to the fps difference - float targetFps = (_avatarLODDecreaseFPS + _avatarLODIncreaseFPS) * 0.5f; - float averageFps = _fastFPSAverage.getAverage(); - const float MAXIMUM_MULTIPLIER_SCALE = 2.0f; - _avatarLODDistanceMultiplier = qMin(MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier * - (averageFps < EPSILON ? MAXIMUM_MULTIPLIER_SCALE : - qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps))); - _lastAvatarDetailDrop = now; - } - } else if (_fastFPSAverage.getAverage() > _avatarLODIncreaseFPS) { - // let the detail level creep slowly upwards - const float DISTANCE_DECREASE_RATE = 0.05f; - _avatarLODDistanceMultiplier = qMax(MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, - _avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE); - } - } - + bool changed = false; + bool octreeChanged = false; quint64 elapsed = now - _lastAdjust; - if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < ADJUST_LOD_DOWN_FPS - && _octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) { - - _octreeSizeScale *= ADJUST_LOD_DOWN_BY; - - if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; - } - changed = true; - _lastAdjust = now; - qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() - << "_octreeSizeScale=" << _octreeSizeScale; - - emit LODDecreased(); - } - - if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > ADJUST_LOD_UP_FPS - && _octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { - _octreeSizeScale *= ADJUST_LOD_UP_BY; - if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; - } - changed = true; - _lastAdjust = now; - qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() - << "_octreeSizeScale=" << _octreeSizeScale; + if (_automaticLODAdjust) { + // LOD Downward adjustment + if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < getLODDecreaseFPS()) { - emit LODIncreased(); - } + // Avatars... attempt to lower the detail in proportion to the fps difference + float targetFps = (getLODDecreaseFPS() + getLODIncreaseFPS()) * 0.5f; + float averageFps = _fastFPSAverage.getAverage(); + const float MAXIMUM_MULTIPLIER_SCALE = 2.0f; + float oldAvatarLODDistanceMultiplier = _avatarLODDistanceMultiplier; + _avatarLODDistanceMultiplier = qMin(MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier * + (averageFps < EPSILON ? MAXIMUM_MULTIPLIER_SCALE : + qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps))); + + if (oldAvatarLODDistanceMultiplier != _avatarLODDistanceMultiplier) { + qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() + << "_avatarLODDistanceMultiplier=" << _avatarLODDistanceMultiplier; + changed = true; + } + + // Octree items... stepwise adjustment + if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) { + _octreeSizeScale *= ADJUST_LOD_DOWN_BY; + if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; + } + octreeChanged = changed = true; + } + + if (changed) { + _lastAdjust = now; + qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() + << "_octreeSizeScale=" << _octreeSizeScale; + + emit LODDecreased(); + } + } - if (changed) { - _shouldRenderTableNeedsRebuilding = true; - auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog(); - if (lodToolsDialog) { - lodToolsDialog->reloadSliders(); + // LOD Upward adjustment + if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > getLODIncreaseFPS()) { + + // Avatars... let the detail level creep slowly upwards + if (_avatarLODDistanceMultiplier < MAXIMUM_AUTO_ADJUST_AVATAR_LOD_DISTANCE_MULTIPLIER) { + const float DISTANCE_DECREASE_RATE = 0.05f; + float oldAvatarLODDistanceMultiplier = _avatarLODDistanceMultiplier; + _avatarLODDistanceMultiplier = qMax(MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, + _avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE); + + if (oldAvatarLODDistanceMultiplier != _avatarLODDistanceMultiplier) { + qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() + << "_avatarLODDistanceMultiplier=" << _avatarLODDistanceMultiplier; + changed = true; + } + } + + // Octee items... stepwise adjustment + if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { + if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; + } else { + _octreeSizeScale *= ADJUST_LOD_UP_BY; + } + if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; + } + octreeChanged = changed = true; + } + + if (changed) { + _lastAdjust = now; + qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() + << "_octreeSizeScale=" << _octreeSizeScale; + + emit LODIncreased(); + } + } + + if (changed) { + _shouldRenderTableNeedsRebuilding = true; + auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog(); + if (lodToolsDialog) { + lodToolsDialog->reloadSliders(); + } } } } @@ -106,7 +152,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { void LODManager::resetLODAdjust() { _fpsAverage.reset(); _fastFPSAverage.reset(); - _lastAvatarDetailDrop = _lastAdjust = usecTimestampNow(); + _lastAdjust = usecTimestampNow(); } QString LODManager::getLODFeedbackText() { @@ -116,29 +162,33 @@ QString LODManager::getLODFeedbackText() { switch (boundaryLevelAdjust) { case 0: { - granularityFeedback = QString("at standard granularity."); + granularityFeedback = QString("."); } break; case 1: { - granularityFeedback = QString("at half of standard granularity."); + granularityFeedback = QString(" at half of standard granularity."); } break; case 2: { - granularityFeedback = QString("at a third of standard granularity."); + granularityFeedback = QString(" at a third of standard granularity."); } break; default: { - granularityFeedback = QString("at 1/%1th of standard granularity.").arg(boundaryLevelAdjust + 1); + granularityFeedback = QString(" at 1/%1th of standard granularity.").arg(boundaryLevelAdjust + 1); } break; } // distance feedback float octreeSizeScale = getOctreeSizeScale(); float relativeToDefault = octreeSizeScale / DEFAULT_OCTREE_SIZE_SCALE; + int relativeToTwentyTwenty = 20 / relativeToDefault; + QString result; if (relativeToDefault > 1.01) { - result = QString("%1 further %2").arg(relativeToDefault,8,'f',2).arg(granularityFeedback); + result = QString("20:%1 or %2 times further than average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',2).arg(granularityFeedback); } else if (relativeToDefault > 0.99) { - result = QString("the default distance %1").arg(granularityFeedback); + result = QString("20:20 or the default distance for average vision%1").arg(granularityFeedback); + } else if (relativeToDefault > 0.01) { + result = QString("20:%1 or %2 of default distance for average vision%3").arg(relativeToTwentyTwenty).arg(relativeToDefault,0,'f',3).arg(granularityFeedback); } else { - result = QString("%1 of default %2").arg(relativeToDefault,8,'f',3).arg(granularityFeedback); + result = QString("%2 of default distance for average vision%3").arg(relativeToDefault,0,'f',3).arg(granularityFeedback); } return result; } @@ -194,18 +244,24 @@ void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) { void LODManager::loadSettings() { - setAutomaticAvatarLOD(automaticAvatarLOD.get()); - setAvatarLODDecreaseFPS(avatarLODDecreaseFPS.get()); - setAvatarLODIncreaseFPS(avatarLODIncreaseFPS.get()); + setAutomaticLODAdjust(automaticLODAdjust.get()); + setDesktopLODDecreaseFPS(desktopLODDecreaseFPS.get()); + setDesktopLODIncreaseFPS(desktopLODIncreaseFPS.get()); + setHMDLODDecreaseFPS(hmdLODDecreaseFPS.get()); + setHMDLODIncreaseFPS(hmdLODIncreaseFPS.get()); + setAvatarLODDistanceMultiplier(avatarLODDistanceMultiplier.get()); setBoundaryLevelAdjust(boundaryLevelAdjust.get()); setOctreeSizeScale(octreeSizeScale.get()); } void LODManager::saveSettings() { - automaticAvatarLOD.set(getAutomaticAvatarLOD()); - avatarLODDecreaseFPS.set(getAvatarLODDecreaseFPS()); - avatarLODIncreaseFPS.set(getAvatarLODIncreaseFPS()); + automaticLODAdjust.set(getAutomaticLODAdjust()); + desktopLODDecreaseFPS.set(getDesktopLODDecreaseFPS()); + desktopLODIncreaseFPS.set(getDesktopLODIncreaseFPS()); + hmdLODDecreaseFPS.set(getHMDLODDecreaseFPS()); + hmdLODIncreaseFPS.set(getHMDLODIncreaseFPS()); + avatarLODDistanceMultiplier.set(getAvatarLODDistanceMultiplier()); boundaryLevelAdjust.set(getBoundaryLevelAdjust()); octreeSizeScale.set(getOctreeSizeScale()); diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 61c24bf5af..57b03cba42 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -17,9 +17,10 @@ #include <SharedUtil.h> #include <SimpleMovingAverage.h> -const float ADJUST_LOD_DOWN_FPS = 40.0; -const float ADJUST_LOD_UP_FPS = 55.0; -const float DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS = 30.0f; +const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0; +const float DEFAULT_DESKTOP_LOD_UP_FPS = 50.0; +const float DEFAULT_HMD_LOD_DOWN_FPS = 60.0; +const float DEFAULT_HMD_LOD_UP_FPS = 65.0; const quint64 ADJUST_LOD_DOWN_DELAY = 1000 * 1000 * 0.5; // Consider adjusting LOD down after half a second const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2; @@ -36,6 +37,7 @@ const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f; const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f; const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; +const float MAXIMUM_AUTO_ADJUST_AVATAR_LOD_DISTANCE_MULTIPLIER = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER; const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; @@ -46,14 +48,21 @@ class LODManager : public QObject, public Dependency { SINGLETON_DEPENDENCY public: - void setAutomaticAvatarLOD(bool automaticAvatarLOD) { _automaticAvatarLOD = automaticAvatarLOD; } - bool getAutomaticAvatarLOD() const { return _automaticAvatarLOD; } - void setAvatarLODDecreaseFPS(float avatarLODDecreaseFPS) { _avatarLODDecreaseFPS = avatarLODDecreaseFPS; } - float getAvatarLODDecreaseFPS() const { return _avatarLODDecreaseFPS; } - void setAvatarLODIncreaseFPS(float avatarLODIncreaseFPS) { _avatarLODIncreaseFPS = avatarLODIncreaseFPS; } - float getAvatarLODIncreaseFPS() const { return _avatarLODIncreaseFPS; } - void setAvatarLODDistanceMultiplier(float multiplier) { _avatarLODDistanceMultiplier = multiplier; } - float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; } + Q_INVOKABLE void setAutomaticLODAdjust(bool value) { _automaticLODAdjust = value; } + Q_INVOKABLE bool getAutomaticLODAdjust() const { return _automaticLODAdjust; } + + Q_INVOKABLE void setDesktopLODDecreaseFPS(float value) { _desktopLODDecreaseFPS = value; } + Q_INVOKABLE float getDesktopLODDecreaseFPS() const { return _desktopLODDecreaseFPS; } + Q_INVOKABLE void setDesktopLODIncreaseFPS(float value) { _desktopLODIncreaseFPS = value; } + Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return _desktopLODIncreaseFPS; } + + Q_INVOKABLE void setHMDLODDecreaseFPS(float value) { _hmdLODDecreaseFPS = value; } + Q_INVOKABLE float getHMDLODDecreaseFPS() const { return _hmdLODDecreaseFPS; } + Q_INVOKABLE void setHMDLODIncreaseFPS(float value) { _hmdLODIncreaseFPS = value; } + Q_INVOKABLE float getHMDLODIncreaseFPS() const { return _hmdLODIncreaseFPS; } + + Q_INVOKABLE void setAvatarLODDistanceMultiplier(float multiplier) { _avatarLODDistanceMultiplier = multiplier; } + Q_INVOKABLE float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; } // User Tweakable LOD Items Q_INVOKABLE QString getLODFeedbackText(); @@ -63,12 +72,15 @@ public: Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust); Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } - void autoAdjustLOD(float currentFPS); Q_INVOKABLE void resetLODAdjust(); Q_INVOKABLE float getFPSAverage() const { return _fpsAverage.getAverage(); } Q_INVOKABLE float getFastFPSAverage() const { return _fastFPSAverage.getAverage(); } + Q_INVOKABLE float getLODDecreaseFPS(); + Q_INVOKABLE float getLODIncreaseFPS(); + bool shouldRenderMesh(float largestDimension, float distanceToCamera); + void autoAdjustLOD(float currentFPS); void loadSettings(); void saveSettings(); @@ -80,16 +92,18 @@ signals: private: LODManager() {} - bool _automaticAvatarLOD = true; - float _avatarLODDecreaseFPS = DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS; - float _avatarLODIncreaseFPS = ADJUST_LOD_UP_FPS; + bool _automaticLODAdjust = true; + float _desktopLODDecreaseFPS = DEFAULT_DESKTOP_LOD_DOWN_FPS; + float _desktopLODIncreaseFPS = DEFAULT_DESKTOP_LOD_UP_FPS; + float _hmdLODDecreaseFPS = DEFAULT_HMD_LOD_DOWN_FPS; + float _hmdLODIncreaseFPS = DEFAULT_HMD_LOD_UP_FPS; + float _avatarLODDistanceMultiplier = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER; float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; int _boundaryLevelAdjust = 0; quint64 _lastAdjust = 0; - quint64 _lastAvatarDetailDrop = 0; SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES; SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES; diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2823e8eb23..8d3c01320f 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -276,7 +276,6 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Entities, 0, true); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion); addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges); - addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DisableAutoAdjustLOD); QMenu* ambientLightMenu = renderOptionsMenu->addMenu(MenuOption::RenderAmbientLight); QActionGroup* ambientLightGroup = new QActionGroup(ambientLightMenu); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index fc1347fa27..60fe5d4cd2 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -136,7 +136,6 @@ namespace MenuOption { const QString DecreaseAvatarSize = "Decrease Avatar Size"; const QString DeleteBookmark = "Delete Bookmark..."; const QString DisableActivityLogger = "Disable Activity Logger"; - const QString DisableAutoAdjustLOD = "Disable Automatically Adjusting LOD"; const QString DisableLightEntities = "Disable Light Entities"; const QString DisableNackPackets = "Disable NACK Packets"; const QString DiskCacheEditor = "Disk Cache Editor"; diff --git a/interface/src/ui/LodToolsDialog.cpp b/interface/src/ui/LodToolsDialog.cpp index 277d634735..af434d5565 100644 --- a/interface/src/ui/LodToolsDialog.cpp +++ b/interface/src/ui/LodToolsDialog.cpp @@ -35,9 +35,51 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : // Create layouter QFormLayout* form = new QFormLayout(this); + // Create a label with feedback... + _feedback = new QLabel(this); + QPalette palette = _feedback->palette(); + const unsigned redish = 0xfff00000; + palette.setColor(QPalette::WindowText, QColor::fromRgb(redish)); + _feedback->setPalette(palette); + _feedback->setText(lodManager->getLODFeedbackText()); + const int FEEDBACK_WIDTH = 350; + _feedback->setFixedWidth(FEEDBACK_WIDTH); + form->addRow("You can see... ", _feedback); + + form->addRow("Automatic LOD Adjustment:", _automaticLODAdjust = new QCheckBox(this)); + _automaticLODAdjust->setChecked(lodManager->getAutomaticLODAdjust()); + connect(_automaticLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust())); + + form->addRow("Desktop Decrease LOD Below FPS:", _desktopLODDecreaseFPS = new QDoubleSpinBox(this)); + _desktopLODDecreaseFPS->setValue(lodManager->getDesktopLODDecreaseFPS()); + _desktopLODDecreaseFPS->setDecimals(0); + connect(_desktopLODDecreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues())); + + form->addRow("Desktop Increase LOD Above FPS:", _desktopLODIncreaseFPS = new QDoubleSpinBox(this)); + _desktopLODIncreaseFPS->setValue(lodManager->getDesktopLODIncreaseFPS()); + _desktopLODIncreaseFPS->setDecimals(0); + connect(_desktopLODIncreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues())); + + form->addRow("HMD Decrease LOD Below FPS:", _hmdLODDecreaseFPS = new QDoubleSpinBox(this)); + _hmdLODDecreaseFPS->setValue(lodManager->getHMDLODDecreaseFPS()); + _hmdLODDecreaseFPS->setDecimals(0); + connect(_hmdLODDecreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues())); + + form->addRow("HMD Increase LOD Above FPS:", _hmdLODIncreaseFPS = new QDoubleSpinBox(this)); + _hmdLODIncreaseFPS->setValue(lodManager->getHMDLODIncreaseFPS()); + _hmdLODIncreaseFPS->setDecimals(0); + connect(_hmdLODIncreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues())); + + form->addRow("Avatar LOD:", _avatarLOD = new QDoubleSpinBox(this)); + _avatarLOD->setDecimals(3); + _avatarLOD->setRange(1.0 / MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, 1.0 / MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER); + _avatarLOD->setSingleStep(0.001); + _avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier()); + connect(_avatarLOD, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues())); + _lodSize = new QSlider(Qt::Horizontal, this); const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER; - const int MIN_LOD_SIZE = 0; + const int MIN_LOD_SIZE = ADJUST_LOD_MIN_SIZE_SCALE; const int STEP_LOD_SIZE = 1; const int PAGE_STEP_LOD_SIZE = 100; const int SLIDER_WIDTH = 300; @@ -50,55 +92,8 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : _lodSize->setPageStep(PAGE_STEP_LOD_SIZE); int sliderValue = lodManager->getOctreeSizeScale() / TREE_SCALE; _lodSize->setValue(sliderValue); - form->addRow("LOD Size Scale:", _lodSize); + form->addRow("Non-Avatar Content LOD:", _lodSize); connect(_lodSize,SIGNAL(valueChanged(int)),this,SLOT(sizeScaleValueChanged(int))); - - _boundaryLevelAdjust = new QSlider(Qt::Horizontal, this); - const int MAX_ADJUST = 10; - const int MIN_ADJUST = 0; - const int STEP_ADJUST = 1; - _boundaryLevelAdjust->setMaximum(MAX_ADJUST); - _boundaryLevelAdjust->setMinimum(MIN_ADJUST); - _boundaryLevelAdjust->setSingleStep(STEP_ADJUST); - _boundaryLevelAdjust->setTickInterval(STEP_ADJUST); - _boundaryLevelAdjust->setTickPosition(QSlider::TicksBelow); - _boundaryLevelAdjust->setFixedWidth(SLIDER_WIDTH); - sliderValue = lodManager->getBoundaryLevelAdjust(); - _boundaryLevelAdjust->setValue(sliderValue); - form->addRow("Boundary Level Adjust:", _boundaryLevelAdjust); - connect(_boundaryLevelAdjust,SIGNAL(valueChanged(int)),this,SLOT(boundaryLevelValueChanged(int))); - - // Create a label with feedback... - _feedback = new QLabel(this); - QPalette palette = _feedback->palette(); - const unsigned redish = 0xfff00000; - palette.setColor(QPalette::WindowText, QColor::fromRgb(redish)); - _feedback->setPalette(palette); - _feedback->setText(lodManager->getLODFeedbackText()); - const int FEEDBACK_WIDTH = 350; - _feedback->setFixedWidth(FEEDBACK_WIDTH); - form->addRow("You can see... ", _feedback); - - form->addRow("Automatic Avatar LOD Adjustment:", _automaticAvatarLOD = new QCheckBox(this)); - _automaticAvatarLOD->setChecked(lodManager->getAutomaticAvatarLOD()); - connect(_automaticAvatarLOD, SIGNAL(toggled(bool)), SLOT(updateAvatarLODControls())); - - form->addRow("Decrease Avatar LOD Below FPS:", _avatarLODDecreaseFPS = new QDoubleSpinBox(this)); - _avatarLODDecreaseFPS->setValue(lodManager->getAvatarLODDecreaseFPS()); - _avatarLODDecreaseFPS->setDecimals(0); - connect(_avatarLODDecreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues())); - - form->addRow("Increase Avatar LOD Above FPS:", _avatarLODIncreaseFPS = new QDoubleSpinBox(this)); - _avatarLODIncreaseFPS->setValue(lodManager->getAvatarLODIncreaseFPS()); - _avatarLODIncreaseFPS->setDecimals(0); - connect(_avatarLODIncreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues())); - - form->addRow("Avatar LOD:", _avatarLOD = new QDoubleSpinBox(this)); - _avatarLOD->setDecimals(3); - _avatarLOD->setRange(1.0 / MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, 1.0 / MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER); - _avatarLOD->setSingleStep(0.001); - _avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier()); - connect(_avatarLOD, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues())); // Add a button to reset QPushButton* resetButton = new QPushButton("Reset", this); @@ -107,49 +102,34 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : this->QDialog::setLayout(form); - updateAvatarLODControls(); + updateAutomaticLODAdjust(); } void LodToolsDialog::reloadSliders() { auto lodManager = DependencyManager::get<LODManager>(); _lodSize->setValue(lodManager->getOctreeSizeScale() / TREE_SCALE); - _boundaryLevelAdjust->setValue(lodManager->getBoundaryLevelAdjust()); _feedback->setText(lodManager->getLODFeedbackText()); + + _avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier()); + } -void LodToolsDialog::updateAvatarLODControls() { - QFormLayout* form = static_cast<QFormLayout*>(layout()); - +void LodToolsDialog::updateAutomaticLODAdjust() { auto lodManager = DependencyManager::get<LODManager>(); - lodManager->setAutomaticAvatarLOD(_automaticAvatarLOD->isChecked()); - - _avatarLODDecreaseFPS->setVisible(_automaticAvatarLOD->isChecked()); - form->labelForField(_avatarLODDecreaseFPS)->setVisible(_automaticAvatarLOD->isChecked()); - - _avatarLODIncreaseFPS->setVisible(_automaticAvatarLOD->isChecked()); - form->labelForField(_avatarLODIncreaseFPS)->setVisible(_automaticAvatarLOD->isChecked()); - - _avatarLOD->setVisible(!_automaticAvatarLOD->isChecked()); - form->labelForField(_avatarLOD)->setVisible(!_automaticAvatarLOD->isChecked()); - - if (!_automaticAvatarLOD->isChecked()) { - _avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier()); - } - - if (isVisible()) { - adjustSize(); - } + lodManager->setAutomaticLODAdjust(_automaticLODAdjust->isChecked()); } -void LodToolsDialog::updateAvatarLODValues() { +void LodToolsDialog::updateLODValues() { auto lodManager = DependencyManager::get<LODManager>(); - if (_automaticAvatarLOD->isChecked()) { - lodManager->setAvatarLODDecreaseFPS(_avatarLODDecreaseFPS->value()); - lodManager->setAvatarLODIncreaseFPS(_avatarLODIncreaseFPS->value()); - - } else { - lodManager->setAvatarLODDistanceMultiplier(1.0 / _avatarLOD->value()); - } + + lodManager->setAutomaticLODAdjust(_automaticLODAdjust->isChecked()); + + lodManager->setDesktopLODDecreaseFPS(_desktopLODDecreaseFPS->value()); + lodManager->setDesktopLODIncreaseFPS(_desktopLODIncreaseFPS->value()); + lodManager->setHMDLODDecreaseFPS(_hmdLODDecreaseFPS->value()); + lodManager->setHMDLODIncreaseFPS(_hmdLODIncreaseFPS->value()); + + lodManager->setAvatarLODDistanceMultiplier(1.0 / _avatarLOD->value()); } void LodToolsDialog::sizeScaleValueChanged(int value) { @@ -160,20 +140,19 @@ void LodToolsDialog::sizeScaleValueChanged(int value) { _feedback->setText(lodManager->getLODFeedbackText()); } -void LodToolsDialog::boundaryLevelValueChanged(int value) { - auto lodManager = DependencyManager::get<LODManager>(); - lodManager->setBoundaryLevelAdjust(value); - _feedback->setText(lodManager->getLODFeedbackText()); -} - void LodToolsDialog::resetClicked(bool checked) { + int sliderValue = DEFAULT_OCTREE_SIZE_SCALE / TREE_SCALE; - //sizeScaleValueChanged(sliderValue); _lodSize->setValue(sliderValue); - _boundaryLevelAdjust->setValue(0); - _automaticAvatarLOD->setChecked(true); - _avatarLODDecreaseFPS->setValue(DEFAULT_ADJUST_AVATAR_LOD_DOWN_FPS); - _avatarLODIncreaseFPS->setValue(ADJUST_LOD_UP_FPS); + _automaticLODAdjust->setChecked(true); + _desktopLODDecreaseFPS->setValue(DEFAULT_DESKTOP_LOD_DOWN_FPS); + _desktopLODIncreaseFPS->setValue(DEFAULT_DESKTOP_LOD_UP_FPS); + _hmdLODDecreaseFPS->setValue(DEFAULT_HMD_LOD_DOWN_FPS); + _hmdLODIncreaseFPS->setValue(DEFAULT_HMD_LOD_UP_FPS); + + _avatarLOD->setValue(1.0 / DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER); + + updateLODValues(); // tell our LOD manager about the reset } void LodToolsDialog::reject() { diff --git a/interface/src/ui/LodToolsDialog.h b/interface/src/ui/LodToolsDialog.h index 772027790c..2e85b3f5a5 100644 --- a/interface/src/ui/LodToolsDialog.h +++ b/interface/src/ui/LodToolsDialog.h @@ -31,11 +31,10 @@ signals: public slots: void reject(); void sizeScaleValueChanged(int value); - void boundaryLevelValueChanged(int value); void resetClicked(bool checked); void reloadSliders(); - void updateAvatarLODControls(); - void updateAvatarLODValues(); + void updateAutomaticLODAdjust(); + void updateLODValues(); protected: @@ -44,10 +43,16 @@ protected: private: QSlider* _lodSize; - QSlider* _boundaryLevelAdjust; - QCheckBox* _automaticAvatarLOD; - QDoubleSpinBox* _avatarLODDecreaseFPS; - QDoubleSpinBox* _avatarLODIncreaseFPS; + + QCheckBox* _automaticLODAdjust; + + QDoubleSpinBox* _desktopLODDecreaseFPS; + QDoubleSpinBox* _desktopLODIncreaseFPS; + + QDoubleSpinBox* _hmdLODDecreaseFPS; + QDoubleSpinBox* _hmdLODIncreaseFPS; + + QDoubleSpinBox* _avatarLOD; QLabel* _feedback; }; From 69f261ae943de395bd3ef27eec684f334554b63d Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Mon, 23 Mar 2015 16:44:19 -0700 Subject: [PATCH 064/177] tweaks to the LOD Tools UI --- libraries/octree/src/OctreeConstants.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/octree/src/OctreeConstants.h b/libraries/octree/src/OctreeConstants.h index a975469053..1246aeffd4 100644 --- a/libraries/octree/src/OctreeConstants.h +++ b/libraries/octree/src/OctreeConstants.h @@ -23,7 +23,7 @@ const int TREE_SCALE = 16384; // ~10 miles.. This is the number of meters of t const float DEFAULT_OCTREE_SIZE_SCALE = TREE_SCALE * 400.0f; // This is used in the LOD Tools to translate between the size scale slider and the values used to set the OctreeSizeScale -const float MAX_LOD_SIZE_MULTIPLIER = 2000.0f; +const float MAX_LOD_SIZE_MULTIPLIER = 800.0f; const int NUMBER_OF_CHILDREN = 8; From c8ad82917e974d23c08d9732e8195cee0fc6d0e4 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Mon, 23 Mar 2015 16:54:36 -0700 Subject: [PATCH 065/177] clean up some debugging spew. take dimensions into account when scaling points used for collision hull creation --- .../src/RenderableModelEntityItem.cpp | 47 +++++++++++++++++-- .../src/RenderableModelEntityItem.h | 2 + libraries/entities/src/EntityItem.h | 11 ++++- libraries/physics/src/ShapeInfoUtil.cpp | 15 ++---- libraries/shared/src/ShapeInfo.cpp | 7 +++ 5 files changed, 64 insertions(+), 18 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 86332c8c07..bb3f00d154 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -266,6 +266,14 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking); } +void RenderableModelEntityItem::updateDimensions(const glm::vec3& value) { + if (glm::distance(_dimensions, value) > MIN_DIMENSIONS_DELTA) { + _dimensions = value; + _dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS); + } + _model->setScaleToFit(true, _dimensions); +} + bool RenderableModelEntityItem::isReadyToComputeShape() { if (!_model) { @@ -294,6 +302,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry(); const FBXGeometry& fbxGeometry = collisionNetworkGeometry->getFBXGeometry(); + AABox aaBox; _points.clear(); unsigned int i = 0; foreach (const FBXMesh& mesh, fbxGeometry.meshes) { @@ -301,15 +310,29 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { foreach (const FBXMeshPart &meshPart, mesh.parts) { QVector<glm::vec3> pointsInPart; unsigned int triangleCount = meshPart.triangleIndices.size() / 3; - for (unsigned int i = 0; i < triangleCount; i++) { - unsigned int p0Index = meshPart.triangleIndices[i*3]; - unsigned int p1Index = meshPart.triangleIndices[i*3+1]; - unsigned int p2Index = meshPart.triangleIndices[i*3+2]; + assert((unsigned int)meshPart.triangleIndices.size() == triangleCount*3); + for (unsigned int j = 0; j < triangleCount; j++) { + unsigned int p0Index = meshPart.triangleIndices[j*3]; + unsigned int p1Index = meshPart.triangleIndices[j*3+1]; + unsigned int p2Index = meshPart.triangleIndices[j*3+2]; + + assert(p0Index < (unsigned int)mesh.vertices.size()); + assert(p1Index < (unsigned int)mesh.vertices.size()); + assert(p2Index < (unsigned int)mesh.vertices.size()); + + // glm::vec3 p0 = mesh.vertices[p0Index] * scale[0]; + // glm::vec3 p1 = mesh.vertices[p1Index] * scale[1]; + // glm::vec3 p2 = mesh.vertices[p2Index] * scale[2]; + glm::vec3 p0 = mesh.vertices[p0Index]; glm::vec3 p1 = mesh.vertices[p1Index]; glm::vec3 p2 = mesh.vertices[p2Index]; + aaBox += p0; + aaBox += p1; + aaBox += p2; + if (!pointsInPart.contains(p0)) { pointsInPart << p0; } @@ -327,7 +350,21 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { } } - info.setParams(getShapeType(), 0.5f * getDimensions(), _collisionModelURL); + // make sure we aren't about to divide by zero + glm::vec3 aaBoxDim = aaBox.getDimensions(); + aaBoxDim = glm::clamp(aaBoxDim, glm::vec3(FLT_EPSILON), aaBoxDim); + + // scale = dimensions / aabox + glm::vec3 scale = _dimensions / aaBoxDim; + + // multiply each point by scale before handing the point-set off to the physics engine + for (int i = 0; i < _points.size(); i++) { + for (int j = 0; j < _points[i].size(); j++) { + _points[i][j] *= scale; + } + } + + info.setParams(getShapeType(), _dimensions, _collisionModelURL); info.setConvexHulls(_points); } } diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 63249f136c..8742fb50eb 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -52,6 +52,8 @@ public: bool needsToCallUpdate() const; + virtual void updateDimensions(const glm::vec3& value); + bool isReadyToComputeShape(); void computeShapeInfo(ShapeInfo& info); ShapeType getShapeType() const; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 88287f8965..49e450c45e 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -40,6 +40,15 @@ class EntityTreeElementExtraEncodeData; #define debugTreeVector(V) V << "[" << V << " in meters ]" +extern const float MIN_POSITION_DELTA; +extern const float MIN_DIMENSIONS_DELTA; +extern const float MIN_ALIGNMENT_DOT; +extern const float MIN_VELOCITY_DELTA; +extern const float MIN_DAMPING_DELTA; +extern const float MIN_GRAVITY_DELTA; +extern const float MIN_SPIN_DELTA; + + /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. @@ -270,7 +279,7 @@ public: void updatePositionInDomainUnits(const glm::vec3& value); void updatePosition(const glm::vec3& value); void updateDimensionsInDomainUnits(const glm::vec3& value); - void updateDimensions(const glm::vec3& value); + virtual void updateDimensions(const glm::vec3& value); void updateRotation(const glm::quat& rotation); void updateDensity(float value); void updateMass(float value); diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp index 07fedb35ad..1073fbae3f 100644 --- a/libraries/physics/src/ShapeInfoUtil.cpp +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -77,10 +77,12 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf const int numPoints = convexHullShape->getNumPoints(); const btVector3* btPoints = convexHullShape->getUnscaledPoints(); QVector<QVector<glm::vec3>> points; + QVector<glm::vec3> childPoints; for (int i = 0; i < numPoints; i++) { glm::vec3 point(btPoints->getX(), btPoints->getY(), btPoints->getZ()); - points[0] << point; + childPoints << point; } + points << childPoints; info.setConvexHulls(points); } break; @@ -116,9 +118,6 @@ void ShapeInfoUtil::collectInfoFromShape(const btCollisionShape* shape, ShapeInf btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { btCollisionShape* shape = NULL; - - qDebug() << "\n\nHERE" << info.getType(); - switch(info.getType()) { case SHAPE_TYPE_BOX: { shape = new btBoxShape(glmToBullet(info.getHalfExtents())); @@ -149,13 +148,8 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { shape = new btCompoundShape(); const QVector<QVector<glm::vec3>>& points = info.getPoints(); - qDebug() << "\n\nSHAPE_TYPE_COMPOUND" << info.getPoints().size() << "hulls."; - foreach (QVector<glm::vec3> hullPoints, info.getPoints()) { auto hull = new btConvexHullShape(); - - qDebug() << " SHAPE_TYPE_COMPOUND" << hullPoints.size() << "points in hull."; - foreach (glm::vec3 point, hullPoints) { btVector3 btPoint(point[0], point[1], point[2]); hull->addPoint(btPoint); @@ -165,9 +159,6 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { static_cast<btCompoundShape*>(shape)->addChildShape (trans, hull); } } - - qDebug() << "DONE, getNumChildShapes =" << static_cast<btCompoundShape*>(shape)->getNumChildShapes(); - break; } return shape; diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 09677cf36c..73dd945f73 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -38,6 +38,8 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString } case SHAPE_TYPE_CONVEX_HULL: _url = QUrl(url); + // halfExtents aren't used by convex-hull or compound convex-hull except as part of + // the generation of the key for the ShapeManager. _halfExtents = halfExtents; break; case SHAPE_TYPE_COMPOUND: @@ -51,18 +53,21 @@ void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString } void ShapeInfo::setBox(const glm::vec3& halfExtents) { + _url = ""; _type = SHAPE_TYPE_BOX; _halfExtents = halfExtents; _doubleHashKey.clear(); } void ShapeInfo::setSphere(float radius) { + _url = ""; _type = SHAPE_TYPE_SPHERE; _halfExtents = glm::vec3(radius, radius, radius); _doubleHashKey.clear(); } void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) { + _url = ""; _type = SHAPE_TYPE_ELLIPSOID; _halfExtents = halfExtents; _doubleHashKey.clear(); @@ -75,9 +80,11 @@ void ShapeInfo::setConvexHulls(const QVector<QVector<glm::vec3>>& points) { _type = SHAPE_TYPE_COMPOUND; } _points = points; + _doubleHashKey.clear(); } void ShapeInfo::setCapsuleY(float radius, float halfHeight) { + _url = ""; _type = SHAPE_TYPE_CAPSULE_Y; _halfExtents = glm::vec3(radius, halfHeight, radius); _doubleHashKey.clear(); From 168e8e8b808f6c03af5c1f0653fe71d252044266 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Tue, 24 Mar 2015 08:31:45 -0700 Subject: [PATCH 066/177] more fixes to avatar parts not rendering --- libraries/render-utils/src/Model.cpp | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index d640876086..873f458ccf 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -725,7 +725,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { const float DEFAULT_ALPHA_THRESHOLD = 0.5f; - //renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, book isSkinned, args); + //renderMeshes(batch, mode, translucent, alphaThreshold, hasTangents, hasSpecular, isSkinned, args, forceRenderMeshes); int opaqueMeshPartsRendered = 0; opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, false, args, true); opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, true, args, true); @@ -753,14 +753,14 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { int translucentMeshPartsRendered = 0; const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args, true); GLBATCH(glDisable)(GL_ALPHA_TEST); GLBATCH(glEnable)(GL_BLEND); @@ -777,14 +777,14 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, args, true); } GLBATCH(glDepthMask)(true); From a9e4d25f97ea27178b0622d0cc2774f8c846272d Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Tue, 24 Mar 2015 08:31:45 -0700 Subject: [PATCH 067/177] more fixes to avatar parts not rendering --- libraries/render-utils/src/Model.cpp | 34 ++++++++++++++-------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index d640876086..873f458ccf 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -725,7 +725,7 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { const float DEFAULT_ALPHA_THRESHOLD = 0.5f; - //renderMeshes(RenderMode mode, bool translucent, float alphaThreshold, bool hasTangents, bool hasSpecular, book isSkinned, args); + //renderMeshes(batch, mode, translucent, alphaThreshold, hasTangents, hasSpecular, isSkinned, args, forceRenderMeshes); int opaqueMeshPartsRendered = 0; opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, false, args, true); opaqueMeshPartsRendered += renderMeshes(batch, mode, false, DEFAULT_ALPHA_THRESHOLD, false, false, false, true, args, true); @@ -753,14 +753,14 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { int translucentMeshPartsRendered = 0; const float MOSTLY_OPAQUE_THRESHOLD = 0.75f; - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, false, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, false, true, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, false, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_OPAQUE_THRESHOLD, false, true, true, true, args, true); GLBATCH(glDisable)(GL_ALPHA_TEST); GLBATCH(glEnable)(GL_BLEND); @@ -777,14 +777,14 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) { if (mode == DEFAULT_RENDER_MODE || mode == DIFFUSE_RENDER_MODE) { const float MOSTLY_TRANSPARENT_THRESHOLD = 0.0f; - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, args); - translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, args); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, false, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, false, true, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, false, true, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, false, args, true); + translucentMeshPartsRendered += renderMeshes(batch, mode, true, MOSTLY_TRANSPARENT_THRESHOLD, false, true, true, true, args, true); } GLBATCH(glDepthMask)(true); From 6d932508ffbe66ddd9e2fe1066868f3d0e0b1e96 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Tue, 24 Mar 2015 10:27:53 -0700 Subject: [PATCH 068/177] Add support for .svo.json extension --- interface/src/Application.h | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.h b/interface/src/Application.h index 4038b21739..6e0c3cebd2 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -95,6 +95,7 @@ static const float NODE_KILLED_BLUE = 0.0f; static const QString SNAPSHOT_EXTENSION = ".jpg"; static const QString SVO_EXTENSION = ".svo"; +static const QString SVO_JSON_EXTENSION = ".svo.json"; static const QString JS_EXTENSION = ".js"; static const QString FST_EXTENSION = ".fst"; From a901bc4b11ba199879cafa6b766012b44deab33f Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Tue, 24 Mar 2015 10:28:12 -0700 Subject: [PATCH 069/177] Update edit.js to export as .svo.json --- examples/edit.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 72938e5ed4..2179fe5342 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -910,8 +910,8 @@ function handeMenuEvent(menuItem) { if (!selectionManager.hasSelection()) { Window.alert("No entities have been selected."); } else { - var filename = "models__" + Window.location.hostname + "__.svo"; - filename = Window.save("Select where to save", filename, "*.svo") + var filename = "entities__" + Window.location.hostname + ".svo.json"; + filename = Window.save("Select where to save", filename, "*.json") if (filename) { var success = Clipboard.exportEntities(filename, selectionManager.selections); if (!success) { @@ -923,7 +923,7 @@ function handeMenuEvent(menuItem) { var importURL; if (menuItem == "Import Entities") { - importURL = Window.browse("Select models to import", "", "*.svo"); + importURL = Window.browse("Select models to import", "", "*.json"); } else { importURL = Window.prompt("URL of SVO to import", ""); } From 2fc0ef80d0eb4b42521355b058d04e880c0378aa Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Tue, 24 Mar 2015 10:40:46 -0700 Subject: [PATCH 070/177] Add SVO_JSON_EXTENSION to accepted extensions --- interface/src/Application.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 840e8388c7..cf9d583945 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3599,6 +3599,7 @@ void Application::initializeAcceptedFiles() { if (_acceptedExtensions.size() == 0) { _acceptedExtensions[SNAPSHOT_EXTENSION] = &Application::acceptSnapshot; _acceptedExtensions[SVO_EXTENSION] = &Application::importSVOFromURL; + _acceptedExtensions[SVO_JSON_EXTENSION] = &Application::importSVOFromURL; _acceptedExtensions[JS_EXTENSION] = &Application::askToLoadScript; _acceptedExtensions[FST_EXTENSION] = &Application::askToSetAvatarUrl; } From faa47da57e829196595c55ff5b2505b3c81303ff Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Tue, 24 Mar 2015 11:49:29 -0700 Subject: [PATCH 071/177] update version of TBB external project --- cmake/externals/tbb/CMakeLists.txt | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/cmake/externals/tbb/CMakeLists.txt b/cmake/externals/tbb/CMakeLists.txt index 06da60ac04..54a73dafb8 100644 --- a/cmake/externals/tbb/CMakeLists.txt +++ b/cmake/externals/tbb/CMakeLists.txt @@ -8,8 +8,8 @@ if (ANDROID) ExternalProject_Add( ${EXTERNAL_NAME} - URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150209oss_src.tgz - URL_MD5 f09c9abe8ec74e6558c1f89cebbe2893 + URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_src.tgz + URL_MD5 bf090eaa86cf89ea014b7b462786a440 BUILD_COMMAND ${NDK_BUILD_COMMAND} --directory=jni target=android tbb tbbmalloc arch=arm BUILD_IN_SOURCE 1 CONFIGURE_COMMAND "" @@ -20,19 +20,20 @@ if (ANDROID) ) else () if (APPLE) - set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_osx.tgz) - set(DOWNLOAD_MD5 3e683c19792582b61382e0d760ea5db2) + set(DOWNLOAD_URL http://hifi-public.s3.amazonaws.com/dependencies/tbb43_20150316oss_osx.tgz) + set(DOWNLOAD_MD5 25a36ebff070ff801760ec658079f6aa) elseif (WIN32) - set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_win.zip) - set(DOWNLOAD_MD5 e19c184f2bb0e944fc5f397f1e34ca84) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_win.zip) + set(DOWNLOAD_MD5 d250d40bb93b255f75bcbb19e976a440) else () - set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150209oss_lin.tgz) - set(DOWNLOAD_MD5 d9c2a6f7807df364be44a8c3c05e8457) + set(DOWNLOAD_URL http://s3.amazonaws.com/hifi-public/dependencies/tbb43_20150316oss_lin.tgz) + set(DOWNLOAD_MD5 7830ba2bc62438325fba2ec0c95367a5) endif () ExternalProject_Add( ${EXTERNAL_NAME} URL ${DOWNLOAD_URL} + URL_MD5 ${DOWNLOAD_MD5} BUILD_COMMAND "" CONFIGURE_COMMAND "" INSTALL_COMMAND "" From 1a6865b41bfe2600bc8b5e7be777d23fa6d40612 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Tue, 24 Mar 2015 12:26:32 -0700 Subject: [PATCH 072/177] send immediate location update when domain changes --- interface/src/Application.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ad6a0d86ce..c21d221303 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -382,6 +382,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : auto discoverabilityManager = DependencyManager::get<DiscoverabilityManager>(); connect(locationUpdateTimer, &QTimer::timeout, discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); locationUpdateTimer->start(DATA_SERVER_LOCATION_CHANGE_UPDATE_MSECS); + + // if we get a domain change, immediately attempt update location in metaverse server + connect(&nodeList->getDomainHandler(), &DomainHandler::connectedToDomain, + discoverabilityManager.data(), &DiscoverabilityManager::updateLocation); connect(nodeList.data(), &NodeList::nodeAdded, this, &Application::nodeAdded); connect(nodeList.data(), &NodeList::nodeKilled, this, &Application::nodeKilled); @@ -3295,11 +3299,6 @@ void Application::connectedToDomain(const QString& hostname) { const QUuid& domainID = DependencyManager::get<NodeList>()->getDomainHandler().getUUID(); if (accountManager.isLoggedIn() && !domainID.isNull()) { - // update our data-server with the domain-server we're logged in with - QString domainPutJsonString = "{\"location\":{\"domain_id\":\"" + uuidStringWithoutCurlyBraces(domainID) + "\"}}"; - accountManager.authenticatedRequest("/api/v1/user/location", QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), domainPutJsonString.toUtf8()); - _notifiedPacketVersionMismatchThisDomain = false; } } From 619428c325864f361c9b9ba17c31733c171ebc85 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Tue, 24 Mar 2015 13:32:22 -0700 Subject: [PATCH 073/177] move LOD FPS settings to Preferences --- interface/src/Application.cpp | 2 + interface/src/LODManager.cpp | 9 - interface/src/LODManager.h | 11 +- interface/src/ui/LodToolsDialog.cpp | 31 ---- interface/src/ui/LodToolsDialog.h | 2 - interface/src/ui/PreferencesDialog.cpp | 10 ++ interface/ui/preferencesDialog.ui | 218 +++++++++++++++++++++++++ 7 files changed, 233 insertions(+), 50 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index ad6a0d86ce..daf2a76f5f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1786,6 +1786,7 @@ bool Application::exportEntities(const QString& filename, float x, float y, floa void Application::loadSettings() { DependencyManager::get<AudioClient>()->loadSettings(); + DependencyManager::get<LODManager>()->loadSettings(); Menu::getInstance()->loadSettings(); _myAvatar->loadData(); @@ -1793,6 +1794,7 @@ void Application::loadSettings() { void Application::saveSettings() { DependencyManager::get<AudioClient>()->saveSettings(); + DependencyManager::get<LODManager>()->saveSettings(); Menu::getInstance()->saveSettings(); _myAvatar->saveData(); diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 739e5f280a..5c55952e3a 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -17,11 +17,8 @@ #include "LODManager.h" -Setting::Handle<bool> automaticLODAdjust("automaticLODAdjust", true); Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS); -Setting::Handle<float> desktopLODIncreaseFPS("desktopLODIncreaseFPS", DEFAULT_DESKTOP_LOD_UP_FPS); Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS); -Setting::Handle<float> hmdLODIncreaseFPS("hmdLODIncreaseFPS", DEFAULT_HMD_LOD_UP_FPS); Setting::Handle<float> avatarLODDistanceMultiplier("avatarLODDistanceMultiplier", @@ -244,11 +241,8 @@ void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) { void LODManager::loadSettings() { - setAutomaticLODAdjust(automaticLODAdjust.get()); setDesktopLODDecreaseFPS(desktopLODDecreaseFPS.get()); - setDesktopLODIncreaseFPS(desktopLODIncreaseFPS.get()); setHMDLODDecreaseFPS(hmdLODDecreaseFPS.get()); - setHMDLODIncreaseFPS(hmdLODIncreaseFPS.get()); setAvatarLODDistanceMultiplier(avatarLODDistanceMultiplier.get()); setBoundaryLevelAdjust(boundaryLevelAdjust.get()); @@ -256,11 +250,8 @@ void LODManager::loadSettings() { } void LODManager::saveSettings() { - automaticLODAdjust.set(getAutomaticLODAdjust()); desktopLODDecreaseFPS.set(getDesktopLODDecreaseFPS()); - desktopLODIncreaseFPS.set(getDesktopLODIncreaseFPS()); hmdLODDecreaseFPS.set(getHMDLODDecreaseFPS()); - hmdLODIncreaseFPS.set(getHMDLODIncreaseFPS()); avatarLODDistanceMultiplier.set(getAvatarLODDistanceMultiplier()); boundaryLevelAdjust.set(getBoundaryLevelAdjust()); diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 57b03cba42..7d63fbd172 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -18,9 +18,8 @@ #include <SimpleMovingAverage.h> const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0; -const float DEFAULT_DESKTOP_LOD_UP_FPS = 50.0; const float DEFAULT_HMD_LOD_DOWN_FPS = 60.0; -const float DEFAULT_HMD_LOD_UP_FPS = 65.0; +const float INCREASE_LOD_GAP = 5.0f; const quint64 ADJUST_LOD_DOWN_DELAY = 1000 * 1000 * 0.5; // Consider adjusting LOD down after half a second const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2; @@ -53,13 +52,11 @@ public: Q_INVOKABLE void setDesktopLODDecreaseFPS(float value) { _desktopLODDecreaseFPS = value; } Q_INVOKABLE float getDesktopLODDecreaseFPS() const { return _desktopLODDecreaseFPS; } - Q_INVOKABLE void setDesktopLODIncreaseFPS(float value) { _desktopLODIncreaseFPS = value; } - Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return _desktopLODIncreaseFPS; } + Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return _desktopLODDecreaseFPS + INCREASE_LOD_GAP; } Q_INVOKABLE void setHMDLODDecreaseFPS(float value) { _hmdLODDecreaseFPS = value; } Q_INVOKABLE float getHMDLODDecreaseFPS() const { return _hmdLODDecreaseFPS; } - Q_INVOKABLE void setHMDLODIncreaseFPS(float value) { _hmdLODIncreaseFPS = value; } - Q_INVOKABLE float getHMDLODIncreaseFPS() const { return _hmdLODIncreaseFPS; } + Q_INVOKABLE float getHMDLODIncreaseFPS() const { return _hmdLODDecreaseFPS + INCREASE_LOD_GAP; } Q_INVOKABLE void setAvatarLODDistanceMultiplier(float multiplier) { _avatarLODDistanceMultiplier = multiplier; } Q_INVOKABLE float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; } @@ -94,9 +91,7 @@ private: bool _automaticLODAdjust = true; float _desktopLODDecreaseFPS = DEFAULT_DESKTOP_LOD_DOWN_FPS; - float _desktopLODIncreaseFPS = DEFAULT_DESKTOP_LOD_UP_FPS; float _hmdLODDecreaseFPS = DEFAULT_HMD_LOD_DOWN_FPS; - float _hmdLODIncreaseFPS = DEFAULT_HMD_LOD_UP_FPS; float _avatarLODDistanceMultiplier = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER; diff --git a/interface/src/ui/LodToolsDialog.cpp b/interface/src/ui/LodToolsDialog.cpp index af434d5565..7635012bc2 100644 --- a/interface/src/ui/LodToolsDialog.cpp +++ b/interface/src/ui/LodToolsDialog.cpp @@ -50,26 +50,6 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : _automaticLODAdjust->setChecked(lodManager->getAutomaticLODAdjust()); connect(_automaticLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust())); - form->addRow("Desktop Decrease LOD Below FPS:", _desktopLODDecreaseFPS = new QDoubleSpinBox(this)); - _desktopLODDecreaseFPS->setValue(lodManager->getDesktopLODDecreaseFPS()); - _desktopLODDecreaseFPS->setDecimals(0); - connect(_desktopLODDecreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues())); - - form->addRow("Desktop Increase LOD Above FPS:", _desktopLODIncreaseFPS = new QDoubleSpinBox(this)); - _desktopLODIncreaseFPS->setValue(lodManager->getDesktopLODIncreaseFPS()); - _desktopLODIncreaseFPS->setDecimals(0); - connect(_desktopLODIncreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues())); - - form->addRow("HMD Decrease LOD Below FPS:", _hmdLODDecreaseFPS = new QDoubleSpinBox(this)); - _hmdLODDecreaseFPS->setValue(lodManager->getHMDLODDecreaseFPS()); - _hmdLODDecreaseFPS->setDecimals(0); - connect(_hmdLODDecreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues())); - - form->addRow("HMD Increase LOD Above FPS:", _hmdLODIncreaseFPS = new QDoubleSpinBox(this)); - _hmdLODIncreaseFPS->setValue(lodManager->getHMDLODIncreaseFPS()); - _hmdLODIncreaseFPS->setDecimals(0); - connect(_hmdLODIncreaseFPS, SIGNAL(valueChanged(double)), SLOT(updateLODValues())); - form->addRow("Avatar LOD:", _avatarLOD = new QDoubleSpinBox(this)); _avatarLOD->setDecimals(3); _avatarLOD->setRange(1.0 / MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, 1.0 / MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER); @@ -123,12 +103,6 @@ void LodToolsDialog::updateLODValues() { auto lodManager = DependencyManager::get<LODManager>(); lodManager->setAutomaticLODAdjust(_automaticLODAdjust->isChecked()); - - lodManager->setDesktopLODDecreaseFPS(_desktopLODDecreaseFPS->value()); - lodManager->setDesktopLODIncreaseFPS(_desktopLODIncreaseFPS->value()); - lodManager->setHMDLODDecreaseFPS(_hmdLODDecreaseFPS->value()); - lodManager->setHMDLODIncreaseFPS(_hmdLODIncreaseFPS->value()); - lodManager->setAvatarLODDistanceMultiplier(1.0 / _avatarLOD->value()); } @@ -145,11 +119,6 @@ void LodToolsDialog::resetClicked(bool checked) { int sliderValue = DEFAULT_OCTREE_SIZE_SCALE / TREE_SCALE; _lodSize->setValue(sliderValue); _automaticLODAdjust->setChecked(true); - _desktopLODDecreaseFPS->setValue(DEFAULT_DESKTOP_LOD_DOWN_FPS); - _desktopLODIncreaseFPS->setValue(DEFAULT_DESKTOP_LOD_UP_FPS); - _hmdLODDecreaseFPS->setValue(DEFAULT_HMD_LOD_DOWN_FPS); - _hmdLODIncreaseFPS->setValue(DEFAULT_HMD_LOD_UP_FPS); - _avatarLOD->setValue(1.0 / DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER); updateLODValues(); // tell our LOD manager about the reset diff --git a/interface/src/ui/LodToolsDialog.h b/interface/src/ui/LodToolsDialog.h index 2e85b3f5a5..709357fddd 100644 --- a/interface/src/ui/LodToolsDialog.h +++ b/interface/src/ui/LodToolsDialog.h @@ -47,10 +47,8 @@ private: QCheckBox* _automaticLODAdjust; QDoubleSpinBox* _desktopLODDecreaseFPS; - QDoubleSpinBox* _desktopLODIncreaseFPS; QDoubleSpinBox* _hmdLODDecreaseFPS; - QDoubleSpinBox* _hmdLODIncreaseFPS; QDoubleSpinBox* _avatarLOD; diff --git a/interface/src/ui/PreferencesDialog.cpp b/interface/src/ui/PreferencesDialog.cpp index fa63079290..a07de371a2 100644 --- a/interface/src/ui/PreferencesDialog.cpp +++ b/interface/src/ui/PreferencesDialog.cpp @@ -19,6 +19,7 @@ #include "Application.h" #include "MainWindow.h" +#include "LODManager.h" #include "Menu.h" #include "ModelsBrowser.h" #include "PreferencesDialog.h" @@ -174,6 +175,10 @@ void PreferencesDialog::loadPreferences() { ui.sixenseReticleMoveSpeedSpin->setValue(sixense.getReticleMoveSpeed()); ui.invertSixenseButtonsCheckBox->setChecked(sixense.getInvertButtons()); + // LOD items + auto lodManager = DependencyManager::get<LODManager>(); + ui.desktopMinimumFPSSpin->setValue(lodManager->getDesktopLODDecreaseFPS()); + ui.hmdMinimumFPSSpin->setValue(lodManager->getHMDLODDecreaseFPS()); } void PreferencesDialog::savePreferences() { @@ -275,4 +280,9 @@ void PreferencesDialog::savePreferences() { audio->setOutputStarveDetectionPeriod(ui.outputStarveDetectionPeriodSpinner->value()); Application::getInstance()->resizeGL(glCanvas->width(), glCanvas->height()); + + // LOD items + auto lodManager = DependencyManager::get<LODManager>(); + lodManager->setDesktopLODDecreaseFPS(ui.desktopMinimumFPSSpin->value()); + lodManager->setHMDLODDecreaseFPS(ui.hmdMinimumFPSSpin->value()); } diff --git a/interface/ui/preferencesDialog.ui b/interface/ui/preferencesDialog.ui index 13894a2592..d295d094c2 100644 --- a/interface/ui/preferencesDialog.ui +++ b/interface/ui/preferencesDialog.ui @@ -701,6 +701,219 @@ </property> </widget> </item> + + + + <item> + <spacer name="verticalSpacer_10"> + <property name="orientation"> + <enum>Qt::Vertical</enum> + </property> + <property name="sizeType"> + <enum>QSizePolicy::Fixed</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>20</height> + </size> + </property> + </spacer> + </item> + + <item> + <widget class="QLabel" name="levelOfDetailTitleLabel"> + <property name="font"> + <font> + <family>Arial</family> + <pointsize>18</pointsize> + <weight>75</weight> + <bold>true</bold> + </font> + </property> + <property name="styleSheet"> + <string notr="true">color:#29967e</string> + </property> + <property name="text"> + <string>Level of Detail Tuning</string> + </property> + <property name="alignment"> + <set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set> + </property> + </widget> + </item> + + <item> + <layout class="QHBoxLayout" name="horizontalLayout_111x"> + <property name="spacing"> + <number>0</number> + </property> + <property name="topMargin"> + <number>7</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>7</number> + </property> + <item> + <widget class="QLabel" name="label_9x"> + <property name="font"> + <font> + <family>Arial</family> + </font> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="text"> + <string>Minimum Desktop FPS</string> + </property> + <property name="indent"> + <number>0</number> + </property> + <!-- + <property name="buddy"> + <cstring>fieldOfViewSpin</cstring> + </property> + --> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_111x"> + <property name="font"> + <font> + <family>Arial</family> + </font> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QSpinBox" name="desktopMinimumFPSSpin"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>95</width> + <height>36</height> + </size> + </property> + <property name="font"> + <font> + <family>Arial</family> + </font> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>120</number> + </property> + </widget> + </item> + </layout> + </item> + + <item> + <layout class="QHBoxLayout" name="horizontalLayout_111y"> + <property name="spacing"> + <number>0</number> + </property> + <property name="topMargin"> + <number>7</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>7</number> + </property> + <item> + <widget class="QLabel" name="label_9y"> + <property name="font"> + <font> + <family>Arial</family> + </font> + </property> + <property name="styleSheet"> + <string notr="true"/> + </property> + <property name="text"> + <string>Minimum HMD FPS</string> + </property> + <property name="indent"> + <number>0</number> + </property> + <!-- + <property name="buddy"> + <cstring>fieldOfViewSpin</cstring> + </property> + --> + </widget> + </item> + <item> + <spacer name="horizontalSpacer_111y"> + <property name="font"> + <font> + <family>Arial</family> + </font> + </property> + <property name="orientation"> + <enum>Qt::Horizontal</enum> + </property> + <property name="sizeHint" stdset="0"> + <size> + <width>0</width> + <height>0</height> + </size> + </property> + </spacer> + </item> + <item> + <widget class="QSpinBox" name="hmdMinimumFPSSpin"> + <property name="minimumSize"> + <size> + <width>100</width> + <height>0</height> + </size> + </property> + <property name="maximumSize"> + <size> + <width>95</width> + <height>36</height> + </size> + </property> + <property name="font"> + <font> + <family>Arial</family> + </font> + </property> + <property name="minimum"> + <number>0</number> + </property> + <property name="maximum"> + <number>120</number> + </property> + </widget> + </item> + </layout> + </item> + + <item> <spacer name="verticalSpacer_8"> <property name="orientation"> @@ -717,6 +930,7 @@ </property> </spacer> </item> + <item> <widget class="QLabel" name="avatarTitleLabel"> <property name="font"> @@ -738,6 +952,7 @@ </property> </widget> </item> + <item> <layout class="QHBoxLayout" name="horizontalLayout_111"> <property name="spacing"> @@ -820,6 +1035,9 @@ </item> </layout> </item> + + + <item> <layout class="QHBoxLayout" name="horizontalLayout_3"> <property name="spacing"> From 6c941d73d5a503671bc8f600273f7043ec4bb5ff Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Tue, 24 Mar 2015 13:34:14 -0700 Subject: [PATCH 074/177] Update edit.js help --- .../html/edit-entities-commands.html | 3832 +++++++++-------- 1 file changed, 1927 insertions(+), 1905 deletions(-) diff --git a/interface/resources/html/edit-entities-commands.html b/interface/resources/html/edit-entities-commands.html index afa662f089..65b985fb6a 100644 --- a/interface/resources/html/edit-entities-commands.html +++ b/interface/resources/html/edit-entities-commands.html @@ -2,2035 +2,2057 @@ <div style="width: 1053px; height: 564px; margin: 20px;"> <input type="hidden" id="version" value="1" /> <?xml version="1.0" encoding="utf-8"?> -<!-- Generator: Adobe Illustrator 18.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> +<!-- Generator: Adobe Illustrator 18.1.1, SVG Export Plug-In . SVG Version: 6.00 Build 0) --> <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> -<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" - width="1013px" height="524px" viewBox="0 0 1013 524.2" enable-background="new 0 0 1013 524.2" xml:space="preserve"> <title>Edit Entity Help</title> +<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" + width="1013px" height="524px" viewBox="0 0 1058.9 556.5" enable-background="new 0 0 1058.9 556.5" xml:space="preserve"> <g> <g> - <path fill="#078876" d="M1.8,14.6V4.2h1.6v1.5C4.2,4.5,5.3,4,6.7,4c0.6,0,1.2,0.1,1.7,0.3s0.9,0.5,1.2,0.9S10,6,10.1,6.5 - c0.1,0.3,0.1,0.9,0.1,1.7v6.4H8.5V8.3c0-0.7-0.1-1.3-0.2-1.6S7.9,6,7.6,5.8S6.8,5.5,6.3,5.5c-0.7,0-1.4,0.2-1.9,0.7 - S3.6,7.6,3.6,8.9v5.7H1.8z"/> - <path fill="#078876" d="M20,11.2l1.8,0.2c-0.3,1.1-0.8,1.9-1.6,2.5s-1.8,0.9-3,0.9c-1.5,0-2.7-0.5-3.6-1.4s-1.3-2.2-1.3-3.9 - c0-1.7,0.4-3.1,1.3-4.1S15.8,4,17.2,4c1.4,0,2.5,0.5,3.4,1.4s1.3,2.3,1.3,4c0,0.1,0,0.3,0,0.5h-7.7c0.1,1.1,0.4,2,1,2.6 - s1.3,0.9,2.2,0.9c0.6,0,1.2-0.2,1.7-0.5S19.8,12,20,11.2z M14.3,8.4h5.8c-0.1-0.9-0.3-1.5-0.7-2c-0.6-0.7-1.3-1-2.2-1 - c-0.8,0-1.5,0.3-2,0.8S14.3,7.5,14.3,8.4z"/> - <path fill="#078876" d="M26,14.6L22.8,4.2h1.8l1.7,6l0.6,2.2c0-0.1,0.2-0.8,0.5-2.1l1.7-6.1h1.8l1.6,6l0.5,2l0.6-2l1.8-6H37 - l-3.2,10.4H32l-1.7-6.2l-0.4-1.8l-2.1,8H26z"/> - <path fill="#078876" d="M38.8,14.6V0.2h10.4v1.7h-8.5v4.4h7.9V8h-7.9v4.9h8.8v1.7H38.8z"/> - <path fill="#078876" d="M58.6,14.6v-1.3c-0.7,1-1.6,1.5-2.9,1.5c-0.8,0-1.6-0.2-2.3-0.7s-1.2-1.1-1.6-1.9s-0.6-1.8-0.6-2.8 - c0-1,0.2-2,0.5-2.8s0.9-1.5,1.6-1.9S54.7,4,55.6,4c0.6,0,1.2,0.1,1.7,0.4s0.9,0.6,1.2,1V0.2h1.7v14.3H58.6z M53,9.4 + <path fill="#048876" d="M27.3,26.9l1.8,0.2c-0.3,1.1-0.8,1.9-1.6,2.5s-1.8,0.9-3,0.9c-1.5,0-2.7-0.5-3.6-1.4s-1.3-2.2-1.3-3.9 + c0-1.7,0.4-3.1,1.3-4.1s2.1-1.4,3.5-1.4c1.4,0,2.5,0.5,3.4,1.4s1.3,2.3,1.3,4c0,0.1,0,0.3,0,0.5h-7.7c0.1,1.1,0.4,2,1,2.6 + s1.3,0.9,2.2,0.9c0.6,0,1.2-0.2,1.7-0.5S27,27.7,27.3,26.9z M21.5,24.1h5.8c-0.1-0.9-0.3-1.5-0.7-2c-0.6-0.7-1.3-1-2.2-1 + c-0.8,0-1.5,0.3-2,0.8S21.6,23.2,21.5,24.1z"/> + <path fill="#048876" d="M38.1,30.3V29c-0.7,1-1.6,1.5-2.9,1.5c-0.8,0-1.6-0.2-2.3-0.7s-1.2-1.1-1.6-1.9s-0.6-1.8-0.6-2.8 + c0-1,0.2-2,0.5-2.8s0.9-1.5,1.6-1.9s1.5-0.7,2.3-0.7c0.6,0,1.2,0.1,1.7,0.4s0.9,0.6,1.2,1V16h1.7v14.3H38.1z M32.5,25.1 c0,1.3,0.3,2.3,0.8,3s1.2,1,2,1c0.8,0,1.4-0.3,2-0.9s0.8-1.6,0.8-2.9c0-1.4-0.3-2.5-0.8-3.1s-1.2-1-2-1c-0.8,0-1.4,0.3-2,1 - S53,8,53,9.4z"/> - <path fill="#078876" d="M63,2.3v-2h1.8v2H63z M63,14.6V4.2h1.8v10.4H63z"/> - <path fill="#078876" d="M71.3,13l0.3,1.6c-0.5,0.1-0.9,0.2-1.3,0.2c-0.6,0-1.1-0.1-1.5-0.3s-0.6-0.5-0.7-0.8s-0.2-1-0.2-2.1v-6 - h-1.3V4.2h1.3V1.6l1.7-1.1v3.6h1.8v1.4h-1.8v6.1c0,0.5,0,0.8,0.1,1s0.2,0.3,0.3,0.3s0.3,0.1,0.6,0.1C70.7,13.1,70.9,13,71.3,13z" - /> - <path fill="#078876" d="M73.2,14.6V0.2h10.4v1.7h-8.5v4.4H83V8h-7.9v4.9h8.8v1.7H73.2z"/> - <path fill="#078876" d="M86.3,14.6V4.2h1.6v1.5C88.7,4.5,89.8,4,91.2,4c0.6,0,1.2,0.1,1.7,0.3s0.9,0.5,1.2,0.9s0.4,0.8,0.5,1.3 - c0.1,0.3,0.1,0.9,0.1,1.7v6.4H93V8.3c0-0.7-0.1-1.3-0.2-1.6S92.4,6,92,5.8s-0.8-0.3-1.2-0.3c-0.7,0-1.4,0.2-1.9,0.7 - s-0.8,1.4-0.8,2.7v5.7H86.3z"/> - <path fill="#078876" d="M101.3,13l0.3,1.6c-0.5,0.1-0.9,0.2-1.3,0.2c-0.6,0-1.1-0.1-1.5-0.3s-0.6-0.5-0.7-0.8s-0.2-1-0.2-2.1v-6 - h-1.3V4.2h1.3V1.6l1.7-1.1v3.6h1.8v1.4h-1.8v6.1c0,0.5,0,0.8,0.1,1s0.2,0.3,0.3,0.3s0.3,0.1,0.6,0.1C100.7,13.1,101,13,101.3,13z" - /> - <path fill="#078876" d="M103,2.3v-2h1.8v2H103z M103,14.6V4.2h1.8v10.4H103z"/> - <path fill="#078876" d="M111.3,13l0.3,1.6c-0.5,0.1-0.9,0.2-1.3,0.2c-0.6,0-1.1-0.1-1.5-0.3s-0.6-0.5-0.7-0.8s-0.2-1-0.2-2.1v-6 - h-1.3V4.2h1.3V1.6l1.7-1.1v3.6h1.8v1.4h-1.8v6.1c0,0.5,0,0.8,0.1,1s0.2,0.3,0.3,0.3s0.3,0.1,0.6,0.1C110.7,13.1,111,13,111.3,13z" - /> - <path fill="#078876" d="M113,2.3v-2h1.8v2H113z M113,14.6V4.2h1.8v10.4H113z"/> - <path fill="#078876" d="M124.5,11.2l1.8,0.2c-0.3,1.1-0.8,1.9-1.6,2.5s-1.8,0.9-3,0.9c-1.5,0-2.7-0.5-3.6-1.4s-1.3-2.2-1.3-3.9 + S32.5,23.7,32.5,25.1z"/> + <path fill="#048876" d="M42.5,18v-2h1.8v2H42.5z M42.5,30.3V19.9h1.8v10.4H42.5z"/> + <path fill="#048876" d="M50.7,28.7l0.3,1.6c-0.5,0.1-0.9,0.2-1.3,0.2c-0.6,0-1.1-0.1-1.5-0.3s-0.6-0.5-0.7-0.8s-0.2-1-0.2-2.1v-6 + h-1.3v-1.4h1.3v-2.6l1.7-1.1v3.6h1.8v1.4H49v6.1c0,0.5,0,0.8,0.1,1s0.2,0.3,0.3,0.3s0.3,0.1,0.6,0.1 + C50.2,28.8,50.4,28.7,50.7,28.7z"/> + <path fill="#048876" d="M52.9,30.3v-2h2v2H52.9z"/> + <path fill="#048876" d="M55.8,34.3l0.3-1.5c0.4,0.1,0.6,0.1,0.8,0.1c0.4,0,0.6-0.1,0.8-0.4s0.3-0.8,0.3-1.8V19.9h1.8v10.9 + c0,1.3-0.2,2.2-0.5,2.7c-0.4,0.7-1.1,1-2.1,1C56.7,34.5,56.2,34.4,55.8,34.3z M58,18v-2h1.8v2H58z"/> + <path fill="#048876" d="M61.7,27.2l1.7-0.3c0.1,0.7,0.4,1.2,0.8,1.6s1.1,0.6,1.9,0.6c0.8,0,1.4-0.2,1.8-0.5s0.6-0.7,0.6-1.2 + c0-0.4-0.2-0.7-0.5-0.9c-0.2-0.2-0.8-0.4-1.8-0.6c-1.3-0.3-2.2-0.6-2.7-0.8s-0.9-0.6-1.1-1S62,23.2,62,22.7c0-0.5,0.1-0.9,0.3-1.3 + s0.5-0.7,0.9-1c0.3-0.2,0.6-0.4,1.1-0.5s1-0.2,1.5-0.2c0.8,0,1.5,0.1,2.1,0.4s1.1,0.6,1.4,1s0.5,0.9,0.6,1.6l-1.7,0.2 + c-0.1-0.5-0.3-1-0.7-1.2s-0.9-0.4-1.6-0.4c-0.8,0-1.4,0.1-1.7,0.4s-0.5,0.6-0.5,0.9c0,0.2,0.1,0.4,0.2,0.6 + c0.1,0.2,0.4,0.3,0.7,0.5c0.2,0.1,0.7,0.2,1.6,0.4c1.2,0.3,2.1,0.6,2.6,0.8s0.9,0.5,1.2,0.9s0.4,0.9,0.4,1.5 + c0,0.6-0.2,1.1-0.5,1.7s-0.8,0.9-1.5,1.2s-1.4,0.4-2.2,0.4c-1.3,0-2.4-0.3-3.1-0.8S61.9,28.3,61.7,27.2z"/> + <path fill="#048876" d="M85.1,26.9l1.8,0.2c-0.3,1.1-0.8,1.9-1.6,2.5s-1.8,0.9-3,0.9c-1.5,0-2.7-0.5-3.6-1.4s-1.3-2.2-1.3-3.9 c0-1.7,0.4-3.1,1.3-4.1s2.1-1.4,3.5-1.4c1.4,0,2.5,0.5,3.4,1.4s1.3,2.3,1.3,4c0,0.1,0,0.3,0,0.5h-7.7c0.1,1.1,0.4,2,1,2.6 - s1.3,0.9,2.2,0.9c0.6,0,1.2-0.2,1.7-0.5S124.3,12,124.5,11.2z M118.8,8.4h5.8c-0.1-0.9-0.3-1.5-0.7-2c-0.6-0.7-1.3-1-2.2-1 - c-0.8,0-1.5,0.3-2,0.8S118.8,7.5,118.8,8.4z"/> - <path fill="#078876" d="M127.9,11.5l1.7-0.3c0.1,0.7,0.4,1.2,0.8,1.6s1.1,0.6,1.9,0.6c0.8,0,1.4-0.2,1.8-0.5s0.6-0.7,0.6-1.2 - c0-0.4-0.2-0.7-0.5-0.9c-0.2-0.2-0.8-0.4-1.8-0.6c-1.3-0.3-2.2-0.6-2.7-0.8s-0.9-0.6-1.1-1s-0.4-0.9-0.4-1.4 - c0-0.5,0.1-0.9,0.3-1.3s0.5-0.7,0.9-1c0.3-0.2,0.6-0.4,1.1-0.5s1-0.2,1.5-0.2c0.8,0,1.5,0.1,2.1,0.4s1.1,0.6,1.4,1 - s0.5,0.9,0.6,1.6l-1.7,0.2c-0.1-0.5-0.3-1-0.7-1.2s-0.9-0.4-1.6-0.4c-0.8,0-1.4,0.1-1.7,0.4s-0.5,0.6-0.5,0.9 - c0,0.2,0.1,0.4,0.2,0.6c0.1,0.2,0.4,0.3,0.7,0.5c0.2,0.1,0.7,0.2,1.6,0.4c1.2,0.3,2.1,0.6,2.6,0.8s0.9,0.5,1.2,0.9 - s0.4,0.9,0.4,1.5c0,0.6-0.2,1.1-0.5,1.7s-0.8,0.9-1.5,1.2s-1.4,0.4-2.2,0.4c-1.3,0-2.4-0.3-3.1-0.8S128,12.6,127.9,11.5z"/> - <path fill="#078876" d="M139.1,14.6v-2h2v2H139.1z"/> - <path fill="#078876" d="M141.9,18.6l0.3-1.5c0.4,0.1,0.6,0.1,0.8,0.1c0.4,0,0.6-0.1,0.8-0.4s0.3-0.8,0.3-1.8V4.2h1.8v10.9 - c0,1.3-0.2,2.2-0.5,2.7c-0.4,0.7-1.1,1-2.1,1C142.8,18.8,142.3,18.7,141.9,18.6z M144.1,2.3v-2h1.8v2H144.1z"/> - <path fill="#078876" d="M147.9,11.5l1.7-0.3c0.1,0.7,0.4,1.2,0.8,1.6s1.1,0.6,1.9,0.6c0.8,0,1.4-0.2,1.8-0.5s0.6-0.7,0.6-1.2 - c0-0.4-0.2-0.7-0.5-0.9c-0.2-0.2-0.8-0.4-1.8-0.6c-1.3-0.3-2.2-0.6-2.7-0.8s-0.9-0.6-1.1-1s-0.4-0.9-0.4-1.4 - c0-0.5,0.1-0.9,0.3-1.3s0.5-0.7,0.9-1c0.3-0.2,0.6-0.4,1.1-0.5s1-0.2,1.5-0.2c0.8,0,1.5,0.1,2.1,0.4s1.1,0.6,1.4,1 - s0.5,0.9,0.6,1.6l-1.7,0.2c-0.1-0.5-0.3-1-0.7-1.2s-0.9-0.4-1.6-0.4c-0.8,0-1.4,0.1-1.7,0.4s-0.5,0.6-0.5,0.9 - c0,0.2,0.1,0.4,0.2,0.6c0.1,0.2,0.4,0.3,0.7,0.5c0.2,0.1,0.7,0.2,1.6,0.4c1.2,0.3,2.1,0.6,2.6,0.8s0.9,0.5,1.2,0.9 - s0.4,0.9,0.4,1.5c0,0.6-0.2,1.1-0.5,1.7s-0.8,0.9-1.5,1.2s-1.4,0.4-2.2,0.4c-1.3,0-2.4-0.3-3.1-0.8S148,12.6,147.9,11.5z"/> - <path fill="#078876" d="M171.2,11.2l1.8,0.2c-0.3,1.1-0.8,1.9-1.6,2.5s-1.8,0.9-3,0.9c-1.5,0-2.7-0.5-3.6-1.4s-1.3-2.2-1.3-3.9 - c0-1.7,0.4-3.1,1.3-4.1s2.1-1.4,3.5-1.4c1.4,0,2.5,0.5,3.4,1.4s1.3,2.3,1.3,4c0,0.1,0,0.3,0,0.5h-7.7c0.1,1.1,0.4,2,1,2.6 - s1.3,0.9,2.2,0.9c0.6,0,1.2-0.2,1.7-0.5S170.9,12,171.2,11.2z M165.4,8.4h5.8c-0.1-0.9-0.3-1.5-0.7-2c-0.6-0.7-1.3-1-2.2-1 - c-0.8,0-1.5,0.3-2,0.8S165.5,7.5,165.4,8.4z"/> - <path fill="#078876" d="M175.2,14.6V4.2h1.6v1.5c0.8-1.1,1.9-1.7,3.3-1.7c0.6,0,1.2,0.1,1.7,0.3s0.9,0.5,1.2,0.9s0.4,0.8,0.5,1.3 - c0.1,0.3,0.1,0.9,0.1,1.7v6.4h-1.8V8.3c0-0.7-0.1-1.3-0.2-1.6S181.3,6,181,5.8s-0.8-0.3-1.2-0.3c-0.7,0-1.4,0.2-1.9,0.7 - S177,7.6,177,8.9v5.7H175.2z"/> - <path fill="#078876" d="M193.1,13.3c-0.7,0.6-1.3,0.9-1.9,1.2s-1.2,0.3-1.9,0.3c-1.1,0-2-0.3-2.6-0.8s-0.9-1.3-0.9-2.1 + s1.3,0.9,2.2,0.9c0.6,0,1.2-0.2,1.7-0.5S84.8,27.7,85.1,26.9z M79.3,24.1h5.8c-0.1-0.9-0.3-1.5-0.7-2c-0.6-0.7-1.3-1-2.2-1 + c-0.8,0-1.5,0.3-2,0.8S79.4,23.2,79.3,24.1z"/> + <path fill="#048876" d="M89.1,30.3V19.9h1.6v1.5c0.8-1.1,1.9-1.7,3.3-1.7c0.6,0,1.2,0.1,1.7,0.3s0.9,0.5,1.2,0.9s0.4,0.8,0.5,1.3 + c0.1,0.3,0.1,0.9,0.1,1.7v6.4h-1.8V24c0-0.7-0.1-1.3-0.2-1.6s-0.4-0.6-0.7-0.8s-0.8-0.3-1.2-0.3c-0.7,0-1.4,0.2-1.9,0.7 + s-0.8,1.4-0.8,2.7v5.7H89.1z"/> + <path fill="#048876" d="M107,29c-0.7,0.6-1.3,0.9-1.9,1.2s-1.2,0.3-1.9,0.3c-1.1,0-2-0.3-2.6-0.8s-0.9-1.3-0.9-2.1 c0-0.5,0.1-1,0.3-1.4s0.5-0.8,0.9-1s0.8-0.4,1.3-0.6c0.3-0.1,0.9-0.2,1.6-0.3c1.4-0.2,2.5-0.4,3.1-0.6c0-0.2,0-0.4,0-0.5 c0-0.7-0.2-1.2-0.5-1.5c-0.4-0.4-1.1-0.6-2-0.6c-0.8,0-1.4,0.1-1.8,0.4s-0.7,0.8-0.9,1.5l-1.7-0.2c0.2-0.7,0.4-1.3,0.8-1.8 s0.9-0.8,1.6-1s1.5-0.4,2.4-0.4c0.9,0,1.6,0.1,2.2,0.3s1,0.5,1.2,0.8s0.4,0.7,0.5,1.2c0.1,0.3,0.1,0.8,0.1,1.6v2.3 - c0,1.6,0,2.7,0.1,3.1s0.2,0.8,0.4,1.2h-1.8C193.3,14.2,193.2,13.8,193.1,13.3z M193,9.4c-0.6,0.3-1.6,0.5-2.9,0.7 + c0,1.6,0,2.7,0.1,3.1s0.2,0.8,0.4,1.2h-1.8C107.2,29.9,107.1,29.5,107,29z M106.9,25.1c-0.6,0.3-1.6,0.5-2.9,0.7 c-0.7,0.1-1.2,0.2-1.5,0.4s-0.5,0.3-0.7,0.6s-0.2,0.5-0.2,0.8c0,0.5,0.2,0.9,0.5,1.2s0.9,0.5,1.6,0.5c0.7,0,1.3-0.1,1.8-0.4 - s0.9-0.7,1.2-1.2c0.2-0.4,0.3-1,0.3-1.8V9.4z"/> - <path fill="#078876" d="M199.1,14.6h-1.6V0.2h1.8v5.1c0.7-0.9,1.7-1.4,2.8-1.4c0.6,0,1.2,0.1,1.8,0.4s1,0.6,1.4,1.1s0.7,1,0.9,1.7 - s0.3,1.4,0.3,2.1c0,1.8-0.4,3.2-1.3,4.1s-1.9,1.5-3.2,1.5c-1.2,0-2.2-0.5-2.9-1.5V14.6z M199.1,9.3c0,1.2,0.2,2.1,0.5,2.7 - c0.6,0.9,1.3,1.4,2.2,1.4c0.8,0,1.4-0.3,2-1s0.8-1.7,0.8-3c0-1.4-0.3-2.4-0.8-3s-1.2-1-1.9-1c-0.8,0-1.4,0.3-2,1 - S199.1,8,199.1,9.3z"/> - <path fill="#078876" d="M208.6,14.6V0.2h1.8v14.3H208.6z"/> - <path fill="#078876" d="M220.1,11.2l1.8,0.2c-0.3,1.1-0.8,1.9-1.6,2.5s-1.8,0.9-3,0.9c-1.5,0-2.7-0.5-3.6-1.4s-1.3-2.2-1.3-3.9 + s0.9-0.7,1.2-1.2c0.2-0.4,0.3-1,0.3-1.8V25.1z"/> + <path fill="#048876" d="M113,30.3h-1.6V16h1.8v5.1c0.7-0.9,1.7-1.4,2.8-1.4c0.6,0,1.2,0.1,1.8,0.4s1,0.6,1.4,1.1s0.7,1,0.9,1.7 + s0.3,1.4,0.3,2.1c0,1.8-0.4,3.2-1.3,4.1s-1.9,1.5-3.2,1.5c-1.2,0-2.2-0.5-2.9-1.5V30.3z M113,25c0,1.2,0.2,2.1,0.5,2.7 + c0.6,0.9,1.3,1.4,2.2,1.4c0.8,0,1.4-0.3,2-1s0.8-1.7,0.8-3c0-1.4-0.3-2.4-0.8-3s-1.2-1-1.9-1c-0.8,0-1.4,0.3-2,1S113,23.7,113,25z + "/> + <path fill="#048876" d="M122.5,30.3V16h1.8v14.3H122.5z"/> + <path fill="#048876" d="M134,26.9l1.8,0.2c-0.3,1.1-0.8,1.9-1.6,2.5s-1.8,0.9-3,0.9c-1.5,0-2.7-0.5-3.6-1.4s-1.3-2.2-1.3-3.9 c0-1.7,0.4-3.1,1.3-4.1s2.1-1.4,3.5-1.4c1.4,0,2.5,0.5,3.4,1.4s1.3,2.3,1.3,4c0,0.1,0,0.3,0,0.5h-7.7c0.1,1.1,0.4,2,1,2.6 - s1.3,0.9,2.2,0.9c0.6,0,1.2-0.2,1.7-0.5S219.9,12,220.1,11.2z M214.4,8.4h5.8c-0.1-0.9-0.3-1.5-0.7-2c-0.6-0.7-1.3-1-2.2-1 - c-0.8,0-1.5,0.3-2,0.8S214.4,7.5,214.4,8.4z"/> - <path fill="#078876" d="M223.5,11.5l1.7-0.3c0.1,0.7,0.4,1.2,0.8,1.6s1.1,0.6,1.9,0.6c0.8,0,1.4-0.2,1.8-0.5s0.6-0.7,0.6-1.2 + s1.3,0.9,2.2,0.9c0.6,0,1.2-0.2,1.7-0.5S133.8,27.7,134,26.9z M128.3,24.1h5.8c-0.1-0.9-0.3-1.5-0.7-2c-0.6-0.7-1.3-1-2.2-1 + c-0.8,0-1.5,0.3-2,0.8S128.3,23.2,128.3,24.1z"/> + <path fill="#048876" d="M137.4,27.2l1.7-0.3c0.1,0.7,0.4,1.2,0.8,1.6s1.1,0.6,1.9,0.6c0.8,0,1.4-0.2,1.8-0.5s0.6-0.7,0.6-1.2 c0-0.4-0.2-0.7-0.5-0.9c-0.2-0.2-0.8-0.4-1.8-0.6c-1.3-0.3-2.2-0.6-2.7-0.8s-0.9-0.6-1.1-1s-0.4-0.9-0.4-1.4 c0-0.5,0.1-0.9,0.3-1.3s0.5-0.7,0.9-1c0.3-0.2,0.6-0.4,1.1-0.5s1-0.2,1.5-0.2c0.8,0,1.5,0.1,2.1,0.4s1.1,0.6,1.4,1 - s0.5,0.9,0.6,1.6L230,7.1c-0.1-0.5-0.3-1-0.7-1.2s-0.9-0.4-1.6-0.4c-0.8,0-1.4,0.1-1.7,0.4s-0.5,0.6-0.5,0.9 + s0.5,0.9,0.6,1.6l-1.7,0.2c-0.1-0.5-0.3-1-0.7-1.2s-0.9-0.4-1.6-0.4c-0.8,0-1.4,0.1-1.7,0.4s-0.5,0.6-0.5,0.9 c0,0.2,0.1,0.4,0.2,0.6c0.1,0.2,0.4,0.3,0.7,0.5c0.2,0.1,0.7,0.2,1.6,0.4c1.2,0.3,2.1,0.6,2.6,0.8s0.9,0.5,1.2,0.9 - s0.4,0.9,0.4,1.5c0,0.6-0.2,1.1-0.5,1.7s-0.8,0.9-1.5,1.2s-1.4,0.4-2.2,0.4c-1.3,0-2.4-0.3-3.1-0.8S223.7,12.6,223.5,11.5z"/> - <path fill="#078876" d="M243.6,13l0.3,1.6c-0.5,0.1-0.9,0.2-1.3,0.2c-0.6,0-1.1-0.1-1.5-0.3s-0.6-0.5-0.7-0.8s-0.2-1-0.2-2.1v-6 - h-1.3V4.2h1.3V1.6l1.7-1.1v3.6h1.8v1.4h-1.8v6.1c0,0.5,0,0.8,0.1,1s0.2,0.3,0.3,0.3s0.3,0.1,0.6,0.1C243,13.1,243.2,13,243.6,13z" - /> - <path fill="#078876" d="M245.3,14.6V0.2h1.8v5.1c0.8-1,1.9-1.4,3.1-1.4c0.8,0,1.4,0.2,2,0.5s1,0.7,1.2,1.3s0.4,1.3,0.4,2.3v6.6 - H252V8c0-0.9-0.2-1.5-0.6-1.9s-0.9-0.6-1.6-0.6c-0.5,0-1,0.1-1.5,0.4s-0.8,0.6-1,1.1S247,8.1,247,8.9v5.7H245.3z"/> - <path fill="#078876" d="M263.5,11.2l1.8,0.2c-0.3,1.1-0.8,1.9-1.6,2.5s-1.8,0.9-3,0.9c-1.5,0-2.7-0.5-3.6-1.4s-1.3-2.2-1.3-3.9 + s0.4,0.9,0.4,1.5c0,0.6-0.2,1.1-0.5,1.7s-0.8,0.9-1.5,1.2s-1.4,0.4-2.2,0.4c-1.3,0-2.4-0.3-3.1-0.8S137.6,28.3,137.4,27.2z"/> + <path fill="#048876" d="M157.5,28.7l0.3,1.6c-0.5,0.1-0.9,0.2-1.3,0.2c-0.6,0-1.1-0.1-1.5-0.3s-0.6-0.5-0.7-0.8s-0.2-1-0.2-2.1v-6 + h-1.3v-1.4h1.3v-2.6l1.7-1.1v3.6h1.8v1.4h-1.8v6.1c0,0.5,0,0.8,0.1,1s0.2,0.3,0.3,0.3s0.3,0.1,0.6,0.1 + C156.9,28.8,157.1,28.7,157.5,28.7z"/> + <path fill="#048876" d="M159.2,30.3V16h1.8v5.1c0.8-1,1.9-1.4,3.1-1.4c0.8,0,1.4,0.2,2,0.5s1,0.7,1.2,1.3s0.4,1.3,0.4,2.3v6.6 + h-1.8v-6.6c0-0.9-0.2-1.5-0.6-1.9s-0.9-0.6-1.6-0.6c-0.5,0-1,0.1-1.5,0.4s-0.8,0.6-1,1.1s-0.3,1.1-0.3,1.9v5.7H159.2z"/> + <path fill="#048876" d="M177.4,26.9l1.8,0.2c-0.3,1.1-0.8,1.9-1.6,2.5s-1.8,0.9-3,0.9c-1.5,0-2.7-0.5-3.6-1.4s-1.3-2.2-1.3-3.9 c0-1.7,0.4-3.1,1.3-4.1s2.1-1.4,3.5-1.4c1.4,0,2.5,0.5,3.4,1.4s1.3,2.3,1.3,4c0,0.1,0,0.3,0,0.5h-7.7c0.1,1.1,0.4,2,1,2.6 - s1.3,0.9,2.2,0.9c0.6,0,1.2-0.2,1.7-0.5S263.2,12,263.5,11.2z M257.7,8.4h5.8c-0.1-0.9-0.3-1.5-0.7-2c-0.6-0.7-1.3-1-2.2-1 - c-0.8,0-1.5,0.3-2,0.8S257.8,7.5,257.7,8.4z"/> - <path fill="#078876" d="M273.5,14.6v-9H272V4.2h1.6V3.1c0-0.7,0.1-1.2,0.2-1.6c0.2-0.5,0.5-0.8,0.9-1.1s1-0.4,1.8-0.4 - c0.5,0,1,0.1,1.6,0.2l-0.3,1.5c-0.4-0.1-0.7-0.1-1-0.1c-0.5,0-0.9,0.1-1.1,0.3s-0.3,0.7-0.3,1.3v1h2v1.4h-2v9H273.5z"/> - <path fill="#078876" d="M278,9.4c0-1.9,0.5-3.3,1.6-4.3c0.9-0.8,2-1.2,3.3-1.2c1.4,0,2.6,0.5,3.5,1.4s1.4,2.2,1.4,3.9 - c0,1.3-0.2,2.4-0.6,3.1s-1,1.4-1.7,1.8s-1.6,0.6-2.5,0.6c-1.5,0-2.6-0.5-3.5-1.4S278,11.1,278,9.4z M279.8,9.4 + s1.3,0.9,2.2,0.9c0.6,0,1.2-0.2,1.7-0.5S177.1,27.7,177.4,26.9z M171.6,24.1h5.8c-0.1-0.9-0.3-1.5-0.7-2c-0.6-0.7-1.3-1-2.2-1 + c-0.8,0-1.5,0.3-2,0.8S171.7,23.2,171.6,24.1z"/> + <path fill="#048876" d="M187.4,30.3v-9h-1.6v-1.4h1.6v-1.1c0-0.7,0.1-1.2,0.2-1.6c0.2-0.5,0.5-0.8,0.9-1.1s1-0.4,1.8-0.4 + c0.5,0,1,0.1,1.6,0.2l-0.3,1.5c-0.4-0.1-0.7-0.1-1-0.1c-0.5,0-0.9,0.1-1.1,0.3s-0.3,0.7-0.3,1.3v1h2v1.4h-2v9H187.4z"/> + <path fill="#048876" d="M191.9,25.1c0-1.9,0.5-3.3,1.6-4.3c0.9-0.8,2-1.2,3.3-1.2c1.4,0,2.6,0.5,3.5,1.4s1.4,2.2,1.4,3.9 + c0,1.3-0.2,2.4-0.6,3.1s-1,1.4-1.7,1.8s-1.6,0.6-2.5,0.6c-1.5,0-2.6-0.5-3.5-1.4S191.9,26.8,191.9,25.1z M193.7,25.1 c0,1.3,0.3,2.3,0.9,3s1.3,1,2.2,1c0.9,0,1.6-0.3,2.2-1s0.9-1.7,0.9-3c0-1.3-0.3-2.3-0.9-2.9s-1.3-1-2.2-1c-0.9,0-1.6,0.3-2.2,1 - S279.8,8,279.8,9.4z"/> - <path fill="#078876" d="M289.7,14.6V0.2h1.8v14.3H289.7z"/> - <path fill="#078876" d="M294.2,14.6V0.2h1.8v14.3H294.2z"/> - <path fill="#078876" d="M298,9.4c0-1.9,0.5-3.3,1.6-4.3c0.9-0.8,2-1.2,3.3-1.2c1.4,0,2.6,0.5,3.5,1.4s1.4,2.2,1.4,3.9 - c0,1.3-0.2,2.4-0.6,3.1s-1,1.4-1.7,1.8s-1.6,0.6-2.5,0.6c-1.5,0-2.6-0.5-3.5-1.4S298,11.1,298,9.4z M299.8,9.4 + S193.7,23.8,193.7,25.1z"/> + <path fill="#048876" d="M203.6,30.3V16h1.8v14.3H203.6z"/> + <path fill="#048876" d="M208.1,30.3V16h1.8v14.3H208.1z"/> + <path fill="#048876" d="M211.9,25.1c0-1.9,0.5-3.3,1.6-4.3c0.9-0.8,2-1.2,3.3-1.2c1.4,0,2.6,0.5,3.5,1.4s1.4,2.2,1.4,3.9 + c0,1.3-0.2,2.4-0.6,3.1s-1,1.4-1.7,1.8s-1.6,0.6-2.5,0.6c-1.5,0-2.6-0.5-3.5-1.4S211.9,26.8,211.9,25.1z M213.7,25.1 c0,1.3,0.3,2.3,0.9,3s1.3,1,2.2,1c0.9,0,1.6-0.3,2.2-1s0.9-1.7,0.9-3c0-1.3-0.3-2.3-0.9-2.9s-1.3-1-2.2-1c-0.9,0-1.6,0.3-2.2,1 - S299.8,8,299.8,9.4z"/> - <path fill="#078876" d="M311.7,14.6l-3.2-10.4h1.8l1.7,6l0.6,2.2c0-0.1,0.2-0.8,0.5-2.1l1.7-6.1h1.8l1.6,6l0.5,2l0.6-2l1.8-6h1.7 - l-3.2,10.4h-1.8L316,8.3l-0.4-1.8l-2.1,8H311.7z"/> - <path fill="#078876" d="M324.2,2.3v-2h1.8v2H324.2z M324.2,14.6V4.2h1.8v10.4H324.2z"/> - <path fill="#078876" d="M328.7,14.6V4.2h1.6v1.5c0.8-1.1,1.9-1.7,3.3-1.7c0.6,0,1.2,0.1,1.7,0.3s0.9,0.5,1.2,0.9s0.4,0.8,0.5,1.3 - c0.1,0.3,0.1,0.9,0.1,1.7v6.4h-1.8V8.3c0-0.7-0.1-1.3-0.2-1.6s-0.4-0.6-0.7-0.8s-0.8-0.3-1.2-0.3c-0.7,0-1.4,0.2-1.9,0.7 - s-0.8,1.4-0.8,2.7v5.7H328.7z"/> - <path fill="#078876" d="M339.5,15.4l1.7,0.3c0.1,0.5,0.3,0.9,0.6,1.2c0.4,0.3,1,0.5,1.8,0.5c0.8,0,1.4-0.2,1.9-0.5 - s0.7-0.8,0.9-1.4c0.1-0.4,0.1-1.1,0.1-2.3c-0.8,0.9-1.7,1.4-2.9,1.4c-1.4,0-2.5-0.5-3.3-1.5s-1.2-2.3-1.2-3.7c0-1,0.2-1.9,0.5-2.7 - s0.9-1.5,1.6-1.9s1.5-0.7,2.4-0.7c1.2,0,2.2,0.5,3,1.5V4.2h1.6v9c0,1.6-0.2,2.8-0.5,3.4s-0.8,1.2-1.6,1.6s-1.6,0.6-2.6,0.6 - c-1.2,0-2.2-0.3-3-0.8S339.4,16.5,339.5,15.4z M340.9,9.2c0,1.4,0.3,2.4,0.8,3s1.2,0.9,2,0.9c0.8,0,1.5-0.3,2-0.9s0.8-1.6,0.8-2.9 - c0-1.3-0.3-2.2-0.8-2.9s-1.2-1-2-1c-0.8,0-1.4,0.3-2,1S340.9,7.9,340.9,9.2z"/> + S213.7,23.8,213.7,25.1z"/> + <path fill="#048876" d="M225.6,30.3l-3.2-10.4h1.8l1.7,6l0.6,2.2c0-0.1,0.2-0.8,0.5-2.1l1.7-6.1h1.8l1.6,6l0.5,2l0.6-2l1.8-6h1.7 + l-3.2,10.4h-1.8l-1.7-6.2l-0.4-1.8l-2.1,8H225.6z"/> + <path fill="#048876" d="M238.1,18v-2h1.8v2H238.1z M238.1,30.3V19.9h1.8v10.4H238.1z"/> + <path fill="#048876" d="M242.6,30.3V19.9h1.6v1.5c0.8-1.1,1.9-1.7,3.3-1.7c0.6,0,1.2,0.1,1.7,0.3s0.9,0.5,1.2,0.9s0.4,0.8,0.5,1.3 + c0.1,0.3,0.1,0.9,0.1,1.7v6.4h-1.8V24c0-0.7-0.1-1.3-0.2-1.6s-0.4-0.6-0.7-0.8s-0.8-0.3-1.2-0.3c-0.7,0-1.4,0.2-1.9,0.7 + s-0.8,1.4-0.8,2.7v5.7H242.6z"/> + <path fill="#048876" d="M253.4,31.1l1.7,0.3c0.1,0.5,0.3,0.9,0.6,1.2c0.4,0.3,1,0.5,1.8,0.5c0.8,0,1.4-0.2,1.9-0.5 + s0.7-0.8,0.9-1.4c0.1-0.4,0.1-1.1,0.1-2.3c-0.8,0.9-1.7,1.4-2.9,1.4c-1.4,0-2.5-0.5-3.3-1.5S253,26.5,253,25c0-1,0.2-1.9,0.5-2.7 + s0.9-1.5,1.6-1.9s1.5-0.7,2.4-0.7c1.2,0,2.2,0.5,3,1.5v-1.2h1.6v9c0,1.6-0.2,2.8-0.5,3.4c-0.3,0.7-0.8,1.2-1.6,1.6 + s-1.6,0.6-2.6,0.6c-1.2,0-2.2-0.3-3-0.8S253.3,32.2,253.4,31.1z M254.8,24.9c0,1.4,0.3,2.4,0.8,3s1.2,0.9,2,0.9 + c0.8,0,1.5-0.3,2-0.9s0.8-1.6,0.8-2.9c0-1.3-0.3-2.2-0.8-2.9s-1.2-1-2-1c-0.8,0-1.4,0.3-2,1S254.8,23.6,254.8,24.9z"/> </g> <g> - <path fill="#078876" d="M534.7,313.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.4,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4s0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1s-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3s1.5-1.1,2.6-1.1 - c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H534.7z"/> - <path fill="#078876" d="M547.3,311.1c0.3,0.1,0.6,0.4,0.9,0.7c0.2,0.3,0.4,0.6,0.4,1c0,0.3,0.1,0.6,0.1,1.1l0,4.7h-2v-4.7 - c0-0.3,0-0.5-0.1-0.7c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.1,0.7c-0.1,0.2-0.2,0.5-0.2,0.9v4.4h-2v-4.4c0-0.4,0-0.8-0.1-1 - c-0.2-0.4-0.5-0.5-1-0.5c-0.6,0-0.9,0.2-1.1,0.5c-0.1,0.2-0.2,0.5-0.2,0.9v4.5h-2v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8 - c0.4-0.3,0.9-0.4,1.5-0.4c0.6,0,1,0.1,1.4,0.4c0.3,0.2,0.5,0.5,0.6,0.9c0.3-0.4,0.6-0.8,1-1c0.4-0.2,0.8-0.3,1.3-0.3 - C546.7,310.9,547,311,547.3,311.1z"/> - <path fill="#078876" d="M556.5,311.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V314c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.3,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C555.4,310.9,556,311.1,556.5,311.5z"/> - <path fill="#078876" d="M563,311.2c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1C562.2,310.9,562.6,311,563,311.2z - M563.5,316.5c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6 - c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6S563.2,316.9,563.5,316.5z"/> - </g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M573.5,327.7c0,2.2-1.8,4-4,4h-43c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h43c2.2,0,4,1.8,4,4V327.7z"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="0" y1="158.7" x2="491" y2="158.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="0" y1="94.7" x2="491" y2="94.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="0" y1="30.7" x2="491" y2="30.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="0" y1="221.7" x2="491" y2="221.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="0" y1="283.7" x2="491" y2="283.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="522" y1="283.7" x2="1013" y2="283.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="0" y1="346.7" x2="491" y2="346.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="0" y1="410.7" x2="491" y2="410.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="0" y1="473.7" x2="491" y2="473.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="522" y1="346.7" x2="1013" y2="346.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="522" y1="410.7" x2="1013" y2="410.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="522" y1="473.7" x2="1013" y2="473.7"/> - <g> - <path fill="#078876" d="M636.1,499.3 M635.9,497.1l-0.5-4.9l-2,0.2c-0.3,0-0.5-0.1-0.6-0.3c-0.1-0.2-0.1-0.5,0.1-0.7l2.7-3.4 - c0.2-0.3,0.6-0.3,0.9-0.1l3.4,2.7c0.2,0.2,0.3,0.4,0.2,0.7c0,0.1-0.1,0.2-0.1,0.2c-0.1,0.1-0.3,0.2-0.4,0.2l-2,0.2l0.5,4.9"/> + <g> + <path fill="#048876" d="M555,329.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9c-0.2-0.2-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1 + l1.9,0.3c-0.2,0.9-0.6,1.5-1.1,2s-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C554.4,327.8,554.8,328.4,555,329.2z"/> + <path fill="#048876" d="M556.4,327h1.8v1c0.6-0.8,1.4-1.2,2.3-1.2c0.5,0,0.9,0.1,1.2,0.3s0.6,0.5,0.8,0.9c0.3-0.4,0.7-0.7,1-0.9 + s0.8-0.3,1.2-0.3c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.6,0.5,0.8,1c0.1,0.3,0.2,0.8,0.2,1.5v4.6h-1.9v-4.1c0-0.7-0.1-1.2-0.2-1.4 + c-0.2-0.3-0.5-0.4-0.8-0.4c-0.3,0-0.5,0.1-0.8,0.2s-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5v3.5h-1.9v-4c0-0.7,0-1.2-0.1-1.4 + s-0.2-0.4-0.3-0.5c-0.1-0.1-0.3-0.2-0.6-0.2c-0.3,0-0.6,0.1-0.8,0.2s-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5v3.5h-1.9V327z"/> + <path fill="#048876" d="M575.6,334.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5c-0.2-0.1-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3s-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V327h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V334.3z"/> + <path fill="#048876" d="M584.2,334.3h-1.8v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V334.3z M579,330.5 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C579.2,329.2,579,329.8,579,330.5z"/> + </g> </g> <g> - <path fill="#078876" d="M640.8,500.9 M643,500.6l4.9-0.5l-0.2-2c0-0.3,0.1-0.5,0.3-0.6c0.2-0.1,0.5-0.1,0.7,0.1l3.4,2.7 - c0.3,0.2,0.3,0.6,0.1,0.9l-2.7,3.4c-0.2,0.2-0.4,0.3-0.7,0.2c-0.1,0-0.2-0.1-0.2-0.1c-0.1-0.1-0.2-0.3-0.2-0.4l-0.2-2l-4.9,0.5"/> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M591.9,343.4c0,2.2-1.8,4-4,4h-43c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h43c2.2,0,4,1.8,4,4V343.4z"/> + </g> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="18.4" y1="174.4" x2="509.4" y2="174.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="18.4" y1="110.4" x2="509.4" y2="110.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="18.4" y1="46.4" x2="509.4" y2="46.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="18.4" y1="237.4" x2="509.4" y2="237.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="18.4" y1="299.4" x2="509.4" y2="299.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="540.4" y1="299.4" x2="1031.4" y2="299.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="18.4" y1="362.4" x2="509.4" y2="362.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="18.4" y1="426.4" x2="509.4" y2="426.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="18.4" y1="489.4" x2="509.4" y2="489.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="540.4" y1="362.4" x2="1031.4" y2="362.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="540.4" y1="426.4" x2="1031.4" y2="426.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="540.4" y1="489.4" x2="1031.4" y2="489.4"/> + <g> + <g> + <path fill="#048876" d="M654.5,515 M654.2,512.8l-0.5-4.9l-2,0.2c-0.3,0-0.5-0.1-0.6-0.3c-0.1-0.2-0.1-0.5,0.1-0.7l2.7-3.4 + c0.2-0.3,0.6-0.3,0.9-0.1l3.4,2.7c0.2,0.2,0.3,0.4,0.2,0.7c0,0.1-0.1,0.2-0.1,0.2c-0.1,0.1-0.3,0.2-0.4,0.2l-2,0.2l0.5,4.9"/> + </g> </g> <g> - <path d="M638.7,521.6 M638.5,519.4l-1.5-12l2.2-0.2l1.4,12"/> + <g> + <path fill="#048876" d="M659.2,516.6 M661.4,516.3l4.9-0.5l-0.2-2c0-0.3,0.1-0.5,0.3-0.6c0.2-0.1,0.5-0.1,0.7,0.1l3.4,2.7 + c0.3,0.2,0.3,0.6,0.1,0.9l-2.7,3.4c-0.2,0.2-0.4,0.3-0.7,0.2c-0.1,0-0.2-0.1-0.2-0.1c-0.1-0.1-0.2-0.3-0.2-0.4l-0.2-2l-4.9,0.5" + /> + </g> </g> <g> - <path d="M620.6,503.5 M622.8,503.3l12-1.5l0.2,2.2l-12,1.4"/> + <path d="M657.1,537.3 M656.9,535.1l-1.5-12l2.2-0.2l1.4,12"/> </g> <g> - <path fill="#333333" d="M135.8,126.6c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6 - c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7h-1.9c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1 - c0.8,0,1.5,0.2,2.2,0.5c0.6,0.3,1,0.9,1,1.8v3.4c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5c0.1,0.1,0.2,0.2,0.3,0.2v0.3h-2.1 - c-0.1-0.2-0.1-0.3-0.1-0.4c0-0.1,0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6 - c-0.4-0.4-0.7-0.9-0.7-1.6c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L135.8,126.6z M137,127.5c-0.1,0.1-0.3,0.1-0.4,0.2 - c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7 - c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4s0.5-0.7,0.6-1.3V127.5z"/> - <path fill="#333333" d="M144.6,123.8c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1 - C143.8,123.5,144.2,123.6,144.6,123.8z M145,129.1c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4 - c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6C144.3,129.7,144.8,129.5,145,129.1z + <path d="M639,519.2 M641.2,519l12-1.5l0.2,2.2l-12,1.4"/> + </g> + <g> + <path fill="#333333" d="M152.7,141.8l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9c0-0.1-0.1-0.3-0.2-0.6 + c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7c-0.4,0.2-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6s-0.6-0.9-0.6-1.5 + c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2c0-0.4-0.1-0.6-0.3-0.8 + c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C153,141.2,152.9,141.5,152.7,141.8z M155.3,143.4c-0.2,0.1-0.6,0.2-1.2,0.3 + s-0.9,0.2-1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7c0.2,0.2,0.5,0.3,0.8,0.3c0.3,0,0.7-0.1,1-0.3 + c0.2-0.2,0.4-0.4,0.5-0.6c0.1-0.2,0.1-0.5,0.1-0.9V143.4z"/> + <path fill="#333333" d="M165.8,146.9H164v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V146.9z M160.6,143.1 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C160.8,141.8,160.6,142.3,160.6,143.1z"/> + <path fill="#333333" d="M174.3,146.9h-1.8v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V146.9z M169.2,143.1 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C169.3,141.8,169.2,142.3,169.2,143.1z"/> + <path fill="#333333" d="M183.4,139.6v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9v-1.5h0.9v-1.4l1.9-1.1v2.6H183.4z"/> + <path fill="#333333" d="M184.3,143.1c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C184.5,144.7,184.3,144,184.3,143.1z M186.3,143.2c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S186.3,142.5,186.3,143.2z"/> + <path fill="#333333" d="M196.3,139.6h2l1.7,5.2l1.7-5.2h2l-2.6,7l-0.5,1.3c-0.2,0.4-0.3,0.7-0.5,1c-0.2,0.2-0.3,0.4-0.5,0.5 + c-0.2,0.1-0.4,0.2-0.7,0.3c-0.3,0.1-0.6,0.1-1,0.1c-0.4,0-0.7,0-1.1-0.1l-0.2-1.5c0.3,0.1,0.6,0.1,0.8,0.1c0.4,0,0.8-0.1,1-0.4 + c0.2-0.3,0.4-0.6,0.5-1L196.3,139.6z"/> + <path fill="#333333" d="M204.5,143.1c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C204.7,144.7,204.5,144,204.5,143.1z M206.5,143.2c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S206.5,142.5,206.5,143.2z"/> + <path fill="#333333" d="M218.3,146.9v-1.1c-0.3,0.4-0.6,0.7-1,0.9s-0.9,0.3-1.4,0.3c-0.5,0-0.9-0.1-1.3-0.3 + c-0.4-0.2-0.7-0.5-0.8-0.9c-0.2-0.4-0.3-0.9-0.3-1.6v-4.6h1.9v3.3c0,1,0,1.6,0.1,1.9c0.1,0.2,0.2,0.4,0.4,0.5 + c0.2,0.1,0.4,0.2,0.7,0.2c0.3,0,0.6-0.1,0.9-0.3c0.3-0.2,0.4-0.4,0.5-0.7c0.1-0.3,0.1-0.9,0.1-2v-3.1h1.9v7.3H218.3z"/> + <path fill="#333333" d="M223.9,146.9H222v-7.3h1.8v1c0.3-0.5,0.6-0.8,0.8-1c0.2-0.2,0.5-0.2,0.8-0.2c0.4,0,0.9,0.1,1.3,0.4 + l-0.6,1.7c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.1-0.3,0.4-0.4,0.8c-0.1,0.4-0.2,1.2-0.2,2.4V146.9z"/> + <path fill="#333333" d="M230.7,144.8l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.3,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C231.3,146,230.9,145.5,230.7,144.8z"/> + <path fill="#333333" d="M243.4,144.5l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S243.3,144.9,243.4,144.5z M243.5,142.6c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H243.5z"/> + <path fill="#333333" d="M247,146.9v-10h1.9v10H247z"/> + <path fill="#333333" d="M255.1,144.5l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S255,144.9,255.1,144.5z M255.2,142.6c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H255.2z"/> + <path fill="#333333" d="M265,141.7l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C264.4,140.4,264.8,141,265,141.7z"/> + <path fill="#333333" d="M269.8,139.6v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9v-1.5h0.9v-1.4l1.9-1.1v2.6H269.8z"/> + <path fill="#333333" d="M271.1,138.6v-1.8h1.9v1.8H271.1z M271.1,146.9v-7.3h1.9v7.3H271.1z"/> + <path fill="#333333" d="M274.6,143.1c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C274.7,144.7,274.6,144,274.6,143.1z M276.5,143.2c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S276.5,142.5,276.5,143.2z"/> + <path fill="#333333" d="M290.2,146.9h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9v-7.3h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V146.9z"/> + <path fill="#333333" d="M297.3,146.9l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3h-1.3l-1.2-4.3l-0.3-1.2l-1.5,5.6H297.3z"/> + <path fill="#333333" d="M306,138.2v-1.4h1.2v1.4H306z M306,146.9v-7.3h1.2v7.3H306z"/> + <path fill="#333333" d="M311.8,145.8l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C311.4,145.8,311.6,145.8,311.8,145.8z"/> + <path fill="#333333" d="M313,146.9v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9s0.3,0.9,0.3,1.6 + v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.6,0.4-0.7,0.8s-0.2,0.8-0.2,1.3 + v4H313z"/> + <path fill="#333333" d="M324.2,144.7l1.2-0.2c0.1,0.5,0.3,0.9,0.6,1.1c0.3,0.3,0.7,0.4,1.3,0.4c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.4-0.5,0.4-0.8c0-0.3-0.1-0.5-0.4-0.7c-0.2-0.1-0.6-0.2-1.3-0.4c-0.9-0.2-1.5-0.4-1.9-0.6c-0.3-0.2-0.6-0.4-0.8-0.7 + c-0.2-0.3-0.3-0.6-0.3-1c0-0.3,0.1-0.6,0.2-0.9c0.1-0.3,0.3-0.5,0.6-0.7c0.2-0.1,0.5-0.3,0.8-0.4c0.3-0.1,0.7-0.1,1.1-0.1 + c0.6,0,1.1,0.1,1.5,0.2s0.7,0.4,1,0.7c0.2,0.3,0.3,0.7,0.4,1.1l-1.2,0.2c-0.1-0.4-0.2-0.7-0.5-0.9c-0.3-0.2-0.6-0.3-1.1-0.3 + c-0.6,0-1,0.1-1.2,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.2,0.1,0.3,0.2,0.4c0.1,0.1,0.3,0.2,0.5,0.3c0.1,0,0.5,0.2,1.1,0.3 + c0.9,0.2,1.5,0.4,1.8,0.6c0.3,0.1,0.6,0.4,0.8,0.6c0.2,0.3,0.3,0.6,0.3,1.1c0,0.4-0.1,0.8-0.4,1.2c-0.2,0.4-0.6,0.6-1,0.8 + c-0.5,0.2-1,0.3-1.5,0.3c-0.9,0-1.7-0.2-2.2-0.6C324.7,146,324.3,145.5,324.2,144.7z"/> + <path fill="#333333" d="M331.7,146.9v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.6,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H331.7z"/> + <path fill="#333333" d="M339.5,138.2v-1.4h1.2v1.4H339.5z M339.5,146.9v-7.3h1.2v7.3H339.5z"/> + <path fill="#333333" d="M342.9,146.9v-6.3h-1.1v-1h1.1v-0.8c0-0.5,0-0.8,0.1-1.1c0.1-0.3,0.3-0.6,0.6-0.8c0.3-0.2,0.7-0.3,1.3-0.3 + c0.3,0,0.7,0,1.1,0.1l-0.2,1.1c-0.3,0-0.5-0.1-0.7-0.1c-0.4,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.2,0.5-0.2,0.9v0.7h1.4v1h-1.4v6.3H342.9 + z"/> + <path fill="#333333" d="M349.2,145.8l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C348.8,145.8,349,145.8,349.2,145.8z"/> + <path fill="#333333" d="M356.9,145.2v-2.7h-2.7v-1.1h2.7v-2.7h1.2v2.7h2.7v1.1H358v2.7H356.9z"/> + <path fill="#333333" d="M366.3,146.9v-10h1.2v10H366.3z"/> + <path fill="#333333" d="M374.4,144.5l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3h-5.4 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C374,145.4,374.2,145,374.4,144.5z M370.4,142.5h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C370.6,141.4,370.4,141.9,370.4,142.5z"/> + <path fill="#333333" d="M377.5,146.9v-6.3h-1.1v-1h1.1v-0.8c0-0.5,0-0.8,0.1-1.1c0.1-0.3,0.3-0.6,0.6-0.8c0.3-0.2,0.7-0.3,1.3-0.3 + c0.3,0,0.7,0,1.1,0.1l-0.2,1.1c-0.3,0-0.5-0.1-0.7-0.1c-0.4,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.2,0.5-0.2,0.9v0.7h1.4v1h-1.4v6.3H377.5 + z"/> + <path fill="#333333" d="M383.8,145.8l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C383.4,145.8,383.6,145.8,383.8,145.8z"/> + <path fill="#333333" d="M393.6,144.2l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C393.3,145.3,393.5,144.8,393.6,144.2z"/> + <path fill="#333333" d="M395.9,146.9v-10h1.2v10H395.9z"/> + <path fill="#333333" d="M399,138.2v-1.4h1.2v1.4H399z M399,146.9v-7.3h1.2v7.3H399z"/> + <path fill="#333333" d="M406.9,144.2l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C406.6,145.3,406.8,144.8,406.9,144.2z"/> + <path fill="#333333" d="M409.1,146.9v-10h1.2v5.7l2.9-3h1.6l-2.8,2.7l3.1,4.6h-1.5l-2.4-3.7l-0.9,0.8v2.9H409.1z"/> + </g> + <g> + <path fill="#048876" d="M29.4,146.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C29.9,147.4,29.6,146.9,29.4,146.2z"/> + <path fill="#048876" d="M39.8,138.2v3.7c0.6-0.7,1.4-1.1,2.2-1.1c0.4,0,0.8,0.1,1.2,0.2s0.6,0.4,0.8,0.6c0.2,0.3,0.3,0.5,0.4,0.8 + c0.1,0.3,0.1,0.8,0.1,1.4v4.3h-1.9v-3.8c0-0.8,0-1.2-0.1-1.4c-0.1-0.2-0.2-0.4-0.4-0.5c-0.2-0.1-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.2c-0.3,0.2-0.4,0.4-0.6,0.7c-0.1,0.3-0.2,0.8-0.2,1.4v3.6h-1.9v-10H39.8z"/> + <path fill="#048876" d="M46.4,140v-1.8h1.9v1.8H46.4z M46.4,148.3V141h1.9v7.3H46.4z"/> + <path fill="#048876" d="M49.4,141h1.1v-0.5c0-0.6,0.1-1.1,0.2-1.4s0.4-0.5,0.7-0.7c0.3-0.2,0.8-0.3,1.3-0.3c0.5,0,1.1,0.1,1.6,0.2 + l-0.3,1.3c-0.3-0.1-0.6-0.1-0.9-0.1c-0.3,0-0.5,0.1-0.6,0.2c-0.1,0.1-0.2,0.4-0.2,0.7v0.5h1.4v1.5h-1.4v5.7h-1.9v-5.7h-1.1V141z" + /> + <path fill="#048876" d="M58.3,141v1.5H57v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V141H55v-1.4l1.9-1.1v2.6H58.3z"/> + </g> + <g> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M107.9,157.4c0,2.2-1.8,4-4,4h-81c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h81c2.2,0,4,1.8,4,4V157.4z"/> + </g> + <g> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M52.9,471.4c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V471.4z"/> + </g> + <g> + <g> + <path fill="#048876" d="M32.6,463.3v-10h6.9v1.7h-4.8v2.4h4.2v1.7h-4.2v4.3H32.6z"/> + </g> + </g> + <g> + <g> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M635.9,342.4c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V342.4z"/> + </g> + <g> + <g> + <path fill="#048876" d="M614.8,334.2v-1.8l5.3-6.5h-4.7v-1.7h7.3v1.6l-5.5,6.8h5.7v1.7H614.8z"/> + </g> + </g> + </g> + <g> + <g> + <path fill="#048876" d="M555,396.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9c-0.2-0.2-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1 + l1.9,0.3c-0.2,0.9-0.6,1.5-1.1,2s-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C554.4,394.8,554.8,395.4,555,396.2z"/> + <path fill="#048876" d="M556.4,394h1.8v1c0.6-0.8,1.4-1.2,2.3-1.2c0.5,0,0.9,0.1,1.2,0.3s0.6,0.5,0.8,0.9c0.3-0.4,0.7-0.7,1-0.9 + s0.8-0.3,1.2-0.3c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.6,0.5,0.8,1c0.1,0.3,0.2,0.8,0.2,1.5v4.6h-1.9v-4.1c0-0.7-0.1-1.2-0.2-1.4 + c-0.2-0.3-0.5-0.4-0.8-0.4c-0.3,0-0.5,0.1-0.8,0.2s-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5v3.5h-1.9v-4c0-0.7,0-1.2-0.1-1.4 + s-0.2-0.4-0.3-0.5c-0.1-0.1-0.3-0.2-0.6-0.2c-0.3,0-0.6,0.1-0.8,0.2s-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5v3.5h-1.9V394z"/> + <path fill="#048876" d="M575.6,401.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5c-0.2-0.1-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3s-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V394h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V401.3z"/> + <path fill="#048876" d="M584.2,401.3h-1.8v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V401.3z M579,397.5 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C579.2,396.2,579,396.8,579,397.5z"/> + </g> + </g> + <g> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M591.9,410.4c0,2.2-1.8,4-4,4h-43c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h43c2.2,0,4,1.8,4,4V410.4z"/> + </g> + <g> + <g> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M733.9,409.4c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V409.4z"/> + </g> + <g> + <g> + <path fill="#048876" d="M712.8,401.2v-1.8l5.3-6.5h-4.7v-1.7h7.3v1.6l-5.5,6.8h5.7v1.7H712.8z"/> + </g> + </g> + </g> + <g> + <path fill="#333333" d="M52.2,80.5l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C52.8,81.7,52.4,81.2,52.2,80.5z"/> + <path fill="#333333" d="M64.9,80.3l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S64.8,80.6,64.9,80.3z M65,78.3c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H65z"/> + <path fill="#333333" d="M68.5,82.6v-10h1.9v10H68.5z"/> + <path fill="#333333" d="M76.6,80.3l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + C72,80.8,71.8,80,71.8,79c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S76.4,80.6,76.6,80.3z M76.7,78.3c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H76.7z"/> + <path fill="#333333" d="M86.5,77.5l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C85.9,76.1,86.2,76.7,86.5,77.5z"/> + <path fill="#333333" d="M91.3,75.3v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9v-1.5H88v-1.4l1.9-1.1v2.6H91.3z"/> + <path fill="#333333" d="M97.9,77.5l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9 + c-0.1-0.1-0.1-0.3-0.2-0.6c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7c-0.4,0.2-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6 + S96,81.2,96,80.6c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2 + c0-0.4-0.1-0.6-0.3-0.8c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C98.2,76.9,98,77.2,97.9,77.5z M100.5,79.1 + c-0.2,0.1-0.6,0.2-1.2,0.3s-0.9,0.2-1,0.3c-0.3,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7c0.2,0.2,0.5,0.3,0.8,0.3 + c0.3,0,0.7-0.1,1-0.3c0.2-0.2,0.4-0.4,0.5-0.6c0-0.2,0.1-0.5,0.1-0.9V79.1z"/> + <path fill="#333333" d="M110.9,82.6h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9v-7.3h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V82.6z"/> + <path fill="#333333" d="M120.9,80.3l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S120.8,80.6,120.9,80.3z M121,78.3c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H121z"/> + <path fill="#333333" d="M131.1,82.6h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9v-7.3h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V82.6z"/> + <path fill="#333333" d="M136.4,75.3v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9v-1.5h0.9v-1.4l1.9-1.1v2.6H136.4z"/> + <path fill="#333333" d="M137.7,74.3v-1.8h1.9v1.8H137.7z M137.7,82.6v-7.3h1.9v7.3H137.7z"/> + <path fill="#333333" d="M144.9,75.3v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9v-1.5h0.9v-1.4l1.9-1.1v2.6H144.9z"/> + <path fill="#333333" d="M145.3,75.3h2l1.7,5.2l1.7-5.2h2l-2.6,7l-0.5,1.3c-0.2,0.4-0.3,0.7-0.5,1c-0.2,0.2-0.3,0.4-0.5,0.5 + c-0.2,0.1-0.4,0.2-0.7,0.3c-0.3,0.1-0.6,0.1-1,0.1c-0.4,0-0.7,0-1.1-0.1l-0.2-1.5c0.3,0.1,0.6,0.1,0.8,0.1c0.4,0,0.8-0.1,1-0.4 + c0.2-0.3,0.4-0.6,0.5-1L145.3,75.3z"/> + <path fill="#333333" d="M159.2,82.6l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3h-1.3l-1.2-4.3l-0.3-1.2l-1.5,5.6H159.2z"/> + <path fill="#333333" d="M168,74v-1.4h1.2V74H168z M168,82.6v-7.3h1.2v7.3H168z"/> + <path fill="#333333" d="M173.8,81.5l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C173.4,81.5,173.5,81.5,173.8,81.5z"/> + <path fill="#333333" d="M175,82.6v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9s0.3,0.9,0.3,1.6 + v4.6h-1.2V78c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.5,0.4-0.7,0.8s-0.2,0.8-0.2,1.3v4 + H175z"/> + <path fill="#333333" d="M186.6,82.6v-10h1.2v10H186.6z"/> + <path fill="#333333" d="M194.7,80.2l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3h-5.4 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C194.3,81.1,194.5,80.7,194.7,80.2z M190.7,78.2h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C190.9,77.1,190.7,77.6,190.7,78.2z"/> + <path fill="#333333" d="M197.8,82.6v-6.3h-1.1v-1h1.1v-0.8c0-0.5,0-0.8,0.1-1.1c0.1-0.3,0.3-0.6,0.6-0.8c0.3-0.2,0.7-0.3,1.3-0.3 + c0.3,0,0.7,0,1.1,0.1l-0.2,1.1c-0.3,0-0.5-0.1-0.7-0.1c-0.4,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.2,0.5-0.2,0.9v0.7h1.4v1H199v6.3H197.8z "/> - <path fill="#333333" d="M153.1,123.8c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1 - C152.4,123.5,152.8,123.6,153.1,123.8z M153.6,129.1c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4 - c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6 - C152.9,129.7,153.3,129.5,153.6,129.1z"/> - <path fill="#333333" d="M160.8,125.1v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H160.8z"/> - <path fill="#333333" d="M172.5,130.2c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C173.4,128.5,173.1,129.5,172.5,130.2z M170.9,129.2 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C170.2,129.8,170.6,129.6,170.9,129.2z"/> - <path fill="#333333" d="M179,132.6l0.2,0c0.2,0,0.4,0,0.5,0c0.2,0,0.3-0.1,0.4-0.2c0.1-0.1,0.2-0.2,0.3-0.5 - c0.1-0.2,0.1-0.4,0.1-0.5l-2.7-7.8h2.2l1.6,5.5l1.5-5.5h2.1l-2.6,7.3c-0.5,1.4-0.9,2.3-1.2,2.6c-0.3,0.3-0.9,0.5-1.7,0.5 - c-0.2,0-0.3,0-0.4,0c-0.1,0-0.3,0-0.5,0V132.6z"/> - <path fill="#333333" d="M192.7,130.2c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C193.7,128.5,193.3,129.5,192.7,130.2z M191.2,129.2 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C190.4,129.8,190.8,129.6,191.2,129.2z"/> - <path fill="#333333" d="M197,123.7v4.5c0,0.4,0,0.7,0.1,1c0.2,0.4,0.5,0.6,1,0.6c0.7,0,1.1-0.3,1.4-0.8c0.1-0.3,0.2-0.7,0.2-1.2 - v-4.1h2v7.5h-1.9v-1.1c0,0-0.1,0.1-0.1,0.2c-0.1,0.1-0.2,0.2-0.3,0.3c-0.3,0.3-0.6,0.5-0.9,0.6c-0.3,0.1-0.6,0.2-1,0.2 - c-1.1,0-1.8-0.4-2.2-1.2c-0.2-0.4-0.3-1.1-0.3-1.9v-4.5H197z"/> - <path fill="#333333" d="M207.7,123.5c0,0,0.1,0,0.2,0v2c-0.1,0-0.2,0-0.3,0s-0.2,0-0.2,0c-0.8,0-1.3,0.3-1.6,0.8 - c-0.2,0.3-0.2,0.7-0.2,1.3v3.6h-2v-7.5h1.9v1.3c0.3-0.5,0.6-0.8,0.8-1C206.6,123.7,207.1,123.5,207.7,123.5 - C207.7,123.5,207.7,123.5,207.7,123.5z"/> - <path fill="#333333" d="M214.5,128.8c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H214.5z" - /> - <path fill="#333333" d="M225.6,123.8c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C224.5,123.5,225.1,123.6,225.6,123.8z M222.7,125.5c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2 - c-0.3-0.3-0.7-0.4-1.2-0.4C223.3,125.1,222.9,125.2,222.7,125.5z"/> - <path fill="#333333" d="M230.5,131.1h-1.9v-10.1h1.9V131.1z"/> - <path fill="#333333" d="M237.3,123.8c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C236.2,123.5,236.7,123.6,237.3,123.8z M234.3,125.5c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2 - c-0.3-0.3-0.7-0.4-1.2-0.4C235,125.1,234.6,125.2,234.3,125.5z"/> - <path fill="#333333" d="M244.6,126.4c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.3,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1s-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3s1.5-1.1,2.6-1.1 - c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H244.6z"/> - <path fill="#333333" d="M247.2,125.1v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H247.2z"/> - <path fill="#333333" d="M254.6,122.8h-2V121h2V122.8z M252.7,123.7h2v7.5h-2V123.7z"/> - <path fill="#333333" d="M262.7,130.2c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C263.7,128.5,263.4,129.5,262.7,130.2z M261.2,129.2 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C260.4,129.8,260.9,129.6,261.2,129.2z"/> - <path fill="#333333" d="M271.1,124.1c0.5,0.4,0.7,1.1,0.7,2v5h-2v-4.5c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C270,123.5,270.6,123.7,271.1,124.1z"/> - <path fill="#333333" d="M278.1,123.8l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3h-1.3l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3 - H278.1z"/> - <path fill="#333333" d="M287.6,121.1h1.3v1.4h-1.3V121.1z M287.6,123.9h1.3v7.3h-1.3V123.9z"/> - <path fill="#333333" d="M291,121.8h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V121.8z"/> - <path fill="#333333" d="M294.6,121.1h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V121.1z"/> - <path fill="#333333" d="M307,128.8c0,0.4,0.1,0.7,0.3,0.9c0.3,0.4,0.9,0.6,1.6,0.6c0.5,0,0.9-0.1,1.2-0.3c0.4-0.2,0.5-0.5,0.5-0.9 - c0-0.3-0.1-0.6-0.4-0.7c-0.2-0.1-0.5-0.2-1.1-0.3l-1-0.2c-0.6-0.2-1.1-0.3-1.4-0.5c-0.5-0.3-0.8-0.8-0.8-1.4 - c0-0.7,0.3-1.3,0.8-1.7s1.2-0.6,2-0.6c1.1,0,1.9,0.3,2.4,1c0.3,0.4,0.5,0.9,0.5,1.3h-1.2c0-0.3-0.1-0.5-0.3-0.8 - c-0.3-0.3-0.8-0.5-1.5-0.5c-0.5,0-0.8,0.1-1.1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.2,0.6,0.5,0.8c0.2,0.1,0.5,0.2,0.8,0.3 - l0.8,0.2c0.9,0.2,1.5,0.4,1.8,0.6c0.5,0.3,0.7,0.8,0.7,1.5c0,0.7-0.2,1.2-0.8,1.7c-0.5,0.5-1.3,0.7-2.3,0.7 - c-1.1,0-1.9-0.2-2.3-0.7c-0.5-0.5-0.7-1.1-0.7-1.8H307z"/> - <path fill="#333333" d="M313.3,121.1h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7H318v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V121.1z"/> - <path fill="#333333" d="M321.1,121.1h1.3v1.4h-1.3V121.1z M321.1,123.9h1.3v7.3h-1.3V123.9z"/> - <path fill="#333333" d="M324.8,121.6c0.3-0.4,0.8-0.6,1.7-0.6c0.1,0,0.2,0,0.2,0s0.2,0,0.3,0v1.1c-0.1,0-0.2,0-0.3,0 - c-0.1,0-0.1,0-0.2,0c-0.4,0-0.6,0.1-0.7,0.3c-0.1,0.2-0.1,0.7-0.1,1.5h1.2v1h-1.2v6.3h-1.2v-6.3h-1v-1h1v-1.1 - C324.5,122.2,324.6,121.8,324.8,121.6z"/> - <path fill="#333333" d="M328.3,121.8h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V121.8z"/> - <path fill="#333333" d="M335.6,128.1V127h3v-3h1.2v3h3v1.1h-3v3h-1.2v-3H335.6z"/> - <path fill="#333333" d="M348,121.1h1.2v10H348V121.1z"/> - <path fill="#333333" d="M355.6,124c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8s0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9s1.5-1.1,2.5-1.1C354.6,123.7,355.1,123.8,355.6,124z M356,126.9c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H356z"/> - <path fill="#333333" d="M359.4,121.6c0.3-0.4,0.8-0.6,1.7-0.6c0.1,0,0.2,0,0.2,0s0.2,0,0.3,0v1.1c-0.1,0-0.2,0-0.3,0 - c-0.1,0-0.1,0-0.2,0c-0.4,0-0.6,0.1-0.7,0.3c-0.1,0.2-0.1,0.7-0.1,1.5h1.2v1h-1.2v6.3h-1.2v-6.3h-1v-1h1v-1.1 - C359.2,122.2,359.2,121.8,359.4,121.6z"/> - <path fill="#333333" d="M363,121.8h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V121.8z"/> - <path fill="#333333" d="M375.3,124.2c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C374.1,123.6,374.8,123.8,375.3,124.2z"/> - <path fill="#333333" d="M377.5,121.1h1.2v10h-1.2V121.1z"/> - <path fill="#333333" d="M380.6,121.1h1.3v1.4h-1.3V121.1z M380.6,123.9h1.3v7.3h-1.3V123.9z"/> - <path fill="#333333" d="M388.6,124.2c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C387.4,123.6,388,123.8,388.6,124.2z"/> - <path fill="#333333" d="M390.7,121.1h1.2v5.8l3.2-3.1h1.6l-2.8,2.7l3,4.6h-1.6l-2.3-3.7l-1,1v2.7h-1.2V121.1z"/> + <path fill="#333333" d="M204.1,81.5l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C203.7,81.5,203.9,81.5,204.1,81.5z"/> + <path fill="#333333" d="M213.9,79.9l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C213.6,81,213.8,80.5,213.9,79.9z"/> + <path fill="#333333" d="M216.2,82.6v-10h1.2v10H216.2z"/> + <path fill="#333333" d="M219.3,74v-1.4h1.2V74H219.3z M219.3,82.6v-7.3h1.2v7.3H219.3z"/> + <path fill="#333333" d="M227.2,79.9l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C226.9,81,227.1,80.5,227.2,79.9z"/> + <path fill="#333333" d="M229.4,82.6v-10h1.2v5.7l2.9-3h1.6l-2.8,2.7l3.1,4.6h-1.5l-2.4-3.7l-0.9,0.8v2.9H229.4z"/> </g> <g> - <path fill="#078876" d="M13.1,130.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H13.1z" - /> - <path fill="#078876" d="M24.7,125.2c0.4,0.2,0.7,0.4,0.9,0.7c0.2,0.3,0.3,0.6,0.4,0.9c0,0.3,0.1,0.8,0.1,1.4v4.4h-2V128 - c0-0.4-0.1-0.7-0.2-1c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.2,0.5s-0.4,0.8-0.4,1.5v4h-1.9v-10h1.9v3.6c0.3-0.4,0.6-0.7,1-0.9 - c0.4-0.2,0.8-0.3,1.2-0.3C23.9,124.9,24.3,125,24.7,125.2z"/> - <path fill="#078876" d="M29.9,124.2h-2v-1.8h2V124.2z M27.9,125.1h2v7.5h-2V125.1z"/> - <path fill="#078876" d="M34.9,122.4c0.1,0,0.2,0,0.4,0v1.6c-0.1,0-0.3,0-0.6,0c-0.3,0-0.4,0-0.5,0.2c-0.1,0.1-0.1,0.3-0.1,0.4 - s0,0.4,0,0.6h1.3v1.4h-1.3v6h-1.9v-6H31v-1.4h1.1v-0.5c0-0.8,0.1-1.3,0.4-1.6c0.3-0.4,1-0.7,2-0.7 - C34.7,122.4,34.8,122.4,34.9,122.4z"/> - <path fill="#078876" d="M35.7,126.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H35.7z"/> - </g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M89.5,141.7c0,2.2-1.8,4-4,4h-81c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h81c2.2,0,4,1.8,4,4V141.7z"/> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M34.5,455.7c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V455.7z"/> - <g> - <path fill="#078876" d="M14.3,437.5h7.2v1.8h-5.1v2.3h4.5v1.8h-4.5v4.2h-2.1V437.5z"/> + <path fill="#333333" d="M86.9,271.4c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C87,272.9,86.9,272.2,86.9,271.4z M88.8,271.5c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S88.8,270.8,88.8,271.5z"/> + <path fill="#333333" d="M97.7,275.1h-1.9v-7.3h1.8v1c0.3-0.5,0.6-0.8,0.8-1c0.2-0.2,0.5-0.2,0.8-0.2c0.4,0,0.9,0.1,1.3,0.4 + l-0.6,1.7c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.1-0.3,0.4-0.4,0.8c-0.1,0.4-0.2,1.2-0.2,2.4V275.1z"/> + <path fill="#333333" d="M101.2,275.1v-10h1.9v3.6c0.6-0.7,1.3-1,2.1-1c0.9,0,1.6,0.3,2.2,1c0.6,0.6,0.9,1.6,0.9,2.8 + c0,1.2-0.3,2.2-0.9,2.9c-0.6,0.7-1.3,1-2.1,1c-0.4,0-0.8-0.1-1.2-0.3c-0.4-0.2-0.8-0.5-1-0.9v1.1H101.2z M103.1,271.3 + c0,0.8,0.1,1.3,0.4,1.7c0.3,0.5,0.8,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.5c0.3-0.4,0.4-0.9,0.4-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C103.3,270.1,103.1,270.6,103.1,271.3z"/> + <path fill="#333333" d="M109.9,266.9v-1.8h1.9v1.8H109.9z M109.9,275.1v-7.3h1.9v7.3H109.9z"/> + <path fill="#333333" d="M117.1,267.9v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2H113v-1.5h0.9v-1.4l1.9-1.1v2.6H117.1z"/> + <path fill="#333333" d="M123.6,275.1l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3h-1.3l-1.2-4.3l-0.3-1.2l-1.5,5.6H123.6z"/> + <path fill="#333333" d="M132.3,266.5v-1.4h1.2v1.4H132.3z M132.3,275.1v-7.3h1.2v7.3H132.3z"/> + <path fill="#333333" d="M138.1,274l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C137.7,274.1,137.9,274.1,138.1,274z"/> + <path fill="#333333" d="M139.3,275.1v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6H144v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.5,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H139.3z"/> + <path fill="#333333" d="M151,275.1v-7.3h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H151z"/> + <path fill="#333333" d="M155.7,266.5v-1.4h1.2v1.4H155.7z M155.7,275.1v-7.3h1.2v7.3H155.7z"/> + <path fill="#333333" d="M158.6,275.7l1.2,0.2c0,0.4,0.2,0.6,0.4,0.8c0.3,0.2,0.7,0.3,1.3,0.3c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.5-0.5,0.6-1c0.1-0.3,0.1-0.8,0.1-1.6c-0.5,0.6-1.2,1-2,1c-1,0-1.8-0.4-2.3-1.1s-0.8-1.6-0.8-2.6c0-0.7,0.1-1.3,0.4-1.9 + c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.7-0.5c0.9,0,1.6,0.3,2.1,1v-0.9h1.1v6.3c0,1.1-0.1,1.9-0.3,2.4c-0.2,0.5-0.6,0.8-1.1,1.1 + s-1.1,0.4-1.8,0.4c-0.9,0-1.6-0.2-2.1-0.6C158.8,277.1,158.5,276.5,158.6,275.7z M159.6,271.4c0,1,0.2,1.6,0.6,2.1 + c0.4,0.4,0.9,0.7,1.4,0.7c0.6,0,1-0.2,1.4-0.7c0.4-0.4,0.6-1.1,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.4-0.7 + c-0.5,0-1,0.2-1.4,0.7C159.8,269.8,159.6,270.5,159.6,271.4z"/> + <path fill="#333333" d="M166.6,275.1v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.5,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H166.6z"/> + <path fill="#333333" d="M177,274l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C176.6,274.1,176.8,274.1,177,274z"/> + <path fill="#333333" d="M186.9,272.5l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C186.6,273.5,186.8,273.1,186.9,272.5z"/> + <path fill="#333333" d="M189.1,275.1v-10h1.2v10H189.1z"/> + <path fill="#333333" d="M192.2,266.5v-1.4h1.2v1.4H192.2z M192.2,275.1v-7.3h1.2v7.3H192.2z"/> + <path fill="#333333" d="M200.1,272.5l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C199.8,273.5,200,273.1,200.1,272.5z"/> + <path fill="#333333" d="M202.4,275.1v-10h1.2v5.7l2.9-3h1.6l-2.8,2.7l3.1,4.6h-1.5l-2.4-3.7l-0.9,0.8v2.9H202.4z"/> + <path fill="#333333" d="M215.8,273.5v-2.7h-2.7v-1.1h2.7v-2.7h1.2v2.7h2.7v1.1H217v2.7H215.8z"/> + <path fill="#333333" d="M230,275.1v-0.9c-0.5,0.7-1.1,1.1-2,1.1c-0.6,0-1.1-0.2-1.6-0.5s-0.9-0.8-1.1-1.3c-0.3-0.6-0.4-1.2-0.4-2 + c0-0.7,0.1-1.4,0.4-2c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.6-0.5c0.4,0,0.8,0.1,1.2,0.3c0.3,0.2,0.6,0.4,0.8,0.7v-3.6h1.2v10 + H230z M226.1,271.5c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.4,0.7c0.5,0,1-0.2,1.4-0.7c0.4-0.4,0.6-1.1,0.6-2 + c0-1-0.2-1.7-0.6-2.2s-0.9-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7C226.3,269.8,226.1,270.5,226.1,271.5z"/> + <path fill="#333333" d="M233.1,275.1v-7.3h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H233.1z"/> + <path fill="#333333" d="M242.5,274.2c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.2-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C242.6,274.9,242.5,274.6,242.5,274.2z M242.4,271.5c-0.4,0.2-1.1,0.3-2,0.5 + c-0.5,0.1-0.9,0.2-1.1,0.2c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3 + c0.5,0,0.9-0.1,1.3-0.3c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V271.5z"/> + <path fill="#333333" d="M245.3,275.7l1.2,0.2c0,0.4,0.2,0.6,0.4,0.8c0.3,0.2,0.7,0.3,1.3,0.3c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.5-0.5,0.6-1c0.1-0.3,0.1-0.8,0.1-1.6c-0.5,0.6-1.2,1-2,1c-1,0-1.8-0.4-2.3-1.1s-0.8-1.6-0.8-2.6c0-0.7,0.1-1.3,0.4-1.9 + c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.7-0.5c0.9,0,1.6,0.3,2.1,1v-0.9h1.1v6.3c0,1.1-0.1,1.9-0.3,2.4c-0.2,0.5-0.6,0.8-1.1,1.1 + s-1.1,0.4-1.8,0.4c-0.9,0-1.6-0.2-2.1-0.6C245.6,277.1,245.3,276.5,245.3,275.7z M246.3,271.4c0,1,0.2,1.6,0.6,2.1 + c0.4,0.4,0.9,0.7,1.4,0.7c0.6,0,1-0.2,1.4-0.7c0.4-0.4,0.6-1.1,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.4-0.7 + c-0.5,0-1,0.2-1.4,0.7C246.5,269.8,246.3,270.5,246.3,271.4z"/> </g> <g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M617.5,326.7c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V326.7z"/> - <g> - <path fill="#078876" d="M596.6,316.7l5.1-6.5h-5v-1.8h7.6v1.7l-5.2,6.6h5.2v1.8h-7.8V316.7z"/> - </g> + <path fill="#333333" d="M87.3,328H89v1.1c0.2-0.4,0.5-0.7,0.9-0.9s0.8-0.3,1.3-0.3c0.8,0,1.6,0.3,2.1,1s0.9,1.6,0.9,2.8 + c0,1.2-0.3,2.2-0.9,2.8c-0.6,0.7-1.3,1-2.2,1c-0.4,0-0.8-0.1-1.1-0.2c-0.3-0.2-0.7-0.4-1-0.8v3.7h-1.9V328z M89.2,331.5 + c0,0.8,0.2,1.4,0.5,1.8c0.3,0.4,0.7,0.6,1.2,0.6c0.4,0,0.8-0.2,1.1-0.5c0.3-0.4,0.4-0.9,0.4-1.8c0-0.8-0.2-1.3-0.5-1.7 + c-0.3-0.4-0.7-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.2,0.5C89.3,330.3,89.2,330.8,89.2,331.5z"/> + <path fill="#333333" d="M97.3,330.2l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9 + c-0.1-0.1-0.1-0.3-0.2-0.6c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7c-0.4,0.2-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6 + s-0.6-0.9-0.6-1.5c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2 + c0-0.4-0.1-0.6-0.3-0.8c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C97.6,329.7,97.4,329.9,97.3,330.2z M99.9,331.8 + c-0.2,0.1-0.6,0.2-1.2,0.3s-0.9,0.2-1,0.3c-0.3,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7c0.2,0.2,0.5,0.3,0.8,0.3 + c0.3,0,0.7-0.1,1-0.3c0.2-0.2,0.4-0.4,0.5-0.6c0-0.2,0.1-0.5,0.1-0.9V331.8z"/> + <path fill="#333333" d="M110.2,335.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V328h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V335.3z"/> + <path fill="#333333" d="M117.3,335.3l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3h-1.3l-1.2-4.3l-0.3-1.2l-1.5,5.6H117.3z"/> + <path fill="#333333" d="M126.1,326.7v-1.4h1.2v1.4H126.1z M126.1,335.3V328h1.2v7.3H126.1z"/> + <path fill="#333333" d="M131.9,334.2l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5V329h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C131.5,334.2,131.7,334.2,131.9,334.2z"/> + <path fill="#333333" d="M133.1,335.3v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.5,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H133.1z"/> + <path fill="#333333" d="M144.8,335.3V328h1.1v1c0.2-0.4,0.5-0.6,0.9-0.9c0.4-0.2,0.8-0.3,1.3-0.3c0.5,0,1,0.1,1.3,0.3 + c0.3,0.2,0.6,0.5,0.7,0.9c0.6-0.8,1.3-1.3,2.2-1.3c0.7,0,1.3,0.2,1.7,0.6c0.4,0.4,0.6,1,0.6,1.8v5h-1.2v-4.6c0-0.5,0-0.8-0.1-1.1 + c-0.1-0.2-0.2-0.4-0.4-0.5c-0.2-0.1-0.5-0.2-0.7-0.2c-0.5,0-0.9,0.2-1.3,0.5c-0.3,0.3-0.5,0.9-0.5,1.6v4.2h-1.2v-4.7 + c0-0.5-0.1-1-0.3-1.2c-0.2-0.3-0.5-0.4-1-0.4c-0.3,0-0.7,0.1-1,0.3s-0.5,0.4-0.6,0.8c-0.1,0.4-0.2,0.9-0.2,1.5v3.8H144.8z"/> + <path fill="#333333" d="M156.5,326.7v-1.4h1.2v1.4H156.5z M156.5,335.3V328h1.2v7.3H156.5z"/> + <path fill="#333333" d="M164.3,335.3v-0.9c-0.5,0.7-1.1,1.1-2,1.1c-0.6,0-1.1-0.2-1.6-0.5s-0.9-0.8-1.1-1.3 + c-0.3-0.6-0.4-1.2-0.4-2c0-0.7,0.1-1.4,0.4-2c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.6-0.5c0.4,0,0.8,0.1,1.2,0.3 + c0.3,0.2,0.6,0.4,0.8,0.7v-3.6h1.2v10H164.3z M160.4,331.6c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.4,0.7c0.5,0,1-0.2,1.4-0.7 + c0.4-0.4,0.6-1.1,0.6-2c0-1-0.2-1.7-0.6-2.2s-0.9-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7C160.6,330,160.4,330.7,160.4,331.6z"/> + <path fill="#333333" d="M172.1,335.3v-0.9c-0.5,0.7-1.1,1.1-2,1.1c-0.6,0-1.1-0.2-1.6-0.5s-0.9-0.8-1.1-1.3 + c-0.3-0.6-0.4-1.2-0.4-2c0-0.7,0.1-1.4,0.4-2c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.6-0.5c0.4,0,0.8,0.1,1.2,0.3 + c0.3,0.2,0.6,0.4,0.8,0.7v-3.6h1.2v10H172.1z M168.2,331.6c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.4,0.7c0.5,0,1-0.2,1.4-0.7 + c0.4-0.4,0.6-1.1,0.6-2c0-1-0.2-1.7-0.6-2.2s-0.9-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7C168.4,330,168.2,330.7,168.2,331.6z"/> + <path fill="#333333" d="M175.1,335.3v-10h1.2v10H175.1z"/> + <path fill="#333333" d="M183.2,332.9l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3h-5.4 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C182.8,333.8,183,333.5,183.2,332.9z M179.2,330.9h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C179.4,329.8,179.2,330.3,179.2,330.9z"/> + <path fill="#333333" d="M194.7,332.6l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C194.4,333.7,194.6,333.2,194.7,332.6z"/> + <path fill="#333333" d="M196.9,335.3v-10h1.2v10H196.9z"/> + <path fill="#333333" d="M200,326.7v-1.4h1.2v1.4H200z M200,335.3V328h1.2v7.3H200z"/> + <path fill="#333333" d="M207.9,332.6l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C207.6,333.7,207.8,333.2,207.9,332.6z"/> + <path fill="#333333" d="M210.2,335.3v-10h1.2v5.7l2.9-3h1.6l-2.8,2.7l3.1,4.6h-1.5l-2.4-3.7l-0.9,0.8v2.9H210.2z"/> + <path fill="#333333" d="M223.6,333.7v-2.7h-2.7v-1.1h2.7V327h1.2v2.7h2.7v1.1h-2.7v2.7H223.6z"/> + <path fill="#333333" d="M237.8,335.3v-0.9c-0.5,0.7-1.1,1.1-2,1.1c-0.6,0-1.1-0.2-1.6-0.5s-0.9-0.8-1.1-1.3 + c-0.3-0.6-0.4-1.2-0.4-2c0-0.7,0.1-1.4,0.4-2c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.6-0.5c0.4,0,0.8,0.1,1.2,0.3 + c0.3,0.2,0.6,0.4,0.8,0.7v-3.6h1.2v10H237.8z M233.9,331.6c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.4,0.7c0.5,0,1-0.2,1.4-0.7 + c0.4-0.4,0.6-1.1,0.6-2c0-1-0.2-1.7-0.6-2.2s-0.9-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7C234.1,330,233.9,330.7,233.9,331.6z"/> + <path fill="#333333" d="M240.9,335.3V328h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H240.9z"/> + <path fill="#333333" d="M250.3,334.4c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.2-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C250.4,335,250.3,334.7,250.3,334.4z M250.2,331.6c-0.4,0.2-1.1,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.1,0.2 + c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.3-0.3 + c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V331.6z"/> + <path fill="#333333" d="M253.1,335.9l1.2,0.2c0,0.4,0.2,0.6,0.4,0.8c0.3,0.2,0.7,0.3,1.3,0.3c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.5-0.5,0.6-1c0.1-0.3,0.1-0.8,0.1-1.6c-0.5,0.6-1.2,1-2,1c-1,0-1.8-0.4-2.3-1.1s-0.8-1.6-0.8-2.6c0-0.7,0.1-1.3,0.4-1.9 + c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.7-0.5c0.9,0,1.6,0.3,2.1,1V328h1.1v6.3c0,1.1-0.1,1.9-0.3,2.4c-0.2,0.5-0.6,0.8-1.1,1.1 + s-1.1,0.4-1.8,0.4c-0.9,0-1.6-0.2-2.1-0.6C253.3,337.2,253.1,336.7,253.1,335.9z M254.1,331.5c0,1,0.2,1.6,0.6,2.1 + c0.4,0.4,0.9,0.7,1.4,0.7c0.6,0,1-0.2,1.4-0.7c0.4-0.4,0.6-1.1,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.4-0.7 + c-0.5,0-1,0.2-1.4,0.7C254.3,330,254.1,330.6,254.1,331.5z"/> </g> <g> - <path fill="#078876" d="M534.7,380.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.4,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4s0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1s-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3s1.5-1.1,2.6-1.1 - c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H534.7z"/> - <path fill="#078876" d="M547.3,378.1c0.3,0.1,0.6,0.4,0.9,0.7c0.2,0.3,0.4,0.6,0.4,1c0,0.3,0.1,0.6,0.1,1.1l0,4.7h-2v-4.7 - c0-0.3,0-0.5-0.1-0.7c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.1,0.7c-0.1,0.2-0.2,0.5-0.2,0.9v4.4h-2v-4.4c0-0.4,0-0.8-0.1-1 - c-0.2-0.4-0.5-0.5-1-0.5c-0.6,0-0.9,0.2-1.1,0.5c-0.1,0.2-0.2,0.5-0.2,0.9v4.5h-2v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8 - c0.4-0.3,0.9-0.4,1.5-0.4c0.6,0,1,0.1,1.4,0.4c0.3,0.2,0.5,0.5,0.6,0.9c0.3-0.4,0.6-0.8,1-1c0.4-0.2,0.8-0.3,1.3-0.3 - C546.7,377.9,547,378,547.3,378.1z"/> - <path fill="#078876" d="M556.5,378.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V381c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.3,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C555.4,377.9,556,378.1,556.5,378.5z"/> - <path fill="#078876" d="M563,378.2c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1C562.2,377.9,562.6,378,563,378.2z - M563.5,383.5c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6 - c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6S563.2,383.9,563.5,383.5z"/> - </g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M573.5,394.7c0,2.2-1.8,4-4,4h-43c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h43c2.2,0,4,1.8,4,4V394.7z"/> - <g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M715.5,393.7c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V393.7z"/> - <g> - <path fill="#078876" d="M694.6,383.7l5.1-6.5h-5v-1.8h7.6v1.7l-5.2,6.6h5.2v1.8h-7.8V383.7z"/> - </g> + <path fill="#333333" d="M53.1,399.3v-1.5l2.7-3.1c0.4-0.5,0.8-0.9,1-1.1c-0.2,0-0.5,0-0.9,0l-2.6,0V392h6v1.4l-2.8,3.2l-1,1.1 + c0.5,0,0.9,0,1,0h3v1.7H53.1z"/> + <path fill="#333333" d="M60.4,395.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C60.6,397.1,60.4,396.4,60.4,395.5z M62.4,395.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S62.4,394.9,62.4,395.6z"/> + <path fill="#333333" d="M69,395.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C69.2,397.1,69,396.4,69,395.5z M71,395.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6c0.3-0.4,0.5-0.9,0.5-1.7 + c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S71,394.9,71,395.6z"/> + <path fill="#333333" d="M77.8,392h1.8v1c0.6-0.8,1.4-1.2,2.3-1.2c0.5,0,0.9,0.1,1.2,0.3s0.6,0.5,0.8,0.9c0.3-0.4,0.7-0.7,1-0.9 + s0.8-0.3,1.2-0.3c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.6,0.5,0.8,1c0.1,0.3,0.2,0.8,0.2,1.5v4.6h-1.9v-4.1c0-0.7-0.1-1.2-0.2-1.4 + c-0.2-0.3-0.5-0.4-0.8-0.4c-0.3,0-0.5,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5v3.5h-1.9v-4 + c0-0.7,0-1.2-0.1-1.4s-0.2-0.4-0.3-0.5s-0.3-0.2-0.6-0.2c-0.3,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7s-0.2,0.8-0.2,1.5v3.5 + h-1.9V392z"/> + <path fill="#333333" d="M94.3,391v-1.8h1.9v1.8H94.3z M94.3,399.3V392h1.9v7.3H94.3z"/> + <path fill="#333333" d="M104.8,399.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V392h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V399.3z"/> + <path fill="#333333" d="M109.6,399.4l2.5-10.4h1.4l-2.5,10.4H109.6z"/> + <path fill="#333333" d="M118,395.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C118.2,397.1,118,396.4,118,395.5z M120,395.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S120,394.9,120,395.6z"/> + <path fill="#333333" d="M131.8,399.3v-1.1c-0.3,0.4-0.6,0.7-1,0.9s-0.9,0.3-1.4,0.3c-0.5,0-0.9-0.1-1.3-0.3 + c-0.4-0.2-0.7-0.5-0.8-0.9c-0.2-0.4-0.3-0.9-0.3-1.6V392h1.9v3.3c0,1,0,1.6,0.1,1.9c0.1,0.2,0.2,0.4,0.4,0.5 + c0.2,0.1,0.4,0.2,0.7,0.2c0.3,0,0.6-0.1,0.9-0.3c0.3-0.2,0.4-0.4,0.5-0.7c0.1-0.3,0.1-0.9,0.1-2V392h1.9v7.3H131.8z"/> + <path fill="#333333" d="M138.9,392v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V392h0.9v-1.4l1.9-1.1v2.6H138.9z"/> + <path fill="#333333" d="M145.4,399.3l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3h-1.3l-1.2-4.3l-0.3-1.2l-1.5,5.6H145.4z"/> + <path fill="#333333" d="M154.1,390.7v-1.4h1.2v1.4H154.1z M154.1,399.3V392h1.2v7.3H154.1z"/> + <path fill="#333333" d="M159.9,398.2l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5V393h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C159.5,398.2,159.7,398.2,159.9,398.2z"/> + <path fill="#333333" d="M161.1,399.3v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.5,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H161.1z"/> + <path fill="#333333" d="M172.3,397.1l1.2-0.2c0.1,0.5,0.3,0.9,0.6,1.1c0.3,0.3,0.7,0.4,1.3,0.4c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.4-0.5,0.4-0.8c0-0.3-0.1-0.5-0.4-0.7c-0.2-0.1-0.6-0.2-1.3-0.4c-0.9-0.2-1.5-0.4-1.9-0.6c-0.3-0.2-0.6-0.4-0.8-0.7 + c-0.2-0.3-0.3-0.6-0.3-1c0-0.3,0.1-0.6,0.2-0.9c0.1-0.3,0.3-0.5,0.6-0.7c0.2-0.1,0.5-0.3,0.8-0.4c0.3-0.1,0.7-0.1,1.1-0.1 + c0.6,0,1.1,0.1,1.5,0.2s0.7,0.4,1,0.7c0.2,0.3,0.3,0.7,0.4,1.1l-1.2,0.2c-0.1-0.4-0.2-0.7-0.5-0.9c-0.3-0.2-0.6-0.3-1.1-0.3 + c-0.6,0-1,0.1-1.2,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.2,0,0.3,0.2,0.4c0.1,0.1,0.3,0.2,0.5,0.3c0.1,0,0.5,0.2,1.1,0.3 + c0.9,0.2,1.5,0.4,1.8,0.6c0.3,0.1,0.6,0.4,0.8,0.6c0.2,0.3,0.3,0.6,0.3,1.1c0,0.4-0.1,0.8-0.4,1.2c-0.2,0.4-0.6,0.6-1,0.8 + c-0.5,0.2-1,0.3-1.5,0.3c-0.9,0-1.7-0.2-2.2-0.6C172.8,398.5,172.4,397.9,172.3,397.1z"/> + <path fill="#333333" d="M184.5,396.6l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C184.2,397.7,184.4,397.2,184.5,396.6z"/> + <path fill="#333333" d="M186.8,399.3V392h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H186.8z"/> + <path fill="#333333" d="M191,395.6c0-1.3,0.4-2.3,1.1-3c0.6-0.5,1.4-0.8,2.3-0.8c1,0,1.8,0.3,2.4,1c0.6,0.7,1,1.6,1,2.7 + c0,0.9-0.1,1.7-0.4,2.2c-0.3,0.5-0.7,1-1.2,1.2c-0.5,0.3-1.1,0.4-1.8,0.4c-1,0-1.8-0.3-2.5-1C191.3,397.8,191,396.9,191,395.6z + M192.3,395.6c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.7c0.4-0.5,0.6-1.2,0.6-2.1c0-0.9-0.2-1.6-0.6-2 + c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1.1,0.2-1.5,0.7C192.5,394,192.3,394.7,192.3,395.6z"/> + <path fill="#333333" d="M199.2,399.3v-10h1.2v10H199.2z"/> + <path fill="#333333" d="M202.3,399.3v-10h1.2v10H202.3z"/> + <path fill="#333333" d="M206.8,399.3l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3H211l-1.2-4.3l-0.3-1.2l-1.5,5.6H206.8z"/> + <path fill="#333333" d="M215.6,399.3v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.5,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H215.6z"/> + <path fill="#333333" d="M228.3,396.9l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3h-5.4 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C227.9,397.8,228.1,397.5,228.3,396.9z M224.3,394.9h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C224.5,393.8,224.3,394.3,224.3,394.9z"/> + <path fill="#333333" d="M236.1,396.9l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3H232 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C235.7,397.8,235.9,397.5,236.1,396.9z M232.1,394.9h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C232.3,393.8,232.1,394.3,232.1,394.9z"/> + <path fill="#333333" d="M238.9,399.3v-10h1.2v10H238.9z"/> </g> <g> - <path fill="#333333" d="M35.9,64.5c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H35.9z" - /> - <path fill="#333333" d="M47.1,59.6c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5C49,62.5,49,63,49,63.7h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C45.9,59.2,46.5,59.3,47.1,59.6z - M44.1,61.2c-0.3,0.3-0.4,0.7-0.5,1.2H47c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C44.8,60.8,44.4,61,44.1,61.2z"/> - <path fill="#333333" d="M52,66.9H50V56.8H52V66.9z"/> - <path fill="#333333" d="M58.7,59.6c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C57.6,59.2,58.2,59.3,58.7,59.6z - M55.8,61.2c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C56.5,60.8,56.1,61,55.8,61.2z"/> - <path fill="#333333" d="M66.1,62.1c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.4,1c-0.1,0.3-0.2,0.8-0.2,1.4 - c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2c0,0.6-0.3,1.2-0.6,1.7 - c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1c-0.6-0.7-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3s1.5-1.1,2.6-1.1 - c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H66.1z"/> - <path fill="#333333" d="M68.7,60.9v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H68.7z"/> - <path fill="#333333" d="M80.9,62.3c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6 - c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7h-1.9c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1 - c0.8,0,1.5,0.2,2.2,0.5c0.6,0.3,1,0.9,1,1.8V65c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5c0.1,0.1,0.2,0.2,0.3,0.2v0.3h-2.1 - c-0.1-0.2-0.1-0.3-0.1-0.4c0-0.1,0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6 - c-0.4-0.4-0.7-0.9-0.7-1.6c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L80.9,62.3z M82.1,63.2c-0.1,0.1-0.3,0.1-0.4,0.2 - c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7 - c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4c0.4-0.2,0.5-0.7,0.6-1.3V63.2z"/> - <path fill="#333333" d="M91.8,59.8c0.5,0.4,0.7,1.1,0.7,2v5h-2v-4.5c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C90.7,59.2,91.3,59.4,91.8,59.8z"/> - <path fill="#333333" d="M103.1,59.6c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C102,59.2,102.6,59.3,103.1,59.6z - M100.2,61.2c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C100.8,60.8,100.4,61,100.2,61.2z"/> - <path fill="#333333" d="M112,59.8c0.5,0.4,0.7,1.1,0.7,2v5h-2v-4.5c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4H106v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C110.9,59.2,111.5,59.4,112,59.8z"/> - <path fill="#333333" d="M113.8,60.9v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H113.8z"/> - <path fill="#333333" d="M121.2,58.5h-2v-1.8h2V58.5z M119.2,59.4h2v7.5h-2V59.4z"/> - <path fill="#333333" d="M122.3,60.9v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H122.3z"/> - <path fill="#333333" d="M128.1,68.3l0.2,0c0.2,0,0.4,0,0.5,0c0.2,0,0.3-0.1,0.4-0.2c0.1-0.1,0.2-0.2,0.3-0.5 - c0.1-0.2,0.1-0.4,0.1-0.5l-2.7-7.8h2.2l1.6,5.5l1.5-5.5h2.1l-2.6,7.3c-0.5,1.4-0.9,2.3-1.2,2.6c-0.3,0.3-0.9,0.5-1.7,0.5 - c-0.2,0-0.3,0-0.4,0c-0.1,0-0.3,0-0.5,0V68.3z"/> - <path fill="#333333" d="M140,59.5l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3H145l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3H140z"/> - <path fill="#333333" d="M149.6,56.8h1.3v1.4h-1.3V56.8z M149.6,59.6h1.3v7.3h-1.3V59.6z"/> - <path fill="#333333" d="M152.9,57.5h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V57.5z"/> - <path fill="#333333" d="M156.6,56.8h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V56.8z"/> - <path fill="#333333" d="M168.3,56.8h1.2v10h-1.2V56.8z"/> - <path fill="#333333" d="M175.9,59.7c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8c0.3,0.5,0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9c0.6-0.7,1.5-1.1,2.5-1.1C174.9,59.4,175.4,59.5,175.9,59.7z M176.3,62.6c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H176.3z"/> - <path fill="#333333" d="M179.7,57.3c0.3-0.4,0.8-0.6,1.7-0.6c0.1,0,0.2,0,0.2,0s0.2,0,0.3,0v1.1c-0.1,0-0.2,0-0.3,0 - c-0.1,0-0.1,0-0.2,0c-0.4,0-0.6,0.1-0.7,0.3c-0.1,0.2-0.1,0.7-0.1,1.5h1.2v1h-1.2v6.3h-1.2v-6.3h-1v-1h1v-1.1 - C179.5,57.9,179.5,57.5,179.7,57.3z"/> - <path fill="#333333" d="M183.3,57.5h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V57.5z"/> - <path fill="#333333" d="M195.6,59.9c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C194.4,59.3,195.1,59.5,195.6,59.9z"/> - <path fill="#333333" d="M197.8,56.8h1.2v10h-1.2V56.8z"/> - <path fill="#333333" d="M200.9,56.8h1.3v1.4h-1.3V56.8z M200.9,59.6h1.3v7.3h-1.3V59.6z"/> - <path fill="#333333" d="M208.9,59.9c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C207.7,59.3,208.3,59.5,208.9,59.9z"/> - <path fill="#333333" d="M211,56.8h1.2v5.8l3.2-3.1h1.6l-2.8,2.7l3,4.6h-1.6l-2.3-3.7l-1,1v2.7H211V56.8z"/> + <path fill="#048876" d="M36.7,526.3h-1.8v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V526.3z M31.6,522.5 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C31.7,521.2,31.6,521.8,31.6,522.5z"/> + <path fill="#048876" d="M42.8,524l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3H40 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S42.7,524.3,42.8,524z M42.9,522c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H42.9z"/> + <path fill="#048876" d="M46.4,526.3v-10h1.9v10H46.4z"/> + <path fill="#048876" d="M54.5,524l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S54.4,524.3,54.5,524z M54.6,522c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H54.6z"/> + <path fill="#048876" d="M61.4,519v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V519h0.9v-1.4l1.9-1.1v2.6H61.4z"/> + <path fill="#048876" d="M66.9,524l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S66.8,524.3,66.9,524z M67,522c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H67z"/> </g> <g> - <path fill="#333333" d="M75,258.5c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C76,256.8,75.7,257.7,75,258.5z M73.5,257.4c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C72.7,258,73.2,257.8,73.5,257.4z"/> - <path fill="#333333" d="M81.5,251.8c0,0,0.1,0,0.2,0v2c-0.1,0-0.2,0-0.3,0s-0.2,0-0.2,0c-0.8,0-1.3,0.3-1.6,0.8 - c-0.2,0.3-0.2,0.7-0.2,1.3v3.6h-2V252h1.9v1.3c0.3-0.5,0.6-0.8,0.8-1C80.4,251.9,80.8,251.8,81.5,251.8 - C81.5,251.8,81.5,251.8,81.5,251.8z"/> - <path fill="#333333" d="M89.2,252.9c0.6,0.7,0.8,1.6,0.8,2.7c0,1.2-0.3,2.1-0.8,2.9c-0.5,0.8-1.3,1.1-2.3,1.1 - c-0.6,0-1.1-0.1-1.5-0.4c-0.2-0.1-0.5-0.4-0.7-0.8v0.9h-1.9v-10.1h1.9v3.6c0.2-0.3,0.5-0.6,0.8-0.8c0.4-0.2,0.8-0.3,1.3-0.3 - C87.9,251.8,88.6,252.2,89.2,252.9z M87.6,257.4c0.3-0.4,0.4-0.9,0.4-1.6c0-0.5-0.1-1-0.2-1.3c-0.3-0.7-0.7-1-1.4-1 - c-0.7,0-1.2,0.3-1.5,1c-0.1,0.3-0.2,0.8-0.2,1.3c0,0.6,0.1,1.2,0.4,1.6c0.3,0.4,0.7,0.6,1.3,0.6C86.9,258,87.3,257.8,87.6,257.4z" - /> - <path fill="#333333" d="M93.4,251.1h-2v-1.8h2V251.1z M91.4,252h2v7.5h-2V252z"/> - <path fill="#333333" d="M94.5,253.4V252h1V250h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H94.5z"/> - <path fill="#333333" d="M104.4,252.1l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3h-1.3l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3 - H104.4z"/> - <path fill="#333333" d="M113.9,249.4h1.3v1.4h-1.3V249.4z M113.9,252.1h1.3v7.3h-1.3V252.1z"/> - <path fill="#333333" d="M117.3,250.1h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V250.1z"/> - <path fill="#333333" d="M120.9,249.3h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V249.3z"/> - <path fill="#333333" d="M132.6,252.1h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0v1.3 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V252.1z"/> - <path fill="#333333" d="M137.3,249.4h1.3v1.4h-1.3V249.4z M137.3,252.1h1.3v7.3h-1.3V252.1z"/> - <path fill="#333333" d="M144.4,252.4c0.2,0.2,0.5,0.4,0.7,0.7v-0.9h1.1v6.7c0,0.9-0.1,1.7-0.4,2.2c-0.5,1-1.5,1.5-2.9,1.5 - c-0.8,0-1.4-0.2-2-0.5c-0.5-0.4-0.8-0.9-0.9-1.7h1.3c0.1,0.3,0.2,0.6,0.4,0.8c0.3,0.3,0.7,0.4,1.3,0.4c0.9,0,1.6-0.3,1.8-1 - c0.2-0.4,0.3-1.1,0.2-2.1c-0.2,0.4-0.5,0.7-0.9,0.8c-0.3,0.2-0.8,0.3-1.4,0.3c-0.8,0-1.5-0.3-2.1-0.8c-0.6-0.6-0.9-1.5-0.9-2.8 - c0-1.2,0.3-2.2,0.9-2.9c0.6-0.7,1.3-1,2.2-1C143.5,252,144,252.1,144.4,252.4z M144.6,253.7c-0.4-0.4-0.8-0.7-1.4-0.7 - c-0.9,0-1.5,0.4-1.8,1.2c-0.2,0.4-0.3,1-0.3,1.7c0,0.8,0.2,1.5,0.5,1.9c0.3,0.4,0.8,0.6,1.3,0.6c0.9,0,1.5-0.4,1.9-1.2 - c0.2-0.5,0.3-1,0.3-1.6C145.2,254.8,145,254.2,144.6,253.7z"/> - <path fill="#333333" d="M148.2,249.3h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V249.3z"/> - <path fill="#333333" d="M156.2,250.1h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V250.1z"/> - <path fill="#333333" d="M168.6,252.5c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C167.4,251.9,168,252.1,168.6,252.5z"/> - <path fill="#333333" d="M170.8,249.4h1.2v10h-1.2V249.4z"/> - <path fill="#333333" d="M173.8,249.4h1.3v1.4h-1.3V249.4z M173.8,252.1h1.3v7.3h-1.3V252.1z"/> - <path fill="#333333" d="M181.8,252.5c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C180.6,251.9,181.3,252.1,181.8,252.5z"/> - <path fill="#333333" d="M183.9,249.4h1.2v5.8l3.2-3.1h1.6l-2.8,2.7l3,4.6h-1.6l-2.3-3.7l-1,1v2.7h-1.2V249.4z"/> - <path fill="#333333" d="M194.6,256.4v-1.1h3v-3h1.2v3h3v1.1h-3v3h-1.2v-3H194.6z"/> - <path fill="#333333" d="M210.9,252.3c0.2,0.1,0.5,0.4,0.7,0.7v-3.7h1.2v10.1h-1.1v-1c-0.3,0.5-0.6,0.8-1,1 - c-0.4,0.2-0.8,0.3-1.3,0.3c-0.8,0-1.5-0.3-2.1-1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.1,0.3-2,0.8-2.8c0.5-0.8,1.3-1.2,2.3-1.2 - C210.1,252,210.5,252.1,210.9,252.3z M208.2,257.8c0.3,0.5,0.9,0.8,1.6,0.8c0.6,0,1-0.2,1.4-0.7c0.4-0.5,0.5-1.2,0.5-2.1 - c0-0.9-0.2-1.6-0.6-2.1c-0.4-0.4-0.8-0.7-1.4-0.7c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.5-0.6,1.2-0.6,2.1 - C207.7,256.6,207.8,257.3,208.2,257.8z"/> - <path fill="#333333" d="M214.7,252.1h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0v1.3 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V252.1z"/> - <path fill="#333333" d="M223.3,255c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.3,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L223.3,255z M220.7,258.3c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C220.3,257.8,220.4,258.1,220.7,258.3z"/> - <path fill="#333333" d="M231.2,252.4c0.2,0.2,0.5,0.4,0.7,0.7v-0.9h1.1v6.7c0,0.9-0.1,1.7-0.4,2.2c-0.5,1-1.5,1.5-2.9,1.5 - c-0.8,0-1.4-0.2-2-0.5c-0.5-0.4-0.8-0.9-0.9-1.7h1.3c0.1,0.3,0.2,0.6,0.4,0.8c0.3,0.3,0.7,0.4,1.3,0.4c0.9,0,1.6-0.3,1.8-1 - c0.2-0.4,0.3-1.1,0.2-2.1c-0.2,0.4-0.5,0.7-0.9,0.8c-0.3,0.2-0.8,0.3-1.4,0.3c-0.8,0-1.5-0.3-2.1-0.8c-0.6-0.6-0.9-1.5-0.9-2.8 - c0-1.2,0.3-2.2,0.9-2.9c0.6-0.7,1.3-1,2.2-1C230.3,252,230.8,252.1,231.2,252.4z M231.4,253.7c-0.4-0.4-0.8-0.7-1.4-0.7 - c-0.9,0-1.5,0.4-1.8,1.2c-0.2,0.4-0.3,1-0.3,1.7c0,0.8,0.2,1.5,0.5,1.9c0.3,0.4,0.8,0.6,1.3,0.6c0.9,0,1.5-0.4,1.9-1.2 - c0.2-0.5,0.3-1,0.3-1.6C231.9,254.8,231.7,254.2,231.4,253.7z"/> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M90.9,535.4c0,2.2-1.8,4-4,4h-64c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h64c2.2,0,4,1.8,4,4V535.4z"/> </g> <g> - <path fill="#333333" d="M75.1,312.9c0.6,0.6,0.9,1.6,0.9,2.8c0,1.3-0.3,2.3-0.9,3c-0.6,0.7-1.4,1-2.3,1c-0.6,0-1.1-0.1-1.5-0.4 - c-0.2-0.2-0.4-0.4-0.6-0.7v3.9h-1.9v-10.4h1.9v1.1c0.2-0.3,0.4-0.6,0.7-0.8c0.4-0.3,1-0.5,1.6-0.5 - C73.7,311.9,74.5,312.3,75.1,312.9z M73.6,314.3c-0.3-0.4-0.7-0.7-1.3-0.7c-0.7,0-1.2,0.3-1.5,1c-0.1,0.4-0.2,0.8-0.2,1.4 - c0,0.9,0.2,1.5,0.7,1.8c0.3,0.2,0.6,0.3,1,0.3c0.5,0,1-0.2,1.3-0.6c0.3-0.4,0.4-1,0.4-1.7C74,315.3,73.9,314.8,73.6,314.3z"/> - <path fill="#333333" d="M80.3,315c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6c-0.2-0.1-0.5-0.2-0.9-0.2 - c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7h-1.9c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1c0.8,0,1.5,0.2,2.2,0.5 - c0.6,0.3,1,0.9,1,1.8v3.4c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5c0.1,0.1,0.2,0.2,0.3,0.2v0.3h-2.1c-0.1-0.2-0.1-0.3-0.1-0.4 - c0-0.1,0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.7-0.9-0.7-1.6 - c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L80.3,315z M81.5,315.9c-0.1,0.1-0.3,0.1-0.4,0.2c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1 - c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4 - c0.4-0.2,0.5-0.7,0.6-1.3V315.9z"/> - <path fill="#333333" d="M91.2,312.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V315c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C90.1,311.9,90.7,312.1,91.2,312.5z"/> - <path fill="#333333" d="M98.2,312.2l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3h-1.3l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3H98.2 + <path fill="#333333" d="M110,526.3h-1.8v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V526.3z M104.8,522.5 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C105,521.2,104.8,521.8,104.8,522.5z"/> + <path fill="#333333" d="M116.1,524l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S116,524.3,116.1,524z M116.2,522c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H116.2z"/> + <path fill="#333333" d="M119.6,526.3v-10h1.9v10H119.6z"/> + <path fill="#333333" d="M127.7,524l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S127.6,524.3,127.7,524z M127.8,522c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H127.8z"/> + <path fill="#333333" d="M134.7,519v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V519h0.9v-1.4l1.9-1.1v2.6H134.7z"/> + <path fill="#333333" d="M140.2,524l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S140.1,524.3,140.2,524z M140.3,522c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H140.3z"/> + <path fill="#333333" d="M147,524.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.3,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C147.5,525.4,147.2,524.9,147,524.2z"/> + <path fill="#333333" d="M159.7,524l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S159.5,524.3,159.7,524z M159.8,522c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H159.8z"/> + <path fill="#333333" d="M163.2,526.3v-10h1.9v10H163.2z"/> + <path fill="#333333" d="M171.3,524l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S171.2,524.3,171.3,524z M171.4,522c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H171.4z"/> + <path fill="#333333" d="M181.2,521.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C180.6,519.8,181,520.4,181.2,521.2z"/> + <path fill="#333333" d="M186,519v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V519h0.9v-1.4l1.9-1.1v2.6H186z"/> + <path fill="#333333" d="M187.4,518v-1.8h1.9v1.8H187.4z M187.4,526.3V519h1.9v7.3H187.4z"/> + <path fill="#333333" d="M190.8,522.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C191,524.1,190.8,523.4,190.8,522.5z M192.8,522.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S192.8,521.9,192.8,522.6z"/> + <path fill="#333333" d="M206.4,526.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V519h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V526.3z"/> + </g> + <g> + <path fill="#333333" d="M683.7,524.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.3,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C684.3,525.4,683.9,524.9,683.7,524.2z"/> + <path fill="#333333" d="M698.5,521.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C697.9,519.8,698.3,520.4,698.5,521.2z"/> + <path fill="#333333" d="M701.4,521.2l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9c0-0.1-0.1-0.3-0.2-0.6 + c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7c-0.4,0.2-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6s-0.6-0.9-0.6-1.5 + c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2c0-0.4-0.1-0.6-0.3-0.8 + c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C701.7,520.7,701.5,520.9,701.4,521.2z M704,522.8c-0.2,0.1-0.6,0.2-1.2,0.3 + s-0.9,0.2-1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7c0.2,0.2,0.5,0.3,0.8,0.3c0.3,0,0.7-0.1,1-0.3 + c0.2-0.2,0.4-0.4,0.5-0.6c0.1-0.2,0.1-0.5,0.1-0.9V522.8z"/> + <path fill="#333333" d="M707.7,526.3v-10h1.9v10H707.7z"/> + <path fill="#333333" d="M715.8,524l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3H713 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S715.7,524.3,715.8,524z M715.9,522c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H715.9z"/> + <path fill="#333333" d="M723.3,519h1.8v1.1c0.2-0.4,0.5-0.7,0.9-0.9s0.8-0.3,1.3-0.3c0.8,0,1.6,0.3,2.1,1s0.9,1.6,0.9,2.8 + c0,1.2-0.3,2.2-0.9,2.8c-0.6,0.7-1.3,1-2.2,1c-0.4,0-0.8-0.1-1.1-0.2c-0.3-0.2-0.7-0.4-1-0.8v3.7h-1.9V519z M725.2,522.5 + c0,0.8,0.2,1.4,0.5,1.8c0.3,0.4,0.7,0.6,1.2,0.6c0.4,0,0.8-0.2,1.1-0.5c0.3-0.4,0.4-0.9,0.4-1.8c0-0.8-0.2-1.3-0.5-1.7 + c-0.3-0.4-0.7-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.2,0.5C725.3,521.3,725.2,521.8,725.2,522.5z"/> + <path fill="#333333" d="M733.7,526.3h-1.9V519h1.8v1c0.3-0.5,0.6-0.8,0.8-1c0.2-0.2,0.5-0.2,0.8-0.2c0.4,0,0.9,0.1,1.3,0.4 + l-0.6,1.7c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.1-0.3,0.4-0.4,0.8c-0.1,0.4-0.2,1.2-0.2,2.4V526.3z"/> + <path fill="#333333" d="M736.9,522.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C737,524.1,736.9,523.4,736.9,522.5z M738.8,522.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S738.8,521.9,738.8,522.6z"/> + <path fill="#333333" d="M745.8,519h1.8v1.1c0.2-0.4,0.5-0.7,0.9-0.9s0.8-0.3,1.3-0.3c0.8,0,1.6,0.3,2.1,1s0.9,1.6,0.9,2.8 + c0,1.2-0.3,2.2-0.9,2.8c-0.6,0.7-1.3,1-2.2,1c-0.4,0-0.8-0.1-1.1-0.2c-0.3-0.2-0.7-0.4-1-0.8v3.7h-1.9V519z M747.7,522.5 + c0,0.8,0.2,1.4,0.5,1.8c0.3,0.4,0.7,0.6,1.2,0.6c0.4,0,0.8-0.2,1.1-0.5c0.3-0.4,0.4-0.9,0.4-1.8c0-0.8-0.2-1.3-0.5-1.7 + c-0.3-0.4-0.7-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.2,0.5C747.9,521.3,747.7,521.8,747.7,522.5z"/> + <path fill="#333333" d="M754,522.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C754.1,524.1,754,523.4,754,522.5z M755.9,522.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S755.9,521.9,755.9,522.6z"/> + <path fill="#333333" d="M764.8,526.3h-1.9V519h1.8v1c0.3-0.5,0.6-0.8,0.8-1c0.2-0.2,0.5-0.2,0.8-0.2c0.4,0,0.9,0.1,1.3,0.4 + l-0.6,1.7c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.1-0.3,0.4-0.4,0.8c-0.1,0.4-0.2,1.2-0.2,2.4V526.3z"/> + <path fill="#333333" d="M771.7,519v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V519h0.9v-1.4l1.9-1.1v2.6H771.7z"/> + <path fill="#333333" d="M773.1,518v-1.8h1.9v1.8H773.1z M773.1,526.3V519h1.9v7.3H773.1z"/> + <path fill="#333333" d="M776.5,522.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C776.7,524.1,776.5,523.4,776.5,522.5z M778.5,522.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S778.5,521.9,778.5,522.6z"/> + <path fill="#333333" d="M787,521.2l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9c0-0.1-0.1-0.3-0.2-0.6 + c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7c-0.4,0.2-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6s-0.6-0.9-0.6-1.5 + c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2c0-0.4-0.1-0.6-0.3-0.8 + c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C787.2,520.7,787.1,520.9,787,521.2z M789.5,522.8c-0.2,0.1-0.6,0.2-1.2,0.3 + s-0.9,0.2-1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7c0.2,0.2,0.5,0.3,0.8,0.3c0.3,0,0.7-0.1,1-0.3 + c0.2-0.2,0.4-0.4,0.5-0.6c0.1-0.2,0.1-0.5,0.1-0.9V522.8z"/> + <path fill="#333333" d="M793.3,526.3v-10h1.9v10H793.3z"/> + <path fill="#333333" d="M797.2,526.3v-10h1.9v10H797.2z"/> + <path fill="#333333" d="M800.2,519h2l1.7,5.2l1.7-5.2h2l-2.6,7l-0.5,1.3c-0.2,0.4-0.3,0.7-0.5,1c-0.2,0.2-0.3,0.4-0.5,0.5 + c-0.2,0.1-0.4,0.2-0.7,0.3c-0.3,0.1-0.6,0.1-1,0.1c-0.4,0-0.7,0-1.1-0.1l-0.2-1.5c0.3,0.1,0.6,0.1,0.8,0.1c0.4,0,0.8-0.1,1-0.4 + c0.2-0.3,0.4-0.6,0.5-1L800.2,519z"/> + <path fill="#333333" d="M813.8,526.3h-1.1v-10h1.2v3.6c0.5-0.7,1.2-1,2-1c0.4,0,0.9,0.1,1.3,0.3c0.4,0.2,0.7,0.4,1,0.8 + c0.3,0.3,0.5,0.7,0.6,1.2c0.1,0.5,0.2,1,0.2,1.5c0,1.2-0.3,2.2-0.9,2.9s-1.4,1-2.2,1c-0.9,0-1.5-0.4-2-1.1V526.3z M813.8,522.6 + c0,0.9,0.1,1.5,0.4,1.9c0.4,0.6,0.9,1,1.6,1c0.5,0,1-0.2,1.4-0.7c0.4-0.5,0.6-1.2,0.6-2.1c0-0.9-0.2-1.6-0.6-2.1s-0.8-0.7-1.4-0.7 + c-0.5,0-1,0.2-1.4,0.7C814,521,813.8,521.7,813.8,522.6z"/> + <path fill="#333333" d="M820.4,529.1l-0.1-1.2c0.3,0.1,0.5,0.1,0.7,0.1c0.3,0,0.5,0,0.7-0.1s0.3-0.2,0.4-0.4 + c0.1-0.1,0.2-0.4,0.4-0.9c0-0.1,0.1-0.2,0.1-0.3l-2.8-7.3h1.3l1.5,4.2c0.2,0.5,0.4,1.1,0.5,1.7c0.1-0.6,0.3-1.1,0.5-1.7l1.6-4.2 + h1.2l-2.8,7.4c-0.3,0.8-0.5,1.3-0.7,1.6c-0.2,0.4-0.5,0.7-0.8,0.9c-0.3,0.2-0.6,0.3-1,0.3C821,529.2,820.7,529.2,820.4,529.1z"/> + <path fill="#333333" d="M830.9,524.1l1.2-0.2c0.1,0.5,0.3,0.9,0.6,1.1c0.3,0.3,0.7,0.4,1.3,0.4c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.4-0.5,0.4-0.8c0-0.3-0.1-0.5-0.4-0.7c-0.2-0.1-0.6-0.2-1.3-0.4c-0.9-0.2-1.5-0.4-1.9-0.6c-0.3-0.2-0.6-0.4-0.8-0.7 + c-0.2-0.3-0.3-0.6-0.3-1c0-0.3,0.1-0.6,0.2-0.9c0.1-0.3,0.3-0.5,0.6-0.7c0.2-0.1,0.5-0.3,0.8-0.4c0.3-0.1,0.7-0.1,1.1-0.1 + c0.6,0,1.1,0.1,1.5,0.2s0.7,0.4,1,0.7c0.2,0.3,0.3,0.7,0.4,1.1l-1.2,0.2c-0.1-0.4-0.2-0.7-0.5-0.9c-0.3-0.2-0.6-0.3-1.1-0.3 + c-0.6,0-1,0.1-1.2,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.2,0.1,0.3,0.2,0.4c0.1,0.1,0.3,0.2,0.5,0.3c0.1,0,0.5,0.2,1.1,0.3 + c0.9,0.2,1.5,0.4,1.8,0.6c0.3,0.1,0.6,0.4,0.8,0.6c0.2,0.3,0.3,0.6,0.3,1.1c0,0.4-0.1,0.8-0.4,1.2c-0.2,0.4-0.6,0.6-1,0.8 + c-0.5,0.2-1,0.3-1.5,0.3c-0.9,0-1.7-0.2-2.2-0.6C831.3,525.5,831,524.9,830.9,524.1z"/> + <path fill="#333333" d="M838.4,526.3v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6H843v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.6,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H838.4z"/> + <path fill="#333333" d="M846.1,517.7v-1.4h1.2v1.4H846.1z M846.1,526.3V519h1.2v7.3H846.1z"/> + <path fill="#333333" d="M849.5,526.3V520h-1.1v-1h1.1v-0.8c0-0.5,0-0.8,0.1-1.1c0.1-0.3,0.3-0.6,0.6-0.8c0.3-0.2,0.7-0.3,1.3-0.3 + c0.3,0,0.7,0,1.1,0.1l-0.2,1.1c-0.3,0-0.5-0.1-0.7-0.1c-0.4,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.2,0.5-0.2,0.9v0.7h1.4v1h-1.4v6.3H849.5 z"/> - <path fill="#333333" d="M107.7,309.5h1.3v1.4h-1.3V309.5z M107.7,312.3h1.3v7.3h-1.3V312.3z"/> - <path fill="#333333" d="M111.1,310.2h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V310.2z"/> - <path fill="#333333" d="M114.7,309.5h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V309.5z"/> - <path fill="#333333" d="M126.4,312.2h1.2v1c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.4-0.4c0.6,0,1.1,0.1,1.4,0.4 - c0.2,0.2,0.4,0.4,0.5,0.7c0.3-0.4,0.6-0.7,1-0.9c0.4-0.2,0.8-0.3,1.2-0.3c1,0,1.7,0.4,2,1.1c0.2,0.4,0.3,0.9,0.3,1.5v4.9H135v-5.1 - c0-0.5-0.1-0.8-0.4-1c-0.2-0.2-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.2,0.5s-0.5,0.9-0.5,1.6v4.3h-1.3v-4.8c0-0.5-0.1-0.9-0.2-1.1 - c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.3,0.5c-0.4,0.4-0.6,1-0.6,2v3.9h-1.2V312.2z"/> - <path fill="#333333" d="M138.1,309.5h1.3v1.4h-1.3V309.5z M138.1,312.3h1.3v7.3h-1.3V312.3z"/> - <path fill="#333333" d="M145.2,312.5c0.2,0.1,0.5,0.4,0.7,0.7v-3.7h1.2v10.1H146v-1c-0.3,0.5-0.6,0.8-1,1 - c-0.4,0.2-0.8,0.3-1.3,0.3c-0.8,0-1.5-0.3-2.1-1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.1,0.3-2,0.8-2.8c0.5-0.8,1.3-1.2,2.3-1.2 - C144.3,312.1,144.8,312.2,145.2,312.5z M142.4,318c0.3,0.5,0.9,0.8,1.6,0.8c0.6,0,1-0.2,1.4-0.7c0.4-0.5,0.5-1.2,0.5-2.1 - c0-0.9-0.2-1.6-0.6-2.1c-0.4-0.4-0.8-0.7-1.4-0.7c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.5-0.6,1.2-0.6,2.1 - C141.9,316.8,142.1,317.4,142.4,318z"/> - <path fill="#333333" d="M153,312.5c0.2,0.1,0.5,0.4,0.7,0.7v-3.7h1.2v10.1h-1.1v-1c-0.3,0.5-0.6,0.8-1,1c-0.4,0.2-0.8,0.3-1.3,0.3 - c-0.8,0-1.5-0.3-2.1-1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.1,0.3-2,0.8-2.8c0.5-0.8,1.3-1.2,2.3-1.2C152.1,312.1,152.6,312.2,153,312.5z - M150.2,318c0.3,0.5,0.9,0.8,1.6,0.8c0.6,0,1-0.2,1.4-0.7c0.4-0.5,0.5-1.2,0.5-2.1c0-0.9-0.2-1.6-0.6-2.1 - c-0.4-0.4-0.8-0.7-1.4-0.7c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.5-0.6,1.2-0.6,2.1C149.7,316.8,149.9,317.4,150.2,318z"/> - <path fill="#333333" d="M156.8,309.5h1.2v10h-1.2V309.5z"/> - <path fill="#333333" d="M164.4,312.4c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8c0.3,0.5,0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9c0.6-0.7,1.5-1.1,2.5-1.1C163.4,312.1,163.9,312.2,164.4,312.4z M164.8,315.3c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H164.8z"/> - <path fill="#333333" d="M176.4,312.6c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C175.2,312,175.8,312.2,176.4,312.6z"/> - <path fill="#333333" d="M178.6,309.5h1.2v10h-1.2V309.5z"/> - <path fill="#333333" d="M181.6,309.5h1.3v1.4h-1.3V309.5z M181.6,312.3h1.3v7.3h-1.3V312.3z"/> - <path fill="#333333" d="M189.6,312.6c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C188.4,312,189.1,312.2,189.6,312.6z"/> - <path fill="#333333" d="M191.7,309.5h1.2v5.8l3.2-3.1h1.6l-2.8,2.7l3,4.6h-1.6l-2.3-3.7l-1,1v2.7h-1.2V309.5z"/> - <path fill="#333333" d="M202.4,316.6v-1.1h3v-3h1.2v3h3v1.1h-3v3h-1.2v-3H202.4z"/> - <path fill="#333333" d="M218.7,312.5c0.2,0.1,0.5,0.4,0.7,0.7v-3.7h1.2v10.1h-1.1v-1c-0.3,0.5-0.6,0.8-1,1 - c-0.4,0.2-0.8,0.3-1.3,0.3c-0.8,0-1.5-0.3-2.1-1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.1,0.3-2,0.8-2.8c0.5-0.8,1.3-1.2,2.3-1.2 - C217.9,312.1,218.3,312.2,218.7,312.5z M216,318c0.3,0.5,0.9,0.8,1.6,0.8c0.6,0,1-0.2,1.4-0.7c0.4-0.5,0.5-1.2,0.5-2.1 - c0-0.9-0.2-1.6-0.6-2.1c-0.4-0.4-0.8-0.7-1.4-0.7c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.5-0.6,1.2-0.6,2.1 - C215.5,316.8,215.6,317.4,216,318z"/> - <path fill="#333333" d="M222.5,312.2h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0v1.3 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V312.2z"/> - <path fill="#333333" d="M231.1,315.1c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.3,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L231.1,315.1z M228.5,318.5c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C228.1,318,228.2,318.2,228.5,318.5z"/> - <path fill="#333333" d="M239,312.5c0.2,0.2,0.5,0.4,0.7,0.7v-0.9h1.1v6.7c0,0.9-0.1,1.7-0.4,2.2c-0.5,1-1.5,1.5-2.9,1.5 - c-0.8,0-1.4-0.2-2-0.5c-0.5-0.4-0.8-0.9-0.9-1.7h1.3c0.1,0.3,0.2,0.6,0.4,0.8c0.3,0.3,0.7,0.4,1.3,0.4c0.9,0,1.6-0.3,1.8-1 - c0.2-0.4,0.3-1.1,0.2-2.1c-0.2,0.4-0.5,0.7-0.9,0.8c-0.3,0.2-0.8,0.3-1.4,0.3c-0.8,0-1.5-0.3-2.1-0.8c-0.6-0.6-0.9-1.5-0.9-2.8 - c0-1.2,0.3-2.2,0.9-2.9c0.6-0.7,1.3-1,2.2-1C238.1,312.1,238.6,312.3,239,312.5z M239.2,313.9c-0.4-0.4-0.8-0.7-1.4-0.7 - c-0.9,0-1.5,0.4-1.8,1.2c-0.2,0.4-0.3,1-0.3,1.7c0,0.8,0.2,1.5,0.5,1.9c0.3,0.4,0.8,0.6,1.3,0.6c0.9,0,1.5-0.4,1.9-1.2 - c0.2-0.5,0.3-1,0.3-1.6C239.7,315,239.5,314.3,239.2,313.9z"/> + <path fill="#333333" d="M855.8,525.2l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5V520h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C855.4,525.2,855.6,525.2,855.8,525.2z"/> + <path fill="#333333" d="M856.6,523.3V522h3.8v1.2H856.6z"/> + <path fill="#333333" d="M866.4,523.6l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C866.1,524.7,866.3,524.2,866.4,523.6z"/> + <path fill="#333333" d="M868.7,526.3v-10h1.2v10H868.7z"/> + <path fill="#333333" d="M871.8,517.7v-1.4h1.2v1.4H871.8z M871.8,526.3V519h1.2v7.3H871.8z"/> + <path fill="#333333" d="M879.6,523.6l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C879.4,524.7,879.6,524.2,879.6,523.6z"/> + <path fill="#333333" d="M881.9,526.3v-10h1.2v5.7l2.9-3h1.6l-2.8,2.7l3.1,4.6h-1.5l-2.4-3.7l-0.9,0.8v2.9H881.9z"/> + <path fill="#333333" d="M888.9,517.7v-1.4h1.2v1.4H888.9z M888.9,526.3V519h1.2v7.3H888.9z"/> + <path fill="#333333" d="M892,526.3V519h1.1v1c0.5-0.8,1.3-1.2,2.3-1.2c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.4,0.8,0.6 + c0.2,0.3,0.3,0.6,0.4,0.9c0,0.2,0.1,0.6,0.1,1.2v4.5h-1.2v-4.4c0-0.5,0-0.9-0.1-1.1c-0.1-0.2-0.3-0.4-0.5-0.6 + c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-1,0.2-1.4,0.5c-0.4,0.3-0.6,1-0.6,1.9v4H892z"/> + <path fill="#333333" d="M899.6,526.9l1.2,0.2c0.1,0.4,0.2,0.6,0.4,0.8c0.3,0.2,0.7,0.3,1.3,0.3c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.5-0.5,0.6-1c0.1-0.3,0.1-0.8,0.1-1.6c-0.5,0.6-1.2,1-2,1c-1,0-1.8-0.4-2.3-1.1s-0.8-1.6-0.8-2.6c0-0.7,0.1-1.3,0.4-1.9 + c0.3-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.7-0.5c0.9,0,1.6,0.3,2.1,1V519h1.1v6.3c0,1.1-0.1,1.9-0.3,2.4c-0.2,0.5-0.6,0.8-1.1,1.1 + s-1.1,0.4-1.8,0.4c-0.9,0-1.6-0.2-2.1-0.6C899.8,528.2,899.6,527.7,899.6,526.9z M900.6,522.5c0,1,0.2,1.6,0.6,2.1 + c0.4,0.4,0.9,0.7,1.4,0.7c0.6,0,1-0.2,1.4-0.7c0.4-0.4,0.6-1.1,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.4-0.7 + c-0.5,0-1,0.2-1.4,0.7C900.8,521,900.6,521.6,900.6,522.5z"/> + <path fill="#333333" d="M916.2,525.4c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.3-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C916.3,526,916.3,525.7,916.2,525.4z M916.1,522.6c-0.4,0.2-1.1,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.1,0.2 + c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.3-0.3 + c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V522.6z"/> + <path fill="#333333" d="M922.7,524.1l1.2-0.2c0.1,0.5,0.3,0.9,0.6,1.1c0.3,0.3,0.7,0.4,1.3,0.4c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.4-0.5,0.4-0.8c0-0.3-0.1-0.5-0.4-0.7c-0.2-0.1-0.6-0.2-1.3-0.4c-0.9-0.2-1.5-0.4-1.9-0.6c-0.3-0.2-0.6-0.4-0.8-0.7 + c-0.2-0.3-0.3-0.6-0.3-1c0-0.3,0.1-0.6,0.2-0.9c0.1-0.3,0.3-0.5,0.6-0.7c0.2-0.1,0.5-0.3,0.8-0.4c0.3-0.1,0.7-0.1,1.1-0.1 + c0.6,0,1.1,0.1,1.5,0.2s0.7,0.4,1,0.7c0.2,0.3,0.3,0.7,0.4,1.1l-1.2,0.2c-0.1-0.4-0.2-0.7-0.5-0.9c-0.3-0.2-0.6-0.3-1.1-0.3 + c-0.6,0-1,0.1-1.2,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.2,0.1,0.3,0.2,0.4c0.1,0.1,0.3,0.2,0.5,0.3c0.1,0,0.5,0.2,1.1,0.3 + c0.9,0.2,1.5,0.4,1.8,0.6c0.3,0.1,0.6,0.4,0.8,0.6c0.2,0.3,0.3,0.6,0.3,1.1c0,0.4-0.1,0.8-0.4,1.2c-0.2,0.4-0.6,0.6-1,0.8 + c-0.5,0.2-1,0.3-1.5,0.3c-0.9,0-1.7-0.2-2.2-0.6C923.1,525.5,922.8,524.9,922.7,524.1z"/> + <path fill="#333333" d="M932.8,525.2l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5V520h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C932.4,525.2,932.6,525.2,932.8,525.2z"/> + <path fill="#333333" d="M934,526.3V519h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H934z"/> + <path fill="#333333" d="M943.7,523.9l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3h-5.4 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C943.2,524.8,943.5,524.5,943.7,523.9z M939.6,521.9h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C939.9,520.8,939.7,521.3,939.6,521.9z"/> + <path fill="#333333" d="M951.2,523.6l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C950.9,524.7,951.1,524.2,951.2,523.6z"/> + <path fill="#333333" d="M953.5,526.3v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.6,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H953.5z"/> + <path fill="#333333" d="M965.2,526.3v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.6,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H965.2z"/> + <path fill="#333333" d="M977.7,525.4c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.3-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C977.8,526,977.7,525.7,977.7,525.4z M977.6,522.6c-0.4,0.2-1.1,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.1,0.2 + c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.3-0.3 + c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V522.6z"/> + <path fill="#333333" d="M980.7,526.3V519h1.1v1c0.5-0.8,1.3-1.2,2.3-1.2c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.4,0.8,0.6 + c0.2,0.3,0.3,0.6,0.4,0.9c0,0.2,0.1,0.6,0.1,1.2v4.5h-1.2v-4.4c0-0.5,0-0.9-0.1-1.1c-0.1-0.2-0.3-0.4-0.5-0.6 + c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-1,0.2-1.4,0.5c-0.4,0.3-0.6,1-0.6,1.9v4H980.7z"/> + <path fill="#333333" d="M993.2,526.3v-0.9c-0.5,0.7-1.1,1.1-2,1.1c-0.6,0-1.1-0.2-1.6-0.5s-0.9-0.8-1.1-1.3 + c-0.3-0.6-0.4-1.2-0.4-2c0-0.7,0.1-1.4,0.4-2c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.6-0.5c0.4,0,0.8,0.1,1.2,0.3 + c0.3,0.2,0.6,0.4,0.8,0.7v-3.6h1.2v10H993.2z M989.4,522.6c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.4,0.7c0.5,0,1-0.2,1.4-0.7 + c0.4-0.4,0.6-1.1,0.6-2c0-1-0.2-1.7-0.6-2.2s-0.9-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7C989.5,521,989.4,521.7,989.4,522.6z"/> + <path fill="#333333" d="M996.3,526.3v-10h1.2v10H996.3z"/> + <path fill="#333333" d="M1004.4,523.9l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3h-5.4 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C1004,524.8,1004.2,524.5,1004.4,523.9z M1000.4,521.9h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C1000.6,520.8,1000.4,521.3,1000.4,521.9z"/> </g> <g> - <path fill="#333333" d="M35,377.7v-1.6h5.9v1.6l-3.7,4.2H41v1.6h-6.3V382l3.7-4.3H35z"/> - <path fill="#333333" d="M48.6,382.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C49.6,380.9,49.3,381.9,48.6,382.6z M47.1,381.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C46.3,382.2,46.8,382,47.1,381.6z"/> - <path fill="#333333" d="M57.2,382.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C58.1,380.9,57.8,381.9,57.2,382.6z M55.6,381.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C54.9,382.2,55.3,382,55.6,381.6z"/> - <path fill="#333333" d="M68.8,376.1c0.3,0.1,0.6,0.4,0.9,0.7c0.2,0.3,0.4,0.6,0.4,1c0,0.3,0.1,0.6,0.1,1.1l0,4.7h-2v-4.7 - c0-0.3,0-0.5-0.1-0.7c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.1,0.7c-0.1,0.2-0.2,0.5-0.2,0.9v4.4h-2v-4.4c0-0.4,0-0.8-0.1-1 - c-0.2-0.4-0.5-0.5-1-0.5c-0.6,0-0.9,0.2-1.1,0.5c-0.1,0.2-0.2,0.5-0.2,0.9v4.5h-2v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8 - c0.4-0.3,0.9-0.4,1.5-0.4c0.6,0,1,0.1,1.4,0.4c0.3,0.2,0.5,0.5,0.6,0.9c0.3-0.4,0.6-0.8,1-1c0.4-0.2,0.8-0.3,1.3-0.3 - C68.2,375.9,68.5,376,68.8,376.1z"/> - <path fill="#333333" d="M77.9,375.2h-2v-1.8h2V375.2z M75.9,376.1h2v7.5h-2V376.1z"/> - <path fill="#333333" d="M85.7,376.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V379c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C84.6,375.9,85.3,376.1,85.7,376.5z"/> - <path fill="#333333" d="M94.4,373.2H96l-3.9,10.4h-1.6L94.4,373.2z"/> - <path fill="#333333" d="M106.2,382.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C107.1,380.9,106.8,381.9,106.2,382.6z M104.6,381.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C103.9,382.2,104.3,382,104.6,381.6z"/> - <path fill="#333333" d="M110.5,376.1v4.5c0,0.4,0,0.7,0.1,1c0.2,0.4,0.5,0.6,1,0.6c0.7,0,1.1-0.3,1.4-0.8c0.1-0.3,0.2-0.7,0.2-1.2 - v-4.1h2v7.5h-1.9v-1.1c0,0-0.1,0.1-0.1,0.2c-0.1,0.1-0.2,0.2-0.3,0.3c-0.3,0.3-0.6,0.5-0.9,0.6s-0.6,0.2-1,0.2 - c-1.1,0-1.8-0.4-2.2-1.2c-0.2-0.4-0.3-1.1-0.3-1.9v-4.5H110.5z"/> - <path fill="#333333" d="M116.3,377.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H116.3z"/> - <path fill="#333333" d="M126.2,376.2l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3h-1.3l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3 - H126.2z"/> - <path fill="#333333" d="M135.7,373.5h1.3v1.4h-1.3V373.5z M135.7,376.3h1.3v7.3h-1.3V376.3z"/> - <path fill="#333333" d="M139.1,374.2h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V374.2z"/> - <path fill="#333333" d="M142.7,373.5h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V373.5z"/> - <path fill="#333333" d="M155.1,381.3c0,0.4,0.1,0.7,0.3,0.9c0.3,0.4,0.9,0.6,1.6,0.6c0.5,0,0.9-0.1,1.2-0.3 - c0.4-0.2,0.5-0.5,0.5-0.9c0-0.3-0.1-0.6-0.4-0.7c-0.2-0.1-0.5-0.2-1.1-0.3l-1-0.2c-0.6-0.2-1.1-0.3-1.4-0.5 - c-0.5-0.3-0.8-0.8-0.8-1.4c0-0.7,0.3-1.3,0.8-1.7c0.5-0.4,1.2-0.6,2-0.6c1.1,0,1.9,0.3,2.4,1c0.3,0.4,0.5,0.9,0.5,1.3h-1.2 - c0-0.3-0.1-0.5-0.3-0.8c-0.3-0.3-0.8-0.5-1.5-0.5c-0.5,0-0.8,0.1-1.1,0.3s-0.4,0.4-0.4,0.7c0,0.3,0.2,0.6,0.5,0.8 - c0.2,0.1,0.5,0.2,0.8,0.3l0.8,0.2c0.9,0.2,1.5,0.4,1.8,0.6c0.5,0.3,0.7,0.8,0.7,1.5c0,0.7-0.3,1.2-0.8,1.7 - c-0.5,0.5-1.3,0.7-2.3,0.7c-1.1,0-1.9-0.2-2.3-0.7c-0.5-0.5-0.7-1.1-0.7-1.8H155.1z"/> - <path fill="#333333" d="M166.2,376.6c0.5,0.4,0.8,1.1,0.9,2.1H166c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C165,376,165.7,376.2,166.2,376.6z"/> - <path fill="#333333" d="M168.4,376.2h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0v1.3 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V376.2z"/> - <path fill="#333333" d="M178.4,377c0.6,0.6,1,1.6,1,2.8c0,1.2-0.3,2.2-0.9,2.9s-1.5,1.2-2.7,1.2c-1,0-1.8-0.3-2.4-1 - c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.2,0.3-2.2,0.9-2.9s1.5-1.1,2.5-1.1C176.9,376,177.7,376.3,178.4,377z M177.6,381.8 - c0.3-0.6,0.5-1.3,0.5-2.1c0-0.7-0.1-1.2-0.3-1.7c-0.3-0.7-0.9-1-1.8-1c-0.7,0-1.3,0.3-1.6,0.9s-0.5,1.3-0.5,2.1 - c0,0.8,0.2,1.4,0.5,1.9s0.9,0.8,1.6,0.8C176.7,382.8,177.3,382.5,177.6,381.8z"/> - <path fill="#333333" d="M180.9,373.5h1.2v10h-1.2V373.5z"/> - <path fill="#333333" d="M184,373.5h1.2v10H184V373.5z"/> - <path fill="#333333" d="M187.6,376.2l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3h-1.3l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3 - H187.6z"/> - <path fill="#333333" d="M197.2,373.5h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V373.5z"/> - <path fill="#333333" d="M209.5,376.4c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8c0.3,0.5,0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9c0.6-0.7,1.5-1.1,2.5-1.1C208.5,376.1,209,376.2,209.5,376.4z M209.9,379.3c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H209.9z"/> - <path fill="#333333" d="M217.3,376.4c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8c0.3,0.5,0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9c0.6-0.7,1.5-1.1,2.5-1.1C216.3,376.1,216.8,376.2,217.3,376.4z M217.7,379.3c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H217.7z"/> - <path fill="#333333" d="M220.6,373.5h1.2v10h-1.2V373.5z"/> - </g> - <g> - <path fill="#078876" d="M15.5,503.2c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1C14.8,502.9,15.2,503,15.5,503.2z - M16,508.5c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6 - c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6C15.3,509.2,15.7,508.9,16,508.5z"/> - <path fill="#078876" d="M25,503.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C23.9,502.9,24.5,503,25,503.3z - M22.1,504.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C22.7,504.5,22.3,504.7,22.1,504.9z"/> - <path fill="#078876" d="M29.9,510.6H28v-10.1h1.9V510.6z"/> - <path fill="#078876" d="M36.7,503.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C35.6,502.9,36.1,503,36.7,503.3z - M33.7,504.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C34.4,504.5,34,504.7,33.7,504.9z"/> - <path fill="#078876" d="M38.8,504.6v-1.4h1v-2.1h1.9v2.1H43v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H38.8z"/> - <path fill="#078876" d="M49.1,503.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C48,502.9,48.6,503,49.1,503.3z - M46.2,504.9c-0.3,0.3-0.4,0.7-0.5,1.2H49c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C46.9,504.5,46.5,504.7,46.2,504.9z"/> - </g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M72.5,519.7c0,2.2-1.8,4-4,4h-64c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h64c2.2,0,4,1.8,4,4V519.7z"/> - <g> - <path fill="#333333" d="M88.8,503.2c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1C88,502.9,88.4,503,88.8,503.2z - M89.3,508.5c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6 - c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6C88.6,509.2,89,508.9,89.3,508.5z"/> - <path fill="#333333" d="M98.2,503.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C97.1,502.9,97.7,503,98.2,503.3z M95.3,504.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C96,504.5,95.6,504.7,95.3,504.9z"/> - <path fill="#333333" d="M103.2,510.6h-1.9v-10.1h1.9V510.6z"/> - <path fill="#333333" d="M109.9,503.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C108.8,502.9,109.4,503,109.9,503.3z M107,504.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C107.7,504.5,107.3,504.7,107,504.9z"/> - <path fill="#333333" d="M112.1,504.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4H115v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H112.1z"/> - <path fill="#333333" d="M122.4,503.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C121.3,502.9,121.8,503,122.4,503.3z M119.4,504.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C120.1,504.5,119.7,504.7,119.4,504.9z"/> - <path fill="#333333" d="M130.7,508.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H130.7z" + <path fill="#333333" d="M64.5,454h1.1v-0.5c0-0.6,0.1-1.1,0.2-1.4s0.4-0.5,0.7-0.7c0.3-0.2,0.8-0.3,1.3-0.3c0.5,0,1.1,0.1,1.6,0.2 + l-0.3,1.3c-0.3-0.1-0.6-0.1-0.9-0.1c-0.3,0-0.5,0.1-0.6,0.2c-0.1,0.1-0.2,0.4-0.2,0.7v0.5h1.4v1.5h-1.4v5.7h-1.9v-5.7h-1.1V454z" /> - <path fill="#333333" d="M141.8,503.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C140.7,502.9,141.3,503,141.8,503.3z M138.9,504.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C139.6,504.5,139.2,504.7,138.9,504.9z"/> - <path fill="#333333" d="M146.7,510.6h-1.9v-10.1h1.9V510.6z"/> - <path fill="#333333" d="M153.5,503.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5H150 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C152.4,502.9,153,503,153.5,503.3z M150.6,504.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C151.2,504.5,150.9,504.7,150.6,504.9z"/> - <path fill="#333333" d="M160.9,505.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.3,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1s-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3s1.5-1.1,2.6-1.1 - c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H160.9z"/> - <path fill="#333333" d="M163.5,504.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H163.5z"/> - <path fill="#333333" d="M170.9,502.2h-2v-1.8h2V502.2z M168.9,503.1h2v7.5h-2V503.1z"/> - <path fill="#333333" d="M179,509.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C179.9,507.9,179.6,508.9,179,509.6z M177.4,508.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C176.7,509.2,177.1,509,177.4,508.6z"/> - <path fill="#333333" d="M187.3,503.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V506c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C186.2,502.9,186.8,503.1,187.3,503.5z"/> + <path fill="#333333" d="M69.5,457.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C69.7,459.1,69.5,458.4,69.5,457.5z M71.5,457.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S71.5,456.9,71.5,457.6z"/> + <path fill="#333333" d="M84.9,456.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C84.2,454.8,84.6,455.4,84.9,456.2z"/> + <path fill="#333333" d="M91.1,461.3v-1.1c-0.3,0.4-0.6,0.7-1,0.9s-0.9,0.3-1.4,0.3c-0.5,0-0.9-0.1-1.3-0.3 + c-0.4-0.2-0.7-0.5-0.8-0.9c-0.2-0.4-0.3-0.9-0.3-1.6V454h1.9v3.3c0,1,0,1.6,0.1,1.9c0.1,0.2,0.2,0.4,0.4,0.5 + c0.2,0.1,0.4,0.2,0.7,0.2c0.3,0,0.6-0.1,0.9-0.3c0.3-0.2,0.4-0.4,0.5-0.7c0.1-0.3,0.1-0.9,0.1-2V454h1.9v7.3H91.1z"/> + <path fill="#333333" d="M94.2,459.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C94.7,460.4,94.4,459.9,94.2,459.2z"/> + <path fill="#333333" d="M106.1,457.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C106.2,459.1,106.1,458.4,106.1,457.5z M108.1,457.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S108.1,456.9,108.1,457.6z"/> + <path fill="#333333" d="M121.7,461.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V454h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V461.3z"/> + <path fill="#333333" d="M126.9,459.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C127.4,460.4,127,459.9,126.9,459.2z"/> + <path fill="#333333" d="M139.5,459l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S139.4,459.3,139.5,459z M139.6,457c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H139.6z"/> + <path fill="#333333" d="M143.1,461.3v-10h1.9v10H143.1z"/> + <path fill="#333333" d="M151.2,459l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S151.1,459.3,151.2,459z M151.3,457c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H151.3z"/> + <path fill="#333333" d="M161.1,456.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C160.5,454.8,160.9,455.4,161.1,456.2z"/> + <path fill="#333333" d="M165.9,454v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V454h0.9v-1.4l1.9-1.1v2.6H165.9z"/> + <path fill="#333333" d="M167.2,453v-1.8h1.9v1.8H167.2z M167.2,461.3V454h1.9v7.3H167.2z"/> + <path fill="#333333" d="M170.7,457.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C170.8,459.1,170.7,458.4,170.7,457.5z M172.6,457.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S172.6,456.9,172.6,457.6z"/> + <path fill="#333333" d="M186.3,461.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V454h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V461.3z"/> </g> + <path fill="#048876" d="M34.5,247.3c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 + c0.7-0.4,1.3-1.8,1.3-3.6s-0.5-3.2-1.3-3.6l0-4.9C32,247.3,33.9,247.3,34.5,247.3z"/> <g> - <path fill="#333333" d="M667.4,508.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H667.4z" - /> - <path fill="#333333" d="M678.2,505.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.3,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1s-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3s1.5-1.1,2.6-1.1 - c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H678.2z"/> - <path fill="#333333" d="M684.4,506c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6 - c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7h-1.9c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1 - c0.8,0,1.5,0.2,2.2,0.5c0.6,0.3,1,0.9,1,1.8v3.4c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5c0.1,0.1,0.2,0.2,0.3,0.2v0.3h-2.1 - c-0.1-0.2-0.1-0.3-0.1-0.4c0-0.1,0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6 - c-0.4-0.4-0.7-0.9-0.7-1.6c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L684.4,506z M685.6,506.9c-0.1,0.1-0.3,0.1-0.4,0.2 - c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7 - c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4s0.5-0.7,0.6-1.3V506.9z"/> - <path fill="#333333" d="M691.3,510.6h-1.9v-10.1h1.9V510.6z"/> - <path fill="#333333" d="M698,503.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C696.9,502.9,697.5,503,698,503.3z M695.1,504.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C695.8,504.5,695.4,504.7,695.1,504.9z"/> - <path fill="#333333" d="M711.1,503.9c0.6,0.6,0.9,1.6,0.9,2.8c0,1.3-0.3,2.3-0.9,3s-1.4,1-2.3,1c-0.6,0-1.1-0.1-1.5-0.4 - c-0.2-0.2-0.4-0.4-0.6-0.7v3.9h-1.9v-10.4h1.9v1.1c0.2-0.3,0.4-0.6,0.7-0.8c0.4-0.3,1-0.5,1.6-0.5 - C709.8,502.9,710.5,503.3,711.1,503.9z M709.6,505.3c-0.3-0.4-0.7-0.7-1.3-0.7c-0.7,0-1.2,0.3-1.5,1c-0.1,0.4-0.2,0.8-0.2,1.4 - c0,0.9,0.2,1.5,0.7,1.8c0.3,0.2,0.6,0.3,1,0.3c0.5,0,1-0.2,1.3-0.6s0.4-1,0.4-1.7C710,506.3,709.9,505.8,709.6,505.3z"/> - <path fill="#333333" d="M717.5,502.9c0,0,0.1,0,0.2,0v2c-0.1,0-0.2,0-0.3,0s-0.2,0-0.2,0c-0.8,0-1.3,0.3-1.6,0.8 - c-0.2,0.3-0.2,0.7-0.2,1.3v3.6h-2v-7.5h1.9v1.3c0.3-0.5,0.6-0.8,0.8-1C716.4,503.1,716.8,502.9,717.5,502.9 - C717.5,502.9,717.5,502.9,717.5,502.9z"/> - <path fill="#333333" d="M725,509.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C726,507.9,725.7,508.9,725,509.6z M723.5,508.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C722.7,509.2,723.2,509,723.5,508.6z"/> - <path fill="#333333" d="M733.7,503.9c0.6,0.6,0.9,1.6,0.9,2.8c0,1.3-0.3,2.3-0.9,3s-1.4,1-2.3,1c-0.6,0-1.1-0.1-1.5-0.4 - c-0.2-0.2-0.4-0.4-0.6-0.7v3.9h-1.9v-10.4h1.9v1.1c0.2-0.3,0.4-0.6,0.7-0.8c0.4-0.3,1-0.5,1.6-0.5 - C732.3,502.9,733,503.3,733.7,503.9z M732.2,505.3c-0.3-0.4-0.7-0.7-1.3-0.7c-0.7,0-1.2,0.3-1.5,1c-0.1,0.4-0.2,0.8-0.2,1.4 - c0,0.9,0.2,1.5,0.7,1.8c0.3,0.2,0.6,0.3,1,0.3c0.5,0,1-0.2,1.3-0.6s0.4-1,0.4-1.7C732.6,506.3,732.4,505.8,732.2,505.3z"/> - <path fill="#333333" d="M742.2,509.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C743.1,507.9,742.8,508.9,742.2,509.6z M740.6,508.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C739.8,509.2,740.3,509,740.6,508.6z"/> - <path fill="#333333" d="M748.6,502.9c0,0,0.1,0,0.2,0v2c-0.1,0-0.2,0-0.3,0s-0.2,0-0.2,0c-0.8,0-1.3,0.3-1.6,0.8 - c-0.2,0.3-0.2,0.7-0.2,1.3v3.6h-2v-7.5h1.9v1.3c0.3-0.5,0.6-0.8,0.8-1C747.5,503.1,748,502.9,748.6,502.9 - C748.6,502.9,748.6,502.9,748.6,502.9z"/> - <path fill="#333333" d="M749.2,504.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H749.2z"/> - <path fill="#333333" d="M756.6,502.2h-2v-1.8h2V502.2z M754.6,503.1h2v7.5h-2V503.1z"/> - <path fill="#333333" d="M764.7,509.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C765.6,507.9,765.3,508.9,764.7,509.6z M763.1,508.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C762.4,509.2,762.8,509,763.1,508.6z"/> - <path fill="#333333" d="M770,506c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6c-0.2-0.1-0.5-0.2-0.9-0.2 - c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7h-1.9c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1c0.8,0,1.5,0.2,2.2,0.5 - c0.6,0.3,1,0.9,1,1.8v3.4c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5c0.1,0.1,0.2,0.2,0.3,0.2v0.3h-2.1c-0.1-0.2-0.1-0.3-0.1-0.4 - c0-0.1,0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.7-0.9-0.7-1.6 - c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L770,506z M771.2,506.9c-0.1,0.1-0.3,0.1-0.4,0.2c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1 - c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4 - s0.5-0.7,0.6-1.3V506.9z"/> - <path fill="#333333" d="M776.8,510.6h-1.9v-10.1h1.9V510.6z"/> - <path fill="#333333" d="M780.7,510.6h-1.9v-10.1h1.9V510.6z"/> - <path fill="#333333" d="M782.9,512l0.2,0c0.2,0,0.4,0,0.5,0c0.2,0,0.3-0.1,0.4-0.2c0.1-0.1,0.2-0.2,0.3-0.5 - c0.1-0.2,0.1-0.4,0.1-0.5l-2.7-7.8h2.2l1.6,5.5l1.5-5.5h2.1l-2.6,7.3c-0.5,1.4-0.9,2.3-1.2,2.6c-0.3,0.3-0.9,0.5-1.7,0.5 - c-0.2,0-0.3,0-0.4,0c-0.1,0-0.3,0-0.5,0V512z"/> - <path fill="#333333" d="M794.2,500.5h1.2v3.6c0.3-0.4,0.6-0.6,1-0.8c0.4-0.2,0.8-0.3,1.2-0.3c0.9,0,1.7,0.3,2.2,0.9 - c0.6,0.6,0.9,1.5,0.9,2.8c0,1.2-0.3,2.1-0.8,2.9s-1.3,1.1-2.3,1.1c-0.6,0-1-0.1-1.4-0.4c-0.2-0.2-0.5-0.4-0.7-0.8v0.9h-1.1V500.5z - M798.9,508.9c0.3-0.5,0.5-1.2,0.5-2.1c0-0.8-0.2-1.4-0.5-1.9c-0.3-0.5-0.8-0.8-1.5-0.8c-0.6,0-1.1,0.2-1.5,0.6s-0.6,1.1-0.6,2.1 - c0,0.7,0.1,1.2,0.3,1.7c0.3,0.8,0.9,1.2,1.8,1.2C798,509.7,798.5,509.4,798.9,508.9z"/> - <path fill="#333333" d="M806.6,503.2h1.4c-0.2,0.5-0.6,1.5-1.2,3.2c-0.4,1.3-0.8,2.3-1.1,3.1c-0.7,1.9-1.2,3-1.5,3.4 - c-0.3,0.4-0.8,0.6-1.5,0.6c-0.2,0-0.3,0-0.4,0c-0.1,0-0.2,0-0.3-0.1v-1.1c0.2,0.1,0.4,0.1,0.5,0.1c0.1,0,0.2,0,0.3,0 - c0.2,0,0.4,0,0.5-0.1c0.1-0.1,0.2-0.2,0.3-0.3c0,0,0.1-0.2,0.2-0.6c0.1-0.3,0.2-0.6,0.3-0.8l-2.7-7.5h1.4l2,6L806.6,503.2z"/> - <path fill="#333333" d="M813.7,508.3c0,0.4,0.1,0.7,0.3,0.9c0.3,0.4,0.9,0.6,1.6,0.6c0.5,0,0.9-0.1,1.2-0.3 - c0.4-0.2,0.5-0.5,0.5-0.9c0-0.3-0.1-0.6-0.4-0.7c-0.2-0.1-0.5-0.2-1.1-0.3l-1-0.2c-0.6-0.2-1.1-0.3-1.4-0.5 - c-0.5-0.3-0.8-0.8-0.8-1.4c0-0.7,0.3-1.3,0.8-1.7s1.2-0.6,2-0.6c1.1,0,1.9,0.3,2.4,1c0.3,0.4,0.5,0.9,0.5,1.3h-1.2 - c0-0.3-0.1-0.5-0.3-0.8c-0.3-0.3-0.8-0.5-1.5-0.5c-0.5,0-0.8,0.1-1.1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.2,0.6,0.5,0.8 - c0.2,0.1,0.5,0.2,0.8,0.3l0.8,0.2c0.9,0.2,1.5,0.4,1.8,0.6c0.5,0.3,0.7,0.8,0.7,1.5c0,0.7-0.2,1.2-0.8,1.7 - c-0.5,0.5-1.3,0.7-2.3,0.7c-1.1,0-1.9-0.2-2.3-0.7c-0.5-0.5-0.7-1.1-0.7-1.8H813.7z"/> - <path fill="#333333" d="M820,500.5h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9H820V500.5z"/> - <path fill="#333333" d="M827.7,500.5h1.3v1.4h-1.3V500.5z M827.7,503.3h1.3v7.3h-1.3V503.3z"/> - <path fill="#333333" d="M831.4,501c0.3-0.4,0.8-0.6,1.7-0.6c0.1,0,0.2,0,0.2,0s0.2,0,0.3,0v1.1c-0.1,0-0.2,0-0.3,0 - c-0.1,0-0.1,0-0.2,0c-0.4,0-0.6,0.1-0.7,0.3c-0.1,0.2-0.1,0.7-0.1,1.5h1.2v1h-1.2v6.3h-1.2v-6.3h-1v-1h1v-1.1 - C831.2,501.6,831.3,501.2,831.4,501z"/> - <path fill="#333333" d="M835,501.2h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V501.2z"/> - <path fill="#333333" d="M838.3,506h3.4v1.3h-3.4V506z"/> - <path fill="#333333" d="M848.1,503.6c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C846.9,503,847.6,503.2,848.1,503.6z"/> - <path fill="#333333" d="M850.3,500.5h1.2v10h-1.2V500.5z"/> - <path fill="#333333" d="M853.4,500.5h1.3v1.4h-1.3V500.5z M853.4,503.3h1.3v7.3h-1.3V503.3z"/> - <path fill="#333333" d="M861.3,503.6c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C860.2,503,860.8,503.2,861.3,503.6z"/> - <path fill="#333333" d="M863.5,500.5h1.2v5.8l3.2-3.1h1.6l-2.8,2.7l3,4.6H868l-2.3-3.7l-1,1v2.7h-1.2V500.5z"/> - <path fill="#333333" d="M870.5,500.5h1.3v1.4h-1.3V500.5z M870.5,503.3h1.3v7.3h-1.3V503.3z"/> - <path fill="#333333" d="M873.6,503.2h1.2v1c0.3-0.4,0.7-0.7,1.1-0.9c0.4-0.2,0.8-0.3,1.3-0.3c1,0,1.7,0.4,2.1,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.4-0.1-0.8-0.2-1.1c-0.2-0.5-0.6-0.7-1.2-0.7c-0.3,0-0.5,0-0.7,0.1 - c-0.3,0.1-0.6,0.3-0.9,0.6c-0.2,0.2-0.3,0.5-0.4,0.7c-0.1,0.3-0.1,0.6-0.1,1.1v3.8h-1.2V503.2z"/> - <path fill="#333333" d="M885.5,503.5c0.2,0.2,0.5,0.4,0.7,0.7v-0.9h1.1v6.7c0,0.9-0.1,1.7-0.4,2.2c-0.5,1-1.5,1.5-2.9,1.5 - c-0.8,0-1.4-0.2-2-0.5c-0.5-0.4-0.8-0.9-0.9-1.7h1.3c0.1,0.3,0.2,0.6,0.4,0.8c0.3,0.3,0.7,0.4,1.3,0.4c0.9,0,1.6-0.3,1.8-1 - c0.2-0.4,0.3-1.1,0.2-2.1c-0.2,0.4-0.5,0.7-0.9,0.8s-0.8,0.3-1.4,0.3c-0.8,0-1.5-0.3-2.1-0.8c-0.6-0.6-0.9-1.5-0.9-2.8 - c0-1.2,0.3-2.2,0.9-2.9s1.3-1,2.2-1C884.5,503.1,885,503.3,885.5,503.5z M885.6,504.9c-0.4-0.4-0.8-0.7-1.4-0.7 - c-0.9,0-1.5,0.4-1.8,1.2c-0.2,0.4-0.3,1-0.3,1.7c0,0.8,0.2,1.5,0.5,1.9c0.3,0.4,0.8,0.6,1.3,0.6c0.9,0,1.5-0.4,1.9-1.2 - c0.2-0.5,0.3-1,0.3-1.6C886.2,506,886,505.3,885.6,504.9z"/> - <path fill="#333333" d="M897,506.1c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.2,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L897,506.1z M894.4,509.5c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C894,509,894.2,509.2,894.4,509.5z"/> - <path fill="#333333" d="M905.5,508.3c0,0.4,0.1,0.7,0.3,0.9c0.3,0.4,0.9,0.6,1.6,0.6c0.5,0,0.9-0.1,1.2-0.3 - c0.4-0.2,0.5-0.5,0.5-0.9c0-0.3-0.1-0.6-0.4-0.7c-0.2-0.1-0.5-0.2-1.1-0.3l-1-0.2c-0.6-0.2-1.1-0.3-1.4-0.5 - c-0.5-0.3-0.8-0.8-0.8-1.4c0-0.7,0.3-1.3,0.8-1.7s1.2-0.6,2-0.6c1.1,0,1.9,0.3,2.4,1c0.3,0.4,0.5,0.9,0.5,1.3H909 - c0-0.3-0.1-0.5-0.3-0.8c-0.3-0.3-0.8-0.5-1.5-0.5c-0.5,0-0.8,0.1-1.1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.2,0.6,0.5,0.8 - c0.2,0.1,0.5,0.2,0.8,0.3l0.8,0.2c0.9,0.2,1.5,0.4,1.8,0.6c0.5,0.3,0.7,0.8,0.7,1.5c0,0.7-0.2,1.2-0.8,1.7 - c-0.5,0.5-1.3,0.7-2.3,0.7c-1.1,0-1.9-0.2-2.3-0.7c-0.5-0.5-0.7-1.1-0.7-1.8H905.5z"/> - <path fill="#333333" d="M912,501.2h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V501.2z"/> - <path fill="#333333" d="M915.7,503.2h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0v1.3 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V503.2z"/> - <path fill="#333333" d="M924.8,503.4c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8s0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9s1.5-1.1,2.5-1.1C923.8,503.1,924.3,503.2,924.8,503.4z M925.3,506.3c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H925.3z"/> - <path fill="#333333" d="M932.9,503.6c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C931.7,503,932.4,503.2,932.9,503.6z"/> - <path fill="#333333" d="M935.1,500.5h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V500.5z"/> - <path fill="#333333" d="M946.8,500.5h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V500.5z"/> - <path fill="#333333" d="M958.5,506.1c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.2,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L958.5,506.1z M955.9,509.5c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C955.5,509,955.6,509.2,955.9,509.5z"/> - <path fill="#333333" d="M962.3,503.2h1.2v1c0.3-0.4,0.7-0.7,1.1-0.9c0.4-0.2,0.8-0.3,1.3-0.3c1,0,1.7,0.4,2.1,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.4-0.1-0.8-0.2-1.1c-0.2-0.5-0.6-0.7-1.2-0.7c-0.3,0-0.5,0-0.7,0.1 - c-0.3,0.1-0.6,0.3-0.9,0.6c-0.2,0.2-0.3,0.5-0.4,0.7c-0.1,0.3-0.1,0.6-0.1,1.1v3.8h-1.2V503.2z"/> - <path fill="#333333" d="M974.2,503.5c0.2,0.1,0.5,0.4,0.7,0.7v-3.7h1.2v10.1H975v-1c-0.3,0.5-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.8,0-1.5-0.3-2.1-1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.1,0.3-2,0.8-2.8c0.5-0.8,1.3-1.2,2.3-1.2 - C973.3,503.1,973.8,503.2,974.2,503.5z M971.4,509c0.3,0.5,0.9,0.8,1.6,0.8c0.6,0,1-0.2,1.4-0.7c0.4-0.5,0.5-1.2,0.5-2.1 - c0-0.9-0.2-1.6-0.6-2.1c-0.4-0.4-0.8-0.7-1.4-0.7c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.5-0.6,1.2-0.6,2.1 - C970.9,507.8,971.1,508.4,971.4,509z"/> - <path fill="#333333" d="M977.9,500.5h1.2v10h-1.2V500.5z"/> - <path fill="#333333" d="M985.5,503.4c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8s0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9s1.5-1.1,2.5-1.1C984.6,503.1,985.1,503.2,985.5,503.4z M986,506.3c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H986z"/> + <path fill="#B6B6B6" d="M18.9,256.5c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 + c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C19,261.1,18.9,258.6,18.9,256.5z"/> + <path fill="#B6B6B6" d="M31,292l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 + c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C42.8,286,37.5,291.9,31,292z"/> </g> + <rect x="24.4" y="314.9" fill="#048876" width="13" height="7"/> + <path fill="#B6B6B6" d="M34.5,310.3c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 + c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C32,310.3,33.9,310.3,34.5,310.3z"/> + <path fill="#B6B6B6" d="M18.9,319.5c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 + c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C19,324.1,18.9,321.6,18.9,319.5z"/> + <path fill="#B6B6B6" d="M31,355l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 + c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C42.8,349,37.5,354.9,31,355z"/> + <rect x="24.4" y="377.9" fill="#048876" width="13" height="7"/> + <path fill="#B6B6B6" d="M34.5,373.3c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 + c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C32,373.3,33.9,373.3,34.5,373.3z"/> + <path fill="#B6B6B6" d="M18.9,382.5c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 + c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C19,387.1,18.9,384.6,18.9,382.5z"/> + <path fill="#B6B6B6" d="M31,418l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 + c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C42.8,412,37.5,417.9,31,418z"/> + <path fill="#B6B6B6" d="M34.5,56.6c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 + c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C32,56.6,33.9,56.6,34.5,56.6z"/> + <path fill="#048876" d="M18.9,65.8c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 + c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C19,70.4,18.9,67.9,18.9,65.8z"/> + <path fill="#B6B6B6" d="M31,101.3l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 + c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C42.8,95.3,37.5,101.2,31,101.3z"/> + <path fill="#B6B6B6" d="M132.5,121.4c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 + c0.7-0.4,1.3-1.8,1.3-3.6s-0.5-3.2-1.3-3.6l0-4.9C130,121.4,131.9,121.4,132.5,121.4z"/> + <path fill="#048876" d="M116.9,130.6c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 + c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C117,135.2,116.9,132.6,116.9,130.6z"/> + <path fill="#B6B6B6" d="M129,166l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 + c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C140.8,160.1,135.5,166,129,166z"/> <g> - <path fill="#333333" d="M49.9,435.4c0.1,0,0.2,0,0.4,0v1.6c-0.1,0-0.3,0-0.6,0c-0.3,0-0.4,0-0.5,0.2c-0.1,0.1-0.1,0.3-0.1,0.4 - s0,0.4,0,0.6h1.3v1.4h-1.3v6h-1.9v-6h-1.1v-1.4h1.1v-0.5c0-0.8,0.1-1.3,0.4-1.6c0.3-0.4,1-0.7,2-0.7 - C49.7,435.4,49.8,435.4,49.9,435.4z"/> - <path fill="#333333" d="M57.7,444.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C58.6,442.9,58.3,443.9,57.7,444.6z M56.1,443.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C55.4,444.2,55.8,444,56.1,443.6z"/> - <path fill="#333333" d="M64.5,440.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.4,1c-0.1,0.3-0.2,0.8-0.2,1.4 - c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2c0,0.6-0.3,1.2-0.6,1.7 - c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1c-0.6-0.7-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3s1.5-1.1,2.6-1.1 - c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H64.5z"/> - <path fill="#333333" d="M69.8,438.1v4.5c0,0.4,0,0.7,0.1,1c0.2,0.4,0.5,0.6,1,0.6c0.7,0,1.1-0.3,1.4-0.8c0.1-0.3,0.2-0.7,0.2-1.2 - v-4.1h2v7.5h-1.9v-1.1c0,0-0.1,0.1-0.1,0.2c-0.1,0.1-0.2,0.2-0.3,0.3c-0.3,0.3-0.6,0.5-0.9,0.6s-0.6,0.2-1,0.2 - c-1.1,0-1.8-0.4-2.2-1.2c-0.2-0.4-0.3-1.1-0.3-1.9v-4.5H69.8z"/> - <path fill="#333333" d="M77.9,443.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H77.9z" - /> - <path fill="#333333" d="M94.3,444.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C95.2,442.9,94.9,443.9,94.3,444.6z M92.7,443.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C92,444.2,92.4,444,92.7,443.6z"/> - <path fill="#333333" d="M102.6,438.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V441c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C101.5,437.9,102.1,438.1,102.6,438.5z"/> - <path fill="#333333" d="M110.6,443.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H110.6z" - /> - <path fill="#333333" d="M121.7,438.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C120.6,437.9,121.2,438,121.7,438.3 - z M118.8,439.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C119.4,439.5,119.1,439.7,118.8,439.9z"/> - <path fill="#333333" d="M126.6,445.6h-1.9v-10.1h1.9V445.6z"/> - <path fill="#333333" d="M133.4,438.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C132.3,437.9,132.8,438,133.4,438.3 - z M130.5,439.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C131.1,439.5,130.7,439.7,130.5,439.9z"/> - <path fill="#333333" d="M140.8,440.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.4,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1c-0.6-0.7-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3 - s1.5-1.1,2.6-1.1c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H140.8z"/> - <path fill="#333333" d="M143.3,439.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H143.3z"/> - <path fill="#333333" d="M150.8,437.2h-2v-1.8h2V437.2z M148.8,438.1h2v7.5h-2V438.1z"/> - <path fill="#333333" d="M158.9,444.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C159.8,442.9,159.5,443.9,158.9,444.6z M157.3,443.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C156.5,444.2,157,444,157.3,443.6z"/> - <path fill="#333333" d="M167.2,438.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V441c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C166.1,437.9,166.7,438.1,167.2,438.5z"/> - </g> - <path fill="#078876" d="M16.2,231.6c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 - c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C13.6,231.6,15.5,231.6,16.2,231.6z"/> - <g> - <path fill="#B6B6B7" d="M0.5,240.8c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 - c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C0.6,245.4,0.5,242.9,0.5,240.8z"/> - <path fill="#B6B6B7" d="M12.6,276.3l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 - c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C24.4,270.3,19.1,276.2,12.6,276.3z"/> - </g> - <rect x="6" y="299.2" fill="#078876" width="13" height="7"/> - <path fill="#B6B6B7" d="M16.2,294.6c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 - c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C13.6,294.6,15.5,294.6,16.2,294.6z"/> - <path fill="#B6B6B7" d="M0.5,303.8c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 - c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C0.6,308.4,0.5,305.9,0.5,303.8z"/> - <path fill="#B6B6B7" d="M12.6,339.3l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 - c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C24.4,333.3,19.1,339.2,12.6,339.3z"/> - <rect x="6" y="362.2" fill="#078876" width="13" height="7"/> - <path fill="#B6B6B7" d="M16.2,357.6c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 - c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C13.6,357.6,15.5,357.6,16.2,357.6z"/> - <path fill="#B6B6B7" d="M0.5,366.8c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 - c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C0.6,371.4,0.5,368.9,0.5,366.8z"/> - <path fill="#B6B6B7" d="M12.6,402.3l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 - c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C24.4,396.3,19.1,402.2,12.6,402.3z"/> - <path fill="#B6B6B7" d="M16.2,40.9c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 - c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C13.6,40.9,15.5,40.9,16.2,40.9z"/> - <path fill="#078876" d="M0.5,50.1c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 - c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C0.6,54.7,0.5,52.2,0.5,50.1z"/> - <path fill="#B6B6B7" d="M12.6,85.6l-0.6,0c-6.5-0.1-11.7-6-11.4-11C1,69.1,0.9,63.1,0.7,57.9l0,0.3c0.1,0,5.9-0.3,11.7-0.3 - c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C24.4,79.6,19.1,85.5,12.6,85.6z"/> - <path fill="#B6B6B7" d="M114.2,105.7c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 - c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C111.6,105.7,113.5,105.7,114.2,105.7z"/> - <path fill="#078876" d="M98.5,114.9c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 - c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C98.6,119.5,98.5,116.9,98.5,114.9z"/> - <path fill="#B6B6B7" d="M110.6,150.3l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 - c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C122.4,144.4,117.1,150.2,110.6,150.3z"/> - <g> - <path fill="#333333" d="M68.8,188.2H70v1c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.4-0.4c0.6,0,1.1,0.1,1.4,0.4 - c0.2,0.2,0.4,0.4,0.5,0.7c0.3-0.4,0.6-0.7,1-0.9c0.4-0.2,0.8-0.3,1.2-0.3c1,0,1.7,0.4,2,1.1c0.2,0.4,0.3,0.9,0.3,1.5v4.9h-1.3 - v-5.1c0-0.5-0.1-0.8-0.4-1c-0.2-0.2-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.2,0.5s-0.5,0.9-0.5,1.6v4.3h-1.3v-4.8 - c0-0.5-0.1-0.9-0.2-1.1c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.3,0.5c-0.4,0.4-0.6,1-0.6,2v3.9h-1.2V188.2z"/> - <path fill="#333333" d="M86.7,194.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C87.6,192.9,87.3,193.9,86.7,194.6z M85.1,193.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C84.4,194.2,84.8,194,85.1,193.6z"/> - <path fill="#333333" d="M93.6,188.1h2.1l-2.7,7.5H91l-2.7-7.5h2.2l1.6,5.5L93.6,188.1z"/> - <path fill="#333333" d="M101.7,188.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C100.6,187.9,101.2,188,101.7,188.3 - z M98.8,189.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C99.4,189.5,99,189.7,98.8,189.9z"/> - <path fill="#333333" d="M110,193.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H110z"/> - <path fill="#333333" d="M121.1,188.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C120,187.9,120.6,188,121.1,188.3z - M118.2,189.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C118.9,189.5,118.5,189.7,118.2,189.9 + <path fill="#333333" d="M87.2,204h1.8v1c0.6-0.8,1.4-1.2,2.3-1.2c0.5,0,0.9,0.1,1.2,0.3s0.6,0.5,0.8,0.9c0.3-0.4,0.7-0.7,1-0.9 + s0.8-0.3,1.2-0.3c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.6,0.5,0.8,1c0.1,0.3,0.2,0.8,0.2,1.5v4.6h-1.9v-4.1c0-0.7-0.1-1.2-0.2-1.4 + c-0.2-0.3-0.5-0.4-0.8-0.4c-0.3,0-0.5,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5v3.5h-1.9v-4 + c0-0.7,0-1.2-0.1-1.4s-0.2-0.4-0.3-0.5s-0.3-0.2-0.6-0.2c-0.3,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7s-0.2,0.8-0.2,1.5v3.5 + h-1.9V204z"/> + <path fill="#333333" d="M99.3,207.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C99.5,209.1,99.3,208.4,99.3,207.5z M101.3,207.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S101.3,206.9,101.3,207.6z"/> + <path fill="#333333" d="M110.3,211.3l-2.9-7.3h2l1.4,3.7l0.4,1.2c0.1-0.3,0.2-0.5,0.2-0.6c0.1-0.2,0.1-0.4,0.2-0.6l1.4-3.7h2 + l-2.9,7.3H110.3z"/> + <path fill="#333333" d="M120.3,209l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S120.2,209.3,120.3,209z M120.4,207c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H120.4z"/> + <path fill="#333333" d="M127.1,209.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C127.6,210.4,127.3,209.9,127.1,209.2z"/> + <path fill="#333333" d="M139.8,209l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3H137 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S139.7,209.3,139.8,209z M139.9,207c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H139.9z"/> + <path fill="#333333" d="M143.3,211.3v-10h1.9v10H143.3z"/> + <path fill="#333333" d="M151.4,209l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S151.3,209.3,151.4,209z M151.5,207c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H151.5z"/> + <path fill="#333333" d="M161.3,206.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C160.7,204.8,161.1,205.4,161.3,206.2z"/> + <path fill="#333333" d="M166.1,204v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2H162V204h0.9v-1.4l1.9-1.1v2.6H166.1z"/> + <path fill="#333333" d="M167.5,203v-1.8h1.9v1.8H167.5z M167.5,211.3V204h1.9v7.3H167.5z"/> + <path fill="#333333" d="M170.9,207.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C171.1,209.1,170.9,208.4,170.9,207.5z M172.9,207.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S172.9,206.9,172.9,207.6z"/> + <path fill="#333333" d="M186.5,211.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V204h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V211.3z"/> + <path fill="#333333" d="M193.6,211.3l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3h-1.3l-1.2-4.3l-0.3-1.2l-1.5,5.6H193.6z"/> + <path fill="#333333" d="M202.4,202.7v-1.4h1.2v1.4H202.4z M202.4,211.3V204h1.2v7.3H202.4z"/> + <path fill="#333333" d="M208.2,210.2l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5V205h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C207.8,210.2,208,210.2,208.2,210.2z"/> + <path fill="#333333" d="M209.4,211.3v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.5,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H209.4z"/> + <path fill="#333333" d="M221,211.3v-10h1.2v10H221z"/> + <path fill="#333333" d="M229.1,208.9l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3H225 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C228.7,209.8,228.9,209.5,229.1,208.9z M225.1,206.9h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C225.3,205.8,225.1,206.3,225.1,206.9z"/> + <path fill="#333333" d="M232.2,211.3V205h-1.1v-1h1.1v-0.8c0-0.5,0-0.8,0.1-1.1c0.1-0.3,0.3-0.6,0.6-0.8c0.3-0.2,0.7-0.3,1.3-0.3 + c0.3,0,0.7,0,1.1,0.1l-0.2,1.1c-0.3,0-0.5-0.1-0.7-0.1c-0.4,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.2,0.5-0.2,0.9v0.7h1.4v1h-1.4v6.3H232.2 z"/> - <path fill="#333333" d="M126.1,195.6h-1.9v-10.1h1.9V195.6z"/> - <path fill="#333333" d="M132.8,188.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C131.7,187.9,132.3,188,132.8,188.3 - z M129.9,189.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C130.6,189.5,130.2,189.7,129.9,189.9z"/> - <path fill="#333333" d="M140.2,190.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.4,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1c-0.6-0.7-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3 - s1.5-1.1,2.6-1.1c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H140.2z"/> - <path fill="#333333" d="M142.8,189.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H142.8z"/> - <path fill="#333333" d="M150.2,187.2h-2v-1.8h2V187.2z M148.2,188.1h2v7.5h-2V188.1z"/> - <path fill="#333333" d="M158.3,194.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C159.2,192.9,158.9,193.9,158.3,194.6z M156.7,193.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C156,194.2,156.4,194,156.7,193.6z"/> - <path fill="#333333" d="M166.7,188.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V191c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C165.5,187.9,166.2,188.1,166.7,188.5z"/> - <path fill="#333333" d="M173.6,188.2l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3h-1.3l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3 - H173.6z"/> - <path fill="#333333" d="M183.2,185.5h1.3v1.4h-1.3V185.5z M183.2,188.3h1.3v7.3h-1.3V188.3z"/> - <path fill="#333333" d="M186.5,186.2h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V186.2z"/> - <path fill="#333333" d="M190.2,185.5h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V185.5z"/> - <path fill="#333333" d="M201.9,185.5h1.2v10h-1.2V185.5z"/> - <path fill="#333333" d="M209.5,188.4c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8c0.3,0.5,0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9c0.6-0.7,1.5-1.1,2.5-1.1C208.5,188.1,209,188.2,209.5,188.4z M209.9,191.3c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H209.9z"/> - <path fill="#333333" d="M213.3,186c0.3-0.4,0.8-0.6,1.7-0.6c0.1,0,0.2,0,0.2,0s0.2,0,0.3,0v1.1c-0.1,0-0.2,0-0.3,0 - c-0.1,0-0.1,0-0.2,0c-0.4,0-0.6,0.1-0.7,0.3c-0.1,0.2-0.1,0.7-0.1,1.5h1.2v1h-1.2v6.3h-1.2v-6.3h-1v-1h1v-1.1 - C213.1,186.6,213.2,186.2,213.3,186z"/> - <path fill="#333333" d="M216.9,186.2h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V186.2z"/> - <path fill="#333333" d="M229.3,188.6c0.5,0.4,0.8,1.1,0.9,2.1H229c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C228.1,188,228.7,188.2,229.3,188.6z"/> - <path fill="#333333" d="M231.5,185.5h1.2v10h-1.2V185.5z"/> - <path fill="#333333" d="M234.5,185.5h1.3v1.4h-1.3V185.5z M234.5,188.3h1.3v7.3h-1.3V188.3z"/> - <path fill="#333333" d="M242.5,188.6c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C241.3,188,242,188.2,242.5,188.6z"/> - <path fill="#333333" d="M244.6,185.5h1.2v5.8l3.2-3.1h1.6l-2.8,2.7l3,4.6h-1.6l-2.3-3.7l-1,1v2.7h-1.2V185.5z"/> - <path fill="#333333" d="M255.3,192.6v-1.1h3v-3h1.2v3h3v1.1h-3v3h-1.2v-3H255.3z"/> - <path fill="#333333" d="M271.6,188.5c0.2,0.1,0.5,0.4,0.7,0.7v-3.7h1.2v10.1h-1.1v-1c-0.3,0.5-0.6,0.8-1,1 - c-0.4,0.2-0.8,0.3-1.3,0.3c-0.8,0-1.5-0.3-2.1-1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.1,0.3-2,0.8-2.8c0.5-0.8,1.3-1.2,2.3-1.2 - C270.8,188.1,271.3,188.2,271.6,188.5z M268.9,194c0.3,0.5,0.9,0.8,1.6,0.8c0.6,0,1-0.2,1.4-0.7c0.4-0.5,0.5-1.2,0.5-2.1 - c0-0.9-0.2-1.6-0.6-2.1c-0.4-0.4-0.8-0.7-1.4-0.7c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.5-0.6,1.2-0.6,2.1 - C268.4,192.8,268.5,193.4,268.9,194z"/> - <path fill="#333333" d="M275.4,188.2h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0v1.3 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V188.2z"/> - <path fill="#333333" d="M284,191.1c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.3,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L284,191.1z M281.4,194.5c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C281,194,281.1,194.2,281.4,194.5z"/> - <path fill="#333333" d="M291.9,188.5c0.2,0.2,0.5,0.4,0.7,0.7v-0.9h1.1v6.7c0,0.9-0.1,1.7-0.4,2.2c-0.5,1-1.5,1.5-2.9,1.5 - c-0.8,0-1.4-0.2-2-0.5c-0.5-0.4-0.8-0.9-0.9-1.7h1.3c0.1,0.3,0.2,0.6,0.4,0.8c0.3,0.3,0.7,0.4,1.3,0.4c0.9,0,1.6-0.3,1.8-1 - c0.2-0.4,0.3-1.1,0.2-2.1c-0.2,0.4-0.5,0.7-0.9,0.8c-0.3,0.2-0.8,0.3-1.4,0.3c-0.8,0-1.5-0.3-2.1-0.8c-0.6-0.6-0.9-1.5-0.9-2.8 - c0-1.2,0.3-2.2,0.9-2.9c0.6-0.7,1.3-1,2.2-1C291,188.1,291.5,188.3,291.9,188.5z M292.1,189.9c-0.4-0.4-0.8-0.7-1.4-0.7 - c-0.9,0-1.5,0.4-1.8,1.2c-0.2,0.4-0.3,1-0.3,1.7c0,0.8,0.2,1.5,0.5,1.9c0.3,0.4,0.8,0.6,1.3,0.6c0.9,0,1.5-0.4,1.9-1.2 - c0.2-0.5,0.3-1,0.3-1.6C292.6,191,292.4,190.3,292.1,189.9z"/> + <path fill="#333333" d="M238.5,210.2l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5V205h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C238.1,210.2,238.3,210.2,238.5,210.2z"/> + <path fill="#333333" d="M248.4,208.6l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C248.1,209.7,248.3,209.2,248.4,208.6z"/> + <path fill="#333333" d="M250.6,211.3v-10h1.2v10H250.6z"/> + <path fill="#333333" d="M253.7,202.7v-1.4h1.2v1.4H253.7z M253.7,211.3V204h1.2v7.3H253.7z"/> + <path fill="#333333" d="M261.6,208.6l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C261.3,209.7,261.5,209.2,261.6,208.6z"/> + <path fill="#333333" d="M263.8,211.3v-10h1.2v5.7l2.9-3h1.6l-2.8,2.7l3.1,4.6h-1.5l-2.4-3.7l-0.9,0.8v2.9H263.8z"/> + <path fill="#333333" d="M277.3,209.7v-2.7h-2.7v-1.1h2.7V203h1.2v2.7h2.7v1.1h-2.7v2.7H277.3z"/> + <path fill="#333333" d="M291.5,211.3v-0.9c-0.5,0.7-1.1,1.1-2,1.1c-0.6,0-1.1-0.2-1.6-0.5s-0.9-0.8-1.1-1.3 + c-0.3-0.6-0.4-1.2-0.4-2c0-0.7,0.1-1.4,0.4-2c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.6-0.5c0.4,0,0.8,0.1,1.2,0.3 + c0.3,0.2,0.6,0.4,0.8,0.7v-3.6h1.2v10H291.5z M287.6,207.6c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.4,0.7c0.5,0,1-0.2,1.4-0.7 + c0.4-0.4,0.6-1.1,0.6-2c0-1-0.2-1.7-0.6-2.2s-0.9-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7C287.8,206,287.6,206.7,287.6,207.6z"/> + <path fill="#333333" d="M294.6,211.3V204h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H294.6z"/> + <path fill="#333333" d="M304,210.4c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.2-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C304.1,211,304,210.7,304,210.4z M303.9,207.6c-0.4,0.2-1.1,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.1,0.2 + c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.3-0.3 + c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V207.6z"/> + <path fill="#333333" d="M306.8,211.9l1.2,0.2c0,0.4,0.2,0.6,0.4,0.8c0.3,0.2,0.7,0.3,1.3,0.3c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.5-0.5,0.6-1c0.1-0.3,0.1-0.8,0.1-1.6c-0.5,0.6-1.2,1-2,1c-1,0-1.8-0.4-2.3-1.1s-0.8-1.6-0.8-2.6c0-0.7,0.1-1.3,0.4-1.9 + c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.7-0.5c0.9,0,1.6,0.3,2.1,1V204h1.1v6.3c0,1.1-0.1,1.9-0.3,2.4c-0.2,0.5-0.6,0.8-1.1,1.1 + s-1.1,0.4-1.8,0.4c-0.9,0-1.6-0.2-2.1-0.6C307,213.2,306.8,212.7,306.8,211.9z M307.8,207.5c0,1,0.2,1.6,0.6,2.1 + c0.4,0.4,0.9,0.7,1.4,0.7c0.6,0,1-0.2,1.4-0.7c0.4-0.4,0.6-1.1,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.4-0.7 + c-0.5,0-1,0.2-1.4,0.7C308,206,307.8,206.6,307.8,207.5z"/> </g> <g> - <path fill="#B6B6B7" d="M16.2,167.9c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 - c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C13.6,167.9,15.5,167.9,16.2,167.9z"/> - <path fill="#078876" d="M0.5,177.1c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 - c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C0.6,181.7,0.5,179.2,0.5,177.1z"/> - <path fill="#B6B6B7" d="M12.6,212.6l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 - c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C24.4,206.6,19.1,212.5,12.6,212.6z"/> + <path fill="#B6B6B6" d="M34.5,183.6c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 + c0.7-0.4,1.3-1.8,1.3-3.6s-0.5-3.2-1.3-3.6l0-4.9C32,183.6,33.9,183.6,34.5,183.6z"/> + <path fill="#048876" d="M18.9,192.8c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 + c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C19,197.4,18.9,194.9,18.9,192.8z"/> + <path fill="#B6B6B6" d="M31,228.3l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 + c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C42.8,222.3,37.5,228.2,31,228.3z"/> <g> - <path fill="#078876" d="M48.7,189.9l4.4,3.1l1.2-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.3,0.1,0.5,0.3,0.5,0.5l0.9,4.7 + <path fill="#048876" d="M67.1,205.6l4.4,3.1l1.2-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.3,0.1,0.5,0.3,0.5,0.5l0.9,4.7 c0.1,0.4-0.2,0.7-0.6,0.8l-4.7,0.9c-0.3,0.1-0.5-0.1-0.7-0.3c-0.2-0.2-0.2-0.5,0-0.8l1.2-1.8l-4.4-3.1l-3.1,4.4l1.8,1.2 c0.2,0.2,0.3,0.4,0.3,0.7c-0.1,0.3-0.3,0.5-0.5,0.5l-4.7,0.9c-0.4,0.1-0.7-0.2-0.8-0.6l-0.9-4.7c-0.1-0.3,0.1-0.5,0.3-0.7 - c0.2-0.2,0.5-0.2,0.8,0l1.8,1.2l3.1-4.4l-4.4-3.1l-1.2,1.8c-0.1,0.2-0.3,0.3-0.4,0.3c-0.1,0-0.2,0-0.3,0 - c-0.3-0.1-0.5-0.3-0.5-0.5l-0.9-4.7c-0.1-0.4,0.2-0.7,0.6-0.8l4.7-0.9c0.3-0.1,0.5,0.1,0.7,0.3c0.2,0.2,0.2,0.5,0,0.8l-1.2,1.8 - l4.4,3.1l3.1-4.4l-1.8-1.2c-0.2-0.2-0.3-0.4-0.3-0.7c0.1-0.3,0.3-0.5,0.5-0.5l4.7-0.9c0.4-0.1,0.7,0.2,0.8,0.6l0.9,4.7 - c0.1,0.3-0.1,0.5-0.3,0.7c-0.1,0-0.2,0.1-0.3,0.1c-0.2,0-0.4,0-0.5-0.1l-1.8-1.2L48.7,189.9z"/> + c0.2-0.2,0.5-0.2,0.8,0l1.8,1.2l3.1-4.4l-4.4-3.1L58,205c-0.1,0.2-0.3,0.3-0.4,0.3c-0.1,0-0.2,0-0.3,0c-0.3-0.1-0.5-0.3-0.5-0.5 + l-0.9-4.7c-0.1-0.4,0.2-0.7,0.6-0.8l4.7-0.9c0.3-0.1,0.5,0.1,0.7,0.3c0.2,0.2,0.2,0.5,0,0.8l-1.2,1.8l4.4,3.1l3.1-4.4l-1.8-1.2 + c-0.2-0.2-0.3-0.4-0.3-0.7c0.1-0.3,0.3-0.5,0.5-0.5l4.7-0.9c0.4-0.1,0.7,0.2,0.8,0.6l0.9,4.7c0.1,0.3-0.1,0.5-0.3,0.7 + c-0.1,0-0.2,0.1-0.3,0.1c-0.2,0-0.4,0-0.5-0.1l-1.8-1.2L67.1,205.6z"/> </g> </g> <g> - <path fill="#078876" d="M48.7,253.6l4.4,3.1l1.2-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.3,0.1,0.5,0.3,0.5,0.5l0.9,4.7 + <path fill="#048876" d="M67.1,269.3l4.4,3.1l1.2-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.3,0.1,0.5,0.3,0.5,0.5l0.9,4.7 c0.1,0.4-0.2,0.7-0.6,0.8l-4.7,0.9c-0.3,0.1-0.5-0.1-0.7-0.3c-0.2-0.2-0.2-0.5,0-0.8l1.2-1.8l-4.4-3.1l-3.1,4.4l1.8,1.2 c0.2,0.2,0.3,0.4,0.3,0.7c-0.1,0.3-0.3,0.5-0.5,0.5l-4.7,0.9c-0.4,0.1-0.7-0.2-0.8-0.6l-0.9-4.7c-0.1-0.3,0.1-0.5,0.3-0.7 c0.2-0.2,0.5-0.2,0.8,0l1.8,1.2l3.1-4.4l-4.4-3.1l-1.2,1.8c-0.1,0.2-0.3,0.3-0.4,0.3c-0.1,0-0.2,0-0.3,0c-0.3-0.1-0.5-0.3-0.5-0.5 l-0.9-4.7c-0.1-0.4,0.2-0.7,0.6-0.8l4.7-0.9c0.3-0.1,0.5,0.1,0.7,0.3c0.2,0.2,0.2,0.5,0,0.8l-1.2,1.8l4.4,3.1l3.1-4.4l-1.8-1.2 c-0.2-0.2-0.3-0.4-0.3-0.7c0.1-0.3,0.3-0.5,0.5-0.5l4.7-0.9c0.4-0.1,0.7,0.2,0.8,0.6l0.9,4.7c0.1,0.3-0.1,0.5-0.3,0.7 - c-0.1,0-0.2,0.1-0.3,0.1c-0.2,0-0.4,0-0.5-0.1l-1.8-1.2L48.7,253.6z"/> + c-0.1,0-0.2,0.1-0.3,0.1c-0.2,0-0.4,0-0.5-0.1l-1.8-1.2L67.1,269.3z"/> </g> <g> - <path fill="#078876" d="M48.7,316.6l4.4,3.1l1.2-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.3,0.1,0.5,0.3,0.5,0.5l0.9,4.7 + <path fill="#048876" d="M67.1,332.3l4.4,3.1l1.2-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.3,0.1,0.5,0.3,0.5,0.5l0.9,4.7 c0.1,0.4-0.2,0.7-0.6,0.8l-4.7,0.9c-0.3,0.1-0.5-0.1-0.7-0.3c-0.2-0.2-0.2-0.5,0-0.8l1.2-1.8l-4.4-3.1l-3.1,4.4l1.8,1.2 c0.2,0.2,0.3,0.4,0.3,0.7c-0.1,0.3-0.3,0.5-0.5,0.5l-4.7,0.9c-0.4,0.1-0.7-0.2-0.8-0.6l-0.9-4.7c-0.1-0.3,0.1-0.5,0.3-0.7 c0.2-0.2,0.5-0.2,0.8,0l1.8,1.2l3.1-4.4l-4.4-3.1l-1.2,1.8c-0.1,0.2-0.3,0.3-0.4,0.3c-0.1,0-0.2,0-0.3,0c-0.3-0.1-0.5-0.3-0.5-0.5 l-0.9-4.7c-0.1-0.4,0.2-0.7,0.6-0.8l4.7-0.9c0.3-0.1,0.5,0.1,0.7,0.3c0.2,0.2,0.2,0.5,0,0.8l-1.2,1.8l4.4,3.1l3.1-4.4l-1.8-1.2 c-0.2-0.2-0.3-0.4-0.3-0.7c0.1-0.3,0.3-0.5,0.5-0.5l4.7-0.9c0.4-0.1,0.7,0.2,0.8,0.6l0.9,4.7c0.1,0.3-0.1,0.5-0.3,0.7 - c-0.1,0-0.2,0.1-0.3,0.1c-0.2,0-0.4,0-0.5-0.1l-1.8-1.2L48.7,316.6z"/> + c-0.1,0-0.2,0.1-0.3,0.1c-0.2,0-0.4,0-0.5-0.1l-1.8-1.2L67.1,332.3z"/> </g> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="522" y1="93.7" x2="1013" y2="93.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="522" y1="30.7" x2="1013" y2="30.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="522" y1="223.7" x2="1013" y2="223.7"/> - <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="522" y1="159.7" x2="1013" y2="159.7"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="540.4" y1="109.4" x2="1031.4" y2="109.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="540.4" y1="46.4" x2="1031.4" y2="46.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="540.4" y1="239.4" x2="1031.4" y2="239.4"/> + <line fill="none" stroke="#E0E0E0" stroke-miterlimit="10" x1="540.4" y1="175.4" x2="1031.4" y2="175.4"/> <g> - <path fill="#333333" d="M643.7,48.9c0.3,0.1,0.6,0.4,0.9,0.7c0.2,0.3,0.4,0.6,0.4,1c0,0.3,0.1,0.6,0.1,1.1l0,4.7h-2v-4.7 - c0-0.3,0-0.5-0.1-0.7c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.1,0.7c-0.1,0.2-0.2,0.5-0.2,0.9v4.4h-2v-4.4c0-0.4,0-0.8-0.1-1 - c-0.2-0.4-0.5-0.5-1-0.5c-0.6,0-0.9,0.2-1.1,0.5c-0.1,0.2-0.2,0.5-0.2,0.9v4.5h-2v-7.4h1.9V50c0.2-0.4,0.5-0.7,0.7-0.8 - c0.4-0.3,0.9-0.4,1.5-0.4c0.6,0,1,0.1,1.4,0.4c0.3,0.2,0.5,0.5,0.6,0.9c0.3-0.4,0.6-0.8,1-1c0.4-0.2,0.8-0.3,1.3-0.3 - C643.1,48.7,643.4,48.8,643.7,48.9z"/> - <path fill="#333333" d="M653.1,55.4c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C654,53.7,653.7,54.6,653.1,55.4z M651.5,54.3c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C650.8,54.9,651.2,54.7,651.5,54.3z"/> - <path fill="#333333" d="M660,48.9h2.1l-2.7,7.5h-2.1l-2.7-7.5h2.2l1.6,5.5L660,48.9z"/> - <path fill="#333333" d="M668.1,49c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C666.9,48.7,667.5,48.8,668.1,49z M665.1,50.7c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C665.8,50.3,665.4,50.4,665.1,50.7z"/> - <path fill="#333333" d="M676.4,53.9c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H676.4z" + <path fill="#333333" d="M652.7,64.8h1.8v1c0.6-0.8,1.4-1.2,2.3-1.2c0.5,0,0.9,0.1,1.2,0.3s0.6,0.5,0.8,0.9c0.3-0.4,0.7-0.7,1-0.9 + s0.8-0.3,1.2-0.3c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.6,0.5,0.8,1c0.1,0.3,0.2,0.8,0.2,1.5V72h-1.9v-4.1c0-0.7-0.1-1.2-0.2-1.4 + c-0.2-0.3-0.5-0.4-0.8-0.4c-0.3,0-0.5,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5V72h-1.9v-4 + c0-0.7,0-1.2-0.1-1.4s-0.2-0.4-0.3-0.5s-0.3-0.2-0.6-0.2c-0.3,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7s-0.2,0.8-0.2,1.5V72 + h-1.9V64.8z"/> + <path fill="#333333" d="M664.9,68.3c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C665,69.8,664.9,69.1,664.9,68.3z M666.9,68.4c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S666.9,67.7,666.9,68.4z"/> + <path fill="#333333" d="M675.9,72l-2.9-7.3h2l1.4,3.7l0.4,1.2c0.1-0.3,0.2-0.5,0.2-0.6c0.1-0.2,0.1-0.4,0.2-0.6l1.4-3.7h2 + l-2.9,7.3H675.9z"/> + <path fill="#333333" d="M685.9,69.7l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S685.8,70.1,685.9,69.7z M686,67.8c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H686z"/> + <path fill="#333333" d="M692.7,70l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.3,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C693.2,71.2,692.9,70.6,692.7,70z"/> + <path fill="#333333" d="M705.3,69.7l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S705.2,70.1,705.3,69.7z M705.4,67.8c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H705.4z"/> + <path fill="#333333" d="M708.9,72V62h1.9v10H708.9z"/> + <path fill="#333333" d="M717,69.7l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S716.9,70.1,717,69.7z M717.1,67.8c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H717.1z"/> + <path fill="#333333" d="M726.9,66.9l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C726.3,65.6,726.7,66.1,726.9,66.9z"/> + <path fill="#333333" d="M731.7,64.8v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9v-1.5h0.9v-1.4l1.9-1.1v2.6H731.7z"/> + <path fill="#333333" d="M733,63.8V62h1.9v1.8H733z M733,72v-7.3h1.9V72H733z"/> + <path fill="#333333" d="M736.5,68.3c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C736.6,69.8,736.5,69.1,736.5,68.3z M738.5,68.4c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S738.5,67.7,738.5,68.4z"/> + <path fill="#333333" d="M752.1,72h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7V72h-1.9v-7.3h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V72z"/> + <path fill="#333333" d="M655.2,91.8c-0.7-0.9-1.3-1.9-1.7-3c-0.5-1.1-0.7-2.3-0.7-3.6c0-1.1,0.2-2.1,0.5-3.1 + c0.4-1.2,1-2.3,1.9-3.4h0.9c-0.6,0.9-0.9,1.6-1.1,2c-0.3,0.6-0.5,1.3-0.7,2c-0.2,0.9-0.3,1.7-0.3,2.6c0,2.2,0.7,4.4,2,6.6H655.2z" /> - <path fill="#333333" d="M687.5,49c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5H684 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C686.4,48.7,687,48.8,687.5,49z M684.6,50.7c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C685.3,50.3,684.9,50.4,684.6,50.7z"/> - <path fill="#333333" d="M692.4,56.3h-1.9V46.2h1.9V56.3z"/> - <path fill="#333333" d="M699.2,49c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C698.1,48.7,698.7,48.8,699.2,49z M696.3,50.7c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C696.9,50.3,696.5,50.4,696.3,50.7z"/> - <path fill="#333333" d="M706.6,51.5c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.3,1c-0.1,0.3-0.2,0.8-0.2,1.4 - c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2c0,0.6-0.3,1.2-0.6,1.7 - c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1s-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3s1.5-1.1,2.6-1.1c0.9,0,1.7,0.2,2.3,0.6 - c0.6,0.4,0.9,1.2,1.1,2.2H706.6z"/> - <path fill="#333333" d="M709.1,50.3v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H709.1z"/> - <path fill="#333333" d="M716.6,48h-2v-1.8h2V48z M714.6,48.9h2v7.5h-2V48.9z"/> - <path fill="#333333" d="M724.7,55.4c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C725.6,53.7,725.3,54.6,724.7,55.4z M723.1,54.3c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C722.4,54.9,722.8,54.7,723.1,54.3z"/> - <path fill="#333333" d="M733,49.3c0.5,0.4,0.7,1.1,0.7,2v5h-2v-4.5c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4H727v-7.4h1.9V50c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C731.9,48.7,732.5,48.9,733,49.3z"/> - <path fill="#333333" d="M637.6,62.9c-0.7,1.4-1.2,2.4-1.4,3.1c-0.3,1-0.5,2.2-0.5,3.5c0,1.3,0.2,2.5,0.6,3.6 - c0.2,0.7,0.7,1.6,1.3,2.9h-0.8c-0.7-1-1.1-1.7-1.2-2c-0.2-0.3-0.3-0.7-0.5-1.2c-0.3-0.7-0.4-1.4-0.5-2.2c0-0.4-0.1-0.8-0.1-1.1 - c0-1.3,0.2-2.5,0.6-3.6c0.3-0.7,0.8-1.7,1.7-3H637.6z"/> - <path fill="#333333" d="M639.1,63h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V63z"/> - <path fill="#333333" d="M652.2,66.5c0.6,0.6,1,1.6,1,2.8c0,1.2-0.3,2.2-0.9,2.9c-0.6,0.8-1.5,1.2-2.7,1.2c-1,0-1.8-0.3-2.4-1 - c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.2,0.3-2.2,0.9-2.9c0.6-0.7,1.5-1.1,2.5-1.1C650.7,65.6,651.5,65.9,652.2,66.5z M651.4,71.4 - c0.3-0.6,0.4-1.3,0.4-2.1c0-0.7-0.1-1.2-0.3-1.7c-0.3-0.7-0.9-1-1.8-1c-0.7,0-1.3,0.3-1.6,0.9s-0.5,1.3-0.5,2.1 - c0,0.8,0.2,1.4,0.5,1.9s0.9,0.8,1.6,0.8C650.5,72.3,651.1,72,651.4,71.4z"/> - <path fill="#333333" d="M654.7,65.8h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0V67 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V65.8z"/> - <path fill="#333333" d="M659.3,63.1h1.3v1.4h-1.3V63.1z M659.3,65.8h1.3v7.3h-1.3V65.8z"/> - <path fill="#333333" d="M661.9,72.1l4.3-5.2h-4v-1.1h5.7v1l-4.3,5.2h4.4v1.1h-6.1V72.1z"/> - <path fill="#333333" d="M674.7,66.5c0.6,0.6,1,1.6,1,2.8c0,1.2-0.3,2.2-0.9,2.9c-0.6,0.8-1.5,1.2-2.7,1.2c-1,0-1.8-0.3-2.4-1 - c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.2,0.3-2.2,0.9-2.9c0.6-0.7,1.5-1.1,2.5-1.1C673.3,65.6,674.1,65.9,674.7,66.5z M674,71.4 - c0.3-0.6,0.4-1.3,0.4-2.1c0-0.7-0.1-1.2-0.3-1.7c-0.3-0.7-0.9-1-1.8-1c-0.7,0-1.3,0.3-1.6,0.9s-0.5,1.3-0.5,2.1 - c0,0.8,0.2,1.4,0.5,1.9s0.9,0.8,1.6,0.8C673.1,72.3,673.7,72,674,71.4z"/> - <path fill="#333333" d="M677.2,65.8h1.2v1c0.3-0.4,0.7-0.7,1.1-0.9c0.4-0.2,0.8-0.3,1.3-0.3c1,0,1.7,0.4,2.1,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.4-0.1-0.8-0.2-1.1c-0.2-0.5-0.6-0.7-1.2-0.7c-0.3,0-0.5,0-0.7,0.1 - c-0.3,0.1-0.6,0.3-0.9,0.6c-0.2,0.2-0.3,0.5-0.4,0.7c-0.1,0.3-0.1,0.6-0.1,1.1v3.8h-1.2V65.8z"/> - <path fill="#333333" d="M685.2,63.8h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V63.8z"/> - <path fill="#333333" d="M692.8,68.7c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.2,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L692.8,68.7z M690.2,72c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C689.8,71.5,689.9,71.8,690.2,72z"/> - <path fill="#333333" d="M696.7,63.1h1.2v10h-1.2V63.1z"/> - <path fill="#333333" d="M703.6,65.8h1.2v1c0.2-0.3,0.5-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c0.8,0,1.5,0.3,2.1,1 - c0.6,0.6,0.9,1.5,0.9,2.7c0,1.6-0.4,2.7-1.3,3.4c-0.5,0.4-1.1,0.6-1.9,0.6c-0.6,0-1-0.1-1.4-0.4c-0.2-0.1-0.5-0.4-0.7-0.7V76h-1.2 - V65.8z M708.2,71.6c0.4-0.5,0.6-1.2,0.6-2.2c0-0.6-0.1-1.1-0.3-1.5c-0.3-0.8-0.9-1.2-1.8-1.2c-0.9,0-1.4,0.4-1.8,1.3 - c-0.2,0.5-0.3,1-0.3,1.7c0,0.6,0.1,1,0.3,1.4c0.3,0.8,0.9,1.1,1.8,1.1C707.3,72.3,707.8,72,708.2,71.6z"/> - <path fill="#333333" d="M711.5,63.1h1.2v10h-1.2V63.1z"/> - <path fill="#333333" d="M718.5,68.7c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.2,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L718.5,68.7z M715.9,72c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C715.5,71.5,715.6,71.8,715.9,72z"/> - <path fill="#333333" d="M722.3,65.8h1.2v1c0.3-0.4,0.7-0.7,1.1-0.9c0.4-0.2,0.8-0.3,1.3-0.3c1,0,1.7,0.4,2.1,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.4-0.1-0.8-0.2-1.1c-0.2-0.5-0.6-0.7-1.2-0.7c-0.3,0-0.5,0-0.7,0.1 - c-0.3,0.1-0.6,0.3-0.9,0.6c-0.2,0.2-0.3,0.5-0.4,0.7c-0.1,0.3-0.1,0.6-0.1,1.1v3.8h-1.2V65.8z"/> - <path fill="#333333" d="M734.6,66c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6H731 - c0,0.7,0.2,1.3,0.5,1.8s0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9s1.5-1.1,2.5-1.1C733.7,65.6,734.2,65.8,734.6,66z M735.1,68.9c0-0.5-0.2-1-0.3-1.3c-0.3-0.6-0.9-0.9-1.7-0.9 - c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H735.1z"/> - <path fill="#333333" d="M737.5,76c0.7-1.4,1.2-2.4,1.4-3.1c0.3-1,0.5-2.1,0.5-3.4s-0.2-2.5-0.6-3.6c-0.2-0.7-0.7-1.6-1.3-2.9h0.8 - c0.7,1.1,1.1,1.8,1.3,2.1c0.1,0.3,0.3,0.6,0.5,1.1c0.2,0.6,0.4,1.1,0.5,1.7c0.1,0.6,0.1,1.1,0.1,1.6c0,1.3-0.2,2.6-0.6,3.6 - c-0.3,0.7-0.8,1.7-1.7,3H737.5z"/> + <path fill="#333333" d="M657.5,88.8v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.6,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H657.5z"/> + <path fill="#333333" d="M664.8,85.2c0-1.3,0.4-2.3,1.1-3c0.6-0.5,1.4-0.8,2.3-0.8c1,0,1.8,0.3,2.4,1c0.6,0.7,1,1.6,1,2.7 + c0,0.9-0.1,1.7-0.4,2.2c-0.3,0.5-0.7,1-1.2,1.2c-0.5,0.3-1.1,0.4-1.8,0.4c-1,0-1.8-0.3-2.5-1C665.1,87.4,664.8,86.4,664.8,85.2z + M666.1,85.2c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.7c0.4-0.5,0.6-1.2,0.6-2.1c0-0.9-0.2-1.6-0.6-2 + c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1.1,0.2-1.5,0.7C666.3,83.6,666.1,84.3,666.1,85.2z"/> + <path fill="#333333" d="M673,88.8v-7.3h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H673z"/> + <path fill="#333333" d="M677.7,80.2v-1.4h1.2v1.4H677.7z M677.7,88.8v-7.3h1.2v7.3H677.7z"/> + <path fill="#333333" d="M680.2,88.8v-1l4.6-5.3c-0.5,0-1,0-1.4,0h-3v-1h5.9v0.8l-3.9,4.6l-0.8,0.8c0.6,0,1.1-0.1,1.6-0.1h3.4v1.1 + H680.2z"/> + <path fill="#333333" d="M687.4,85.2c0-1.3,0.4-2.3,1.1-3c0.6-0.5,1.4-0.8,2.3-0.8c1,0,1.8,0.3,2.4,1c0.6,0.7,1,1.6,1,2.7 + c0,0.9-0.1,1.7-0.4,2.2c-0.3,0.5-0.7,1-1.2,1.2c-0.5,0.3-1.1,0.4-1.8,0.4c-1,0-1.8-0.3-2.5-1C687.7,87.4,687.4,86.4,687.4,85.2z + M688.6,85.2c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.7c0.4-0.5,0.6-1.2,0.6-2.1c0-0.9-0.2-1.6-0.6-2 + c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1.1,0.2-1.5,0.7C688.8,83.6,688.6,84.3,688.6,85.2z"/> + <path fill="#333333" d="M695.6,88.8v-7.3h1.1v1c0.5-0.8,1.3-1.2,2.3-1.2c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.4,0.8,0.6 + c0.2,0.3,0.3,0.6,0.4,0.9c0,0.2,0.1,0.6,0.1,1.2v4.5h-1.2v-4.4c0-0.5,0-0.9-0.1-1.1c-0.1-0.2-0.3-0.4-0.5-0.6 + c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-1,0.2-1.4,0.5c-0.4,0.3-0.6,1-0.6,1.9v4H695.6z"/> + <path fill="#333333" d="M706.1,87.7l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C705.7,87.8,705.8,87.8,706.1,87.7z"/> + <path fill="#333333" d="M712,87.9c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.3-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C712.1,88.6,712,88.3,712,87.9z M711.9,85.2c-0.4,0.2-1.1,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.1,0.2 + c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.3-0.3 + c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V85.2z"/> + <path fill="#333333" d="M715,88.8v-10h1.2v10H715z"/> + <path fill="#333333" d="M722.1,91.6v-10h1.1v0.9c0.3-0.4,0.6-0.6,0.9-0.8c0.3-0.2,0.7-0.3,1.2-0.3c0.6,0,1.2,0.2,1.6,0.5 + c0.5,0.3,0.8,0.8,1.1,1.3c0.2,0.6,0.4,1.2,0.4,1.9c0,0.7-0.1,1.4-0.4,2c-0.3,0.6-0.7,1-1.2,1.4c-0.5,0.3-1,0.5-1.6,0.5 + c-0.4,0-0.8-0.1-1.1-0.3c-0.3-0.2-0.6-0.4-0.8-0.7v3.5H722.1z M723.2,85.2c0,0.9,0.2,1.6,0.6,2.1c0.4,0.4,0.8,0.7,1.4,0.7 + c0.5,0,1-0.2,1.4-0.7c0.4-0.5,0.6-1.2,0.6-2.2c0-0.9-0.2-1.6-0.6-2.1c-0.4-0.5-0.8-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7 + C723.4,83.6,723.2,84.3,723.2,85.2z"/> + <path fill="#333333" d="M729.8,88.8v-10h1.2v10H729.8z"/> + <path fill="#333333" d="M737.7,87.9c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.3-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C737.8,88.6,737.7,88.3,737.7,87.9z M737.6,85.2c-0.4,0.2-1.1,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.1,0.2 + c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.3-0.3 + c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V85.2z"/> + <path fill="#333333" d="M740.7,88.8v-7.3h1.1v1c0.5-0.8,1.3-1.2,2.3-1.2c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.4,0.8,0.6 + c0.2,0.3,0.3,0.6,0.4,0.9c0,0.2,0.1,0.6,0.1,1.2v4.5h-1.2v-4.4c0-0.5,0-0.9-0.1-1.1c-0.1-0.2-0.3-0.4-0.5-0.6 + c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-1,0.2-1.4,0.5c-0.4,0.3-0.6,1-0.6,1.9v4H740.7z"/> + <path fill="#333333" d="M753.5,86.5l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3h-5.4 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C753.1,87.4,753.3,87,753.5,86.5z M749.5,84.5h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C749.7,83.4,749.5,83.9,749.5,84.5z"/> + <path fill="#333333" d="M757.1,91.8h-0.9c1.4-2.2,2-4.4,2-6.6c0-0.9-0.1-1.7-0.3-2.5c-0.2-0.7-0.4-1.3-0.6-2 + c-0.2-0.4-0.5-1.1-1.1-2.1h0.9c0.9,1.1,1.5,2.3,1.9,3.4c0.4,1,0.5,2,0.5,3.1c0,1.2-0.2,2.4-0.7,3.6S757.8,90.9,757.1,91.8z"/> </g> <g> - <path fill="#333333" d="M716.7,114.1c0.3,0.1,0.6,0.4,0.9,0.7c0.2,0.3,0.4,0.6,0.4,1c0,0.3,0.1,0.6,0.1,1.1l0,4.7h-2v-4.7 - c0-0.3,0-0.5-0.1-0.7c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.1,0.7c-0.1,0.2-0.2,0.5-0.2,0.9v4.4h-2v-4.4c0-0.4,0-0.8-0.1-1 - c-0.2-0.4-0.5-0.5-1-0.5c-0.6,0-0.9,0.2-1.1,0.5c-0.1,0.2-0.2,0.5-0.2,0.9v4.5h-2v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8 - c0.4-0.3,0.9-0.4,1.5-0.4c0.6,0,1,0.1,1.4,0.4c0.3,0.2,0.5,0.5,0.6,0.9c0.3-0.4,0.6-0.8,1-1c0.4-0.2,0.8-0.3,1.3-0.3 - C716.1,113.9,716.4,114,716.7,114.1z"/> - <path fill="#333333" d="M726.1,120.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C727,118.9,726.7,119.9,726.1,120.6z M724.5,119.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C723.8,120.2,724.2,120,724.5,119.6z"/> - <path fill="#333333" d="M733,114.1h2.1l-2.7,7.5h-2.1l-2.7-7.5h2.2l1.6,5.5L733,114.1z"/> - <path fill="#333333" d="M741.1,114.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C739.9,113.9,740.5,114,741.1,114.3z M738.1,115.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C738.8,115.5,738.4,115.7,738.1,115.9z"/> - <path fill="#333333" d="M749.4,119.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H749.4z" - /> - <path fill="#333333" d="M760.5,114.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5H757 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C759.4,113.9,760,114,760.5,114.3z M757.6,115.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C758.3,115.5,757.9,115.7,757.6,115.9z"/> - <path fill="#333333" d="M765.4,121.6h-1.9v-10.1h1.9V121.6z"/> - <path fill="#333333" d="M772.2,114.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C771.1,113.9,771.7,114,772.2,114.3z M769.3,115.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C769.9,115.5,769.5,115.7,769.3,115.9z"/> - <path fill="#333333" d="M779.6,116.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.3,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1s-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3s1.5-1.1,2.6-1.1 - c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H779.6z"/> - <path fill="#333333" d="M782.1,115.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H782.1z"/> - <path fill="#333333" d="M789.6,113.2h-2v-1.8h2V113.2z M787.6,114.1h2v7.5h-2V114.1z"/> - <path fill="#333333" d="M797.7,120.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C798.6,118.9,798.3,119.9,797.7,120.6z M796.1,119.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C795.4,120.2,795.8,120,796.1,119.6z"/> - <path fill="#333333" d="M806,114.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V117c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4H800v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C804.9,113.9,805.5,114.1,806,114.5z"/> - <path fill="#333333" d="M814.4,114.1v4.5c0,0.4,0,0.7,0.1,1c0.2,0.4,0.5,0.6,1,0.6c0.7,0,1.1-0.3,1.4-0.8c0.1-0.3,0.2-0.7,0.2-1.2 - v-4.1h2v7.5h-1.9v-1.1c0,0-0.1,0.1-0.1,0.2c-0.1,0.1-0.2,0.2-0.3,0.3c-0.3,0.3-0.6,0.5-0.9,0.6c-0.3,0.1-0.6,0.2-1,0.2 - c-1.1,0-1.8-0.4-2.2-1.2c-0.2-0.4-0.3-1.1-0.3-1.9v-4.5H814.4z"/> - <path fill="#333333" d="M827.3,114.9c0.6,0.6,0.9,1.6,0.9,2.8c0,1.3-0.3,2.3-0.9,3s-1.4,1-2.3,1c-0.6,0-1.1-0.1-1.5-0.4 - c-0.2-0.2-0.4-0.4-0.6-0.7v3.9h-1.9v-10.4h1.9v1.1c0.2-0.3,0.4-0.6,0.7-0.8c0.4-0.3,1-0.5,1.6-0.5 - C825.9,113.9,826.7,114.3,827.3,114.9z M825.8,116.3c-0.3-0.4-0.7-0.7-1.3-0.7c-0.7,0-1.2,0.3-1.5,1c-0.1,0.4-0.2,0.8-0.2,1.4 - c0,0.9,0.2,1.5,0.7,1.8c0.3,0.2,0.6,0.3,1,0.3c0.5,0,1-0.2,1.3-0.6s0.4-1,0.4-1.7C826.2,117.3,826,116.8,825.8,116.3z"/> - <path fill="#333333" d="M831.8,111.2h1.6l-3.9,10.4h-1.6L831.8,111.2z"/> - <path fill="#333333" d="M837.4,114.2c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1C836.6,113.9,837,114,837.4,114.2z - M837.9,119.5c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6 - c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6C837.2,120.2,837.6,119.9,837.9,119.5z"/> - <path fill="#333333" d="M848.2,120.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C849.2,118.9,848.8,119.9,848.2,120.6z M846.7,119.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C845.9,120.2,846.3,120,846.7,119.6z"/> - <path fill="#333333" d="M854.1,114.1h2l1.1,5.4l1.2-5.4h2l-2.2,7.5h-2l-1.2-5.4l-1.2,5.4h-2l-2.1-7.5h2.1l1.2,5.3L854.1,114.1z"/> - <path fill="#333333" d="M867.4,114.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V117c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C866.3,113.9,867,114.1,867.4,114.5z"/> - <path fill="#333333" d="M710.6,128.2c-0.7,1.4-1.2,2.4-1.4,3.1c-0.3,1-0.5,2.2-0.5,3.5c0,1.3,0.2,2.5,0.6,3.6 - c0.2,0.7,0.7,1.6,1.3,2.9h-0.8c-0.7-1-1.1-1.7-1.2-2c-0.2-0.3-0.3-0.7-0.5-1.2c-0.3-0.7-0.4-1.4-0.5-2.2c0-0.4-0.1-0.8-0.1-1.1 - c0-1.3,0.2-2.5,0.6-3.6c0.3-0.7,0.8-1.7,1.7-3H710.6z"/> - <path fill="#333333" d="M712.7,131l2,6l2-6h1.3l-2.8,7.3h-1.3l-2.7-7.3H712.7z"/> - <path fill="#333333" d="M723.6,131.2c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6H720 - c0,0.7,0.2,1.3,0.5,1.8s0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9s1.5-1.1,2.5-1.1C722.6,130.9,723.1,131,723.6,131.2z M724,134.1c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H724z"/> - <path fill="#333333" d="M726.9,131h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0v1.3 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V131z"/> - <path fill="#333333" d="M731.8,129h1.2v2h1.2v1H733v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1V132h-1v-1h1V129z"/> - <path fill="#333333" d="M735.4,128.3h1.3v1.4h-1.3V128.3z M735.4,131.1h1.3v7.3h-1.3V131.1z"/> - <path fill="#333333" d="M743.3,131.4c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C742.2,130.8,742.8,131,743.3,131.4z"/> - <path fill="#333333" d="M749.4,133.9c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.2,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L749.4,133.9z M746.8,137.3c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C746.5,136.8,746.6,137,746.8,137.3z"/> - <path fill="#333333" d="M753.3,128.3h1.2v10h-1.2V128.3z"/> - <path fill="#333333" d="M760.2,131.1h1.2v1c0.2-0.3,0.5-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c0.8,0,1.5,0.3,2.1,1 - c0.6,0.6,0.9,1.5,0.9,2.7c0,1.6-0.4,2.7-1.3,3.4c-0.5,0.4-1.1,0.6-1.9,0.6c-0.6,0-1-0.1-1.4-0.4c-0.2-0.1-0.5-0.4-0.7-0.7v3.7 - h-1.2V131.1z M764.8,136.8c0.4-0.5,0.6-1.2,0.6-2.2c0-0.6-0.1-1.1-0.3-1.5c-0.3-0.8-0.9-1.2-1.8-1.2c-0.9,0-1.4,0.4-1.8,1.3 - c-0.2,0.5-0.3,1-0.3,1.7c0,0.6,0.1,1,0.3,1.4c0.3,0.8,0.9,1.1,1.8,1.1C764,137.5,764.4,137.3,764.8,136.8z"/> - <path fill="#333333" d="M768.1,128.3h1.2v10h-1.2V128.3z"/> - <path fill="#333333" d="M775.1,133.9c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.2,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L775.1,133.9z M772.5,137.3c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C772.1,136.8,772.3,137,772.5,137.3z"/> - <path fill="#333333" d="M779,131h1.2v1c0.3-0.4,0.7-0.7,1.1-0.9c0.4-0.2,0.8-0.3,1.3-0.3c1,0,1.7,0.4,2.1,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.4-0.1-0.8-0.2-1.1c-0.2-0.5-0.6-0.7-1.2-0.7c-0.3,0-0.5,0-0.7,0.1 - c-0.3,0.1-0.6,0.3-0.9,0.6c-0.2,0.2-0.3,0.5-0.4,0.7c-0.1,0.3-0.1,0.6-0.1,1.1v3.8H779V131z"/> - <path fill="#333333" d="M791.3,131.2c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8s0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9s1.5-1.1,2.5-1.1C790.3,130.9,790.8,131,791.3,131.2z M791.7,134.1c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H791.7z"/> - <path fill="#333333" d="M794.1,141.2c0.7-1.4,1.2-2.4,1.4-3.1c0.3-1,0.5-2.1,0.5-3.4s-0.2-2.5-0.6-3.6c-0.2-0.7-0.7-1.6-1.3-2.9 - h0.8c0.7,1.1,1.1,1.8,1.3,2.1c0.1,0.3,0.3,0.6,0.5,1.1c0.2,0.6,0.4,1.1,0.5,1.7c0.1,0.6,0.1,1.1,0.1,1.6c0,1.3-0.2,2.6-0.6,3.6 - c-0.3,0.7-0.8,1.7-1.7,3H794.1z"/> - <path fill="#333333" d="M803.7,131l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3h-1.3l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3H803.7 - z"/> - <path fill="#333333" d="M813.2,128.3h1.3v1.4h-1.3V128.3z M813.2,131.1h1.3v7.3h-1.3V131.1z"/> - <path fill="#333333" d="M816.6,129h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1V132h-1v-1h1V129z"/> - <path fill="#333333" d="M820.2,128.3h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V128.3z"/> - <path fill="#333333" d="M835.8,133.9c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.2,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L835.8,133.9z M833.2,137.3c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C832.8,136.8,833,137,833.2,137.3z"/> - <path fill="#333333" d="M839.7,128.3h1.2v10h-1.2V128.3z"/> - <path fill="#333333" d="M843,129h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1V132h-1v-1h1V129z"/> - <path fill="#333333" d="M850.3,135.4v-1.1h3v-3h1.2v3h3v1.1h-3v3h-1.2v-3H850.3z"/> - <path fill="#333333" d="M863.9,131v4.9c0,0.4,0.1,0.7,0.2,0.9c0.2,0.4,0.6,0.7,1.2,0.7c0.8,0,1.4-0.4,1.7-1.1 - c0.2-0.4,0.2-1,0.2-1.7V131h1.2v7.3h-1.2l0-1.1c-0.2,0.3-0.4,0.5-0.6,0.7c-0.5,0.4-1,0.6-1.7,0.6c-1,0-1.7-0.3-2.1-1 - c-0.2-0.4-0.3-0.9-0.3-1.5v-5H863.9z"/> - <path fill="#333333" d="M870.3,131.1h1.2v1c0.2-0.3,0.5-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c0.8,0,1.5,0.3,2.1,1 - c0.6,0.6,0.9,1.5,0.9,2.7c0,1.6-0.4,2.7-1.3,3.4c-0.5,0.4-1.1,0.6-1.9,0.6c-0.6,0-1-0.1-1.4-0.4c-0.2-0.1-0.5-0.4-0.7-0.7v3.7 - h-1.2V131.1z M874.9,136.8c0.4-0.5,0.6-1.2,0.6-2.2c0-0.6-0.1-1.1-0.3-1.5c-0.3-0.8-0.9-1.2-1.8-1.2c-0.9,0-1.4,0.4-1.8,1.3 - c-0.2,0.5-0.3,1-0.3,1.7c0,0.6,0.1,1,0.3,1.4c0.3,0.8,0.9,1.1,1.8,1.1C874.1,137.5,874.6,137.3,874.9,136.8z"/> - <path fill="#333333" d="M884.4,128.3h1l-3.2,10h-1L884.4,128.3z"/> - <path fill="#333333" d="M893.9,131.3c0.2,0.1,0.5,0.4,0.7,0.7v-3.7h1.2v10.1h-1.1v-1c-0.3,0.5-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.8,0-1.5-0.3-2.1-1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.1,0.3-2,0.8-2.8c0.5-0.8,1.3-1.2,2.3-1.2C893.1,130.9,893.5,131,893.9,131.3z - M891.2,136.8c0.3,0.5,0.9,0.8,1.6,0.8c0.6,0,1-0.2,1.4-0.7c0.4-0.5,0.5-1.2,0.5-2.1c0-0.9-0.2-1.6-0.6-2.1 - c-0.4-0.4-0.8-0.7-1.4-0.7c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.5-0.6,1.2-0.6,2.1C890.7,135.6,890.8,136.2,891.2,136.8z"/> - <path fill="#333333" d="M903,131.8c0.6,0.6,1,1.6,1,2.8c0,1.2-0.3,2.2-0.9,2.9c-0.6,0.8-1.5,1.2-2.7,1.2c-1,0-1.8-0.3-2.4-1 - c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.2,0.3-2.2,0.9-2.9c0.6-0.7,1.5-1.1,2.5-1.1C901.5,130.8,902.3,131.1,903,131.8z M902.2,136.6 - c0.3-0.6,0.4-1.3,0.4-2.1c0-0.7-0.1-1.2-0.3-1.7c-0.3-0.7-0.9-1-1.8-1c-0.7,0-1.3,0.3-1.6,0.9s-0.5,1.3-0.5,2.1 - c0,0.8,0.2,1.4,0.5,1.9s0.9,0.8,1.6,0.8C901.3,137.6,901.9,137.3,902.2,136.6z"/> - <path fill="#333333" d="M906,131l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3H911l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3H906z"/> - <path fill="#333333" d="M915.6,131h1.2v1c0.3-0.4,0.7-0.7,1.1-0.9c0.4-0.2,0.8-0.3,1.3-0.3c1,0,1.7,0.4,2.1,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.4-0.1-0.8-0.2-1.1c-0.2-0.5-0.6-0.7-1.2-0.7c-0.3,0-0.5,0-0.7,0.1 - c-0.3,0.1-0.6,0.3-0.9,0.6c-0.2,0.2-0.3,0.5-0.4,0.7c-0.1,0.3-0.1,0.6-0.1,1.1v3.8h-1.2V131z"/> + <path fill="#333333" d="M725.7,130h1.8v1c0.6-0.8,1.4-1.2,2.3-1.2c0.5,0,0.9,0.1,1.2,0.3s0.6,0.5,0.8,0.9c0.3-0.4,0.7-0.7,1-0.9 + s0.8-0.3,1.2-0.3c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.6,0.5,0.8,1c0.1,0.3,0.2,0.8,0.2,1.5v4.6h-1.9v-4.1c0-0.7-0.1-1.2-0.2-1.4 + c-0.2-0.3-0.5-0.4-0.8-0.4c-0.3,0-0.5,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5v3.5h-1.9v-4 + c0-0.7,0-1.2-0.1-1.4s-0.2-0.4-0.3-0.5s-0.3-0.2-0.6-0.2c-0.3,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7s-0.2,0.8-0.2,1.5v3.5 + h-1.9V130z"/> + <path fill="#333333" d="M737.9,133.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C738,135.1,737.9,134.4,737.9,133.5z M739.9,133.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S739.9,132.9,739.9,133.6z"/> + <path fill="#333333" d="M748.9,137.3L746,130h2l1.4,3.7l0.4,1.2c0.1-0.3,0.2-0.5,0.2-0.6c0.1-0.2,0.1-0.4,0.2-0.6l1.4-3.7h2 + l-2.9,7.3H748.9z"/> + <path fill="#333333" d="M758.9,135l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S758.8,135.3,758.9,135z M759,133c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H759z"/> + <path fill="#333333" d="M765.7,135.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.3,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C766.2,136.4,765.9,135.9,765.7,135.2z"/> + <path fill="#333333" d="M778.3,135l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S778.2,135.3,778.3,135z M778.4,133c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H778.4z"/> + <path fill="#333333" d="M781.9,137.3v-10h1.9v10H781.9z"/> + <path fill="#333333" d="M790,135l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S789.9,135.3,790,135z M790.1,133c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H790.1z"/> + <path fill="#333333" d="M799.9,132.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C799.3,130.8,799.7,131.4,799.9,132.2z"/> + <path fill="#333333" d="M804.7,130v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V130h0.9v-1.4l1.9-1.1v2.6H804.7z"/> + <path fill="#333333" d="M806,129v-1.8h1.9v1.8H806z M806,137.3V130h1.9v7.3H806z"/> + <path fill="#333333" d="M809.5,133.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C809.6,135.1,809.5,134.4,809.5,133.5z M811.5,133.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S811.5,132.9,811.5,133.6z"/> + <path fill="#333333" d="M825.1,137.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V130h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V137.3z"/> + <path fill="#333333" d="M835.7,137.3v-1.1c-0.3,0.4-0.6,0.7-1,0.9s-0.9,0.3-1.4,0.3c-0.5,0-0.9-0.1-1.3-0.3 + c-0.4-0.2-0.7-0.5-0.8-0.9c-0.2-0.4-0.3-0.9-0.3-1.6V130h1.9v3.3c0,1,0,1.6,0.1,1.9c0.1,0.2,0.2,0.4,0.4,0.5 + c0.2,0.1,0.4,0.2,0.7,0.2c0.3,0,0.6-0.1,0.9-0.3c0.3-0.2,0.4-0.4,0.5-0.7c0.1-0.3,0.1-0.9,0.1-2V130h1.9v7.3H835.7z"/> + <path fill="#333333" d="M839.4,130h1.8v1.1c0.2-0.4,0.5-0.7,0.9-0.9s0.8-0.3,1.3-0.3c0.8,0,1.6,0.3,2.1,1s0.9,1.6,0.9,2.8 + c0,1.2-0.3,2.2-0.9,2.8c-0.6,0.7-1.3,1-2.2,1c-0.4,0-0.8-0.1-1.1-0.2c-0.3-0.2-0.7-0.4-1-0.8v3.7h-1.9V130z M841.3,133.5 + c0,0.8,0.2,1.4,0.5,1.8c0.3,0.4,0.7,0.6,1.2,0.6c0.4,0,0.8-0.2,1.1-0.5c0.3-0.4,0.4-0.9,0.4-1.8c0-0.8-0.2-1.3-0.5-1.7 + c-0.3-0.4-0.7-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.2,0.5C841.5,132.3,841.3,132.8,841.3,133.5z"/> + <path fill="#333333" d="M847,137.4l2.5-10.4h1.4l-2.5,10.4H847z"/> + <path fill="#333333" d="M858.6,137.3h-1.8v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V137.3z M853.5,133.5 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C853.6,132.2,853.5,132.8,853.5,133.5z"/> + <path fill="#333333" d="M860,133.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C860.2,135.1,860,134.4,860,133.5z M862,133.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S862,132.9,862,133.6z"/> + <path fill="#333333" d="M870.4,137.3l-2.3-7.3h1.9l1.4,4.8l1.3-4.8h1.9l1.2,4.8l1.4-4.8h1.9l-2.3,7.3h-1.8l-1.3-4.7l-1.2,4.7 + H870.4z"/> + <path fill="#333333" d="M886.5,137.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V130h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V137.3z"/> + <path fill="#333333" d="M728.2,157c-0.7-0.9-1.3-1.9-1.7-3c-0.5-1.1-0.7-2.3-0.7-3.6c0-1.1,0.2-2.1,0.5-3.1c0.4-1.2,1-2.3,1.9-3.4 + h0.9c-0.6,0.9-0.9,1.6-1.1,2c-0.3,0.6-0.5,1.3-0.7,2c-0.2,0.9-0.3,1.7-0.3,2.6c0,2.2,0.7,4.4,2,6.6H728.2z"/> + <path fill="#333333" d="M732.5,154.1l-2.8-7.3h1.3l1.6,4.3c0.2,0.5,0.3,1,0.5,1.5c0.1-0.4,0.3-0.8,0.5-1.4l1.6-4.4h1.3l-2.7,7.3 + H732.5z"/> + <path fill="#333333" d="M742.4,151.7l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3h-5.4 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C742,152.6,742.3,152.3,742.4,151.7z M738.4,149.7h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C738.7,148.6,738.4,149.1,738.4,149.7z"/> + <path fill="#333333" d="M745.2,154.1v-7.3h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H745.2z"/> + <path fill="#333333" d="M752.6,153l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9V145l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C752.2,153,752.4,153,752.6,153z"/> + <path fill="#333333" d="M753.8,145.5V144h1.2v1.4H753.8z M753.8,154.1v-7.3h1.2v7.3H753.8z"/> + <path fill="#333333" d="M761.7,151.4l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C761.4,152.5,761.6,152,761.7,151.4z"/> + <path fill="#333333" d="M768.7,153.2c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.3-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C768.8,153.8,768.7,153.5,768.7,153.2z M768.6,150.4c-0.4,0.2-1.1,0.3-2,0.5 + c-0.5,0.1-0.9,0.2-1.1,0.2c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3 + c0.5,0,0.9-0.1,1.3-0.3c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V150.4z"/> + <path fill="#333333" d="M771.7,154.1v-10h1.2v10H771.7z"/> + <path fill="#333333" d="M778.7,156.9v-10h1.1v0.9c0.3-0.4,0.6-0.6,0.9-0.8c0.3-0.2,0.7-0.3,1.2-0.3c0.6,0,1.2,0.2,1.6,0.5 + c0.5,0.3,0.8,0.8,1.1,1.3c0.2,0.6,0.4,1.2,0.4,1.9c0,0.7-0.1,1.4-0.4,2c-0.3,0.6-0.7,1-1.2,1.4c-0.5,0.3-1,0.5-1.6,0.5 + c-0.4,0-0.8-0.1-1.1-0.3c-0.3-0.2-0.6-0.4-0.8-0.7v3.5H778.7z M779.8,150.5c0,0.9,0.2,1.6,0.6,2.1c0.4,0.4,0.8,0.7,1.4,0.7 + c0.5,0,1-0.2,1.4-0.7c0.4-0.5,0.6-1.2,0.6-2.2c0-0.9-0.2-1.6-0.6-2.1c-0.4-0.5-0.8-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7 + C780,148.8,779.8,149.5,779.8,150.5z"/> + <path fill="#333333" d="M786.5,154.1v-10h1.2v10H786.5z"/> + <path fill="#333333" d="M794.3,153.2c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.3-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C794.5,153.8,794.4,153.5,794.3,153.2z M794.2,150.4c-0.4,0.2-1.1,0.3-2,0.5 + c-0.5,0.1-0.9,0.2-1.1,0.2c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3 + c0.5,0,0.9-0.1,1.3-0.3c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V150.4z"/> + <path fill="#333333" d="M797.4,154.1v-7.3h1.1v1c0.5-0.8,1.3-1.2,2.3-1.2c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.4,0.8,0.6 + c0.2,0.3,0.3,0.6,0.4,0.9c0,0.2,0.1,0.6,0.1,1.2v4.5h-1.2v-4.4c0-0.5,0-0.9-0.1-1.1c-0.1-0.2-0.3-0.4-0.5-0.6 + c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-1,0.2-1.4,0.5c-0.4,0.3-0.6,1-0.6,1.9v4H797.4z"/> + <path fill="#333333" d="M810.1,151.7l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3H806 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C809.7,152.6,810,152.3,810.1,151.7z M806.1,149.7h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C806.4,148.6,806.1,149.1,806.1,149.7z"/> + <path fill="#333333" d="M813.8,157h-0.9c1.4-2.2,2-4.4,2-6.6c0-0.9-0.1-1.7-0.3-2.5c-0.2-0.7-0.4-1.3-0.6-2 + c-0.2-0.4-0.5-1.1-1.1-2.1h0.9c0.9,1.1,1.5,2.3,1.9,3.4c0.4,1,0.5,2,0.5,3.1c0,1.2-0.2,2.4-0.7,3.6S814.4,156.2,813.8,157z"/> + <path fill="#333333" d="M822.8,154.1l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3H827l-1.2-4.3l-0.3-1.2l-1.5,5.6H822.8z"/> + <path fill="#333333" d="M831.6,145.5V144h1.2v1.4H831.6z M831.6,154.1v-7.3h1.2v7.3H831.6z"/> + <path fill="#333333" d="M837.4,153l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9V145l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C837,153,837.2,153,837.4,153z"/> + <path fill="#333333" d="M838.6,154.1v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.6,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H838.6z"/> + <path fill="#333333" d="M855,153.2c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.3-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C855.2,153.8,855.1,153.5,855,153.2z M854.9,150.4c-0.4,0.2-1.1,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.1,0.2 + c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.3-0.3 + c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V150.4z"/> + <path fill="#333333" d="M858.1,154.1v-10h1.2v10H858.1z"/> + <path fill="#333333" d="M863.9,153l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9V145l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C863.5,153,863.7,153,863.9,153z"/> + <path fill="#333333" d="M871.6,152.4v-2.7h-2.7v-1.1h2.7v-2.7h1.2v2.7h2.7v1.1h-2.7v2.7H871.6z"/> + <path fill="#333333" d="M885.8,154.1V153c-0.6,0.8-1.3,1.2-2.3,1.2c-0.4,0-0.8-0.1-1.2-0.2c-0.4-0.2-0.6-0.4-0.8-0.6 + c-0.2-0.2-0.3-0.6-0.4-0.9c0-0.2-0.1-0.6-0.1-1.1v-4.5h1.2v4c0,0.6,0,1.1,0.1,1.3c0.1,0.3,0.2,0.6,0.5,0.8 + c0.3,0.2,0.6,0.3,0.9,0.3s0.7-0.1,1-0.3c0.3-0.2,0.6-0.4,0.7-0.8c0.1-0.3,0.2-0.8,0.2-1.4v-3.9h1.2v7.3H885.8z"/> + <path fill="#333333" d="M888.8,156.9v-10h1.1v0.9c0.3-0.4,0.6-0.6,0.9-0.8c0.3-0.2,0.7-0.3,1.2-0.3c0.6,0,1.2,0.2,1.6,0.5 + c0.5,0.3,0.8,0.8,1.1,1.3c0.2,0.6,0.4,1.2,0.4,1.9c0,0.7-0.1,1.4-0.4,2c-0.3,0.6-0.7,1-1.2,1.4c-0.5,0.3-1,0.5-1.6,0.5 + c-0.4,0-0.8-0.1-1.1-0.3c-0.3-0.2-0.6-0.4-0.8-0.7v3.5H888.8z M889.9,150.5c0,0.9,0.2,1.6,0.6,2.1c0.4,0.4,0.8,0.7,1.4,0.7 + c0.5,0,1-0.2,1.4-0.7c0.4-0.5,0.6-1.2,0.6-2.2c0-0.9-0.2-1.6-0.6-2.1c-0.4-0.5-0.8-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7 + C890.1,148.8,889.9,149.5,889.9,150.5z"/> + <path fill="#333333" d="M899.6,154.2l2.9-10.4h1l-2.9,10.4H899.6z"/> + <path fill="#333333" d="M913,154.1v-0.9c-0.5,0.7-1.1,1.1-2,1.1c-0.6,0-1.1-0.2-1.6-0.5s-0.9-0.8-1.1-1.3c-0.3-0.6-0.4-1.2-0.4-2 + c0-0.7,0.1-1.4,0.4-2c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.6-0.5c0.4,0,0.8,0.1,1.2,0.3c0.3,0.2,0.6,0.4,0.8,0.7V144h1.2v10H913 + z M909.1,150.4c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.4,0.7c0.5,0,1-0.2,1.4-0.7c0.4-0.4,0.6-1.1,0.6-2c0-1-0.2-1.7-0.6-2.2 + s-0.9-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7C909.3,148.8,909.1,149.5,909.1,150.4z"/> + <path fill="#333333" d="M915.6,150.4c0-1.3,0.4-2.3,1.1-3c0.6-0.5,1.4-0.8,2.3-0.8c1,0,1.8,0.3,2.4,1c0.6,0.7,1,1.6,1,2.7 + c0,0.9-0.1,1.7-0.4,2.2c-0.3,0.5-0.7,1-1.2,1.2c-0.5,0.3-1.1,0.4-1.8,0.4c-1,0-1.8-0.3-2.5-1C915.9,152.6,915.6,151.7,915.6,150.4 + z M916.9,150.4c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.7c0.4-0.5,0.6-1.2,0.6-2.1 + c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1.1,0.2-1.5,0.7C917.1,148.8,916.9,149.5,916.9,150.4z"/> + <path fill="#333333" d="M925.2,154.1l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3h-1.3l-1.2-4.3l-0.3-1.2l-1.5,5.6H925.2z"/> + <path fill="#333333" d="M934,154.1v-7.3h1.1v1c0.5-0.8,1.3-1.2,2.3-1.2c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.4,0.8,0.6 + c0.2,0.3,0.3,0.6,0.4,0.9c0,0.2,0.1,0.6,0.1,1.2v4.5h-1.2v-4.4c0-0.5,0-0.9-0.1-1.1c-0.1-0.2-0.3-0.4-0.5-0.6 + c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-1,0.2-1.4,0.5c-0.4,0.3-0.6,1-0.6,1.9v4H934z"/> </g> <g> - <path fill="#333333" d="M700.7,180.1c0.3,0.1,0.6,0.4,0.9,0.7c0.2,0.3,0.4,0.6,0.4,1c0,0.3,0.1,0.6,0.1,1.1l0,4.7h-2v-4.7 - c0-0.3,0-0.5-0.1-0.7c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.1,0.7c-0.1,0.2-0.2,0.5-0.2,0.9v4.4h-2v-4.4c0-0.4,0-0.8-0.1-1 - c-0.2-0.4-0.5-0.5-1-0.5c-0.6,0-0.9,0.2-1.1,0.5c-0.1,0.2-0.2,0.5-0.2,0.9v4.5h-2v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8 - c0.4-0.3,0.9-0.4,1.5-0.4c0.6,0,1,0.1,1.4,0.4c0.3,0.2,0.5,0.5,0.6,0.9c0.3-0.4,0.6-0.8,1-1c0.4-0.2,0.8-0.3,1.3-0.3 - C700.1,179.9,700.4,180,700.7,180.1z"/> - <path fill="#333333" d="M710.1,186.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C711,184.9,710.7,185.9,710.1,186.6z M708.5,185.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C707.8,186.2,708.2,186,708.5,185.6z"/> - <path fill="#333333" d="M717,180.1h2.1l-2.7,7.5h-2.1l-2.7-7.5h2.2l1.6,5.5L717,180.1z"/> - <path fill="#333333" d="M725.1,180.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9c-0.8-0.6-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3c0.7-0.7,1.6-1,2.7-1 - C723.9,179.9,724.5,180,725.1,180.3z M722.1,181.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C722.8,181.5,722.4,181.7,722.1,181.9z"/> - <path fill="#333333" d="M732.2,183.3c0.3-0.4,0.8-0.9,1.5-1.3l0.2-0.1c-0.3-0.3-0.5-0.7-0.7-1c-0.2-0.3-0.2-0.7-0.2-1.1 - c0-0.7,0.2-1.3,0.7-1.7c0.5-0.4,1.1-0.6,1.9-0.6c0.7,0,1.3,0.2,1.8,0.6c0.5,0.4,0.7,1,0.7,1.6c0,0.6-0.1,1.1-0.4,1.4 - s-0.7,0.7-1.2,1l1.4,1.8c0.2-0.2,0.3-0.5,0.4-0.8c0.1-0.3,0.1-0.6,0.1-0.9h1.7c0,0.6-0.2,1.2-0.4,1.9c-0.1,0.4-0.4,0.7-0.7,1.2 - l1.8,2.2h-2.4l-0.7-0.9c-0.3,0.3-0.7,0.5-1,0.7c-0.5,0.3-1.1,0.4-1.8,0.4c-1,0-1.8-0.3-2.4-0.9c-0.6-0.6-0.9-1.3-0.9-2 - C731.7,184.3,731.9,183.8,732.2,183.3z M734.1,185.8c0.3,0.3,0.6,0.4,1.1,0.4c0.3,0,0.6-0.1,0.9-0.2s0.5-0.3,0.7-0.5l-1.9-2.3 - c-0.5,0.3-0.8,0.6-1,0.9s-0.2,0.5-0.2,0.8C733.7,185.2,733.8,185.5,734.1,185.8z M734.9,180.4c0.1,0.1,0.3,0.4,0.6,0.7 - c0.3-0.2,0.5-0.4,0.6-0.5c0.2-0.2,0.4-0.5,0.4-0.8c0-0.2-0.1-0.4-0.2-0.6c-0.1-0.2-0.4-0.2-0.6-0.2c-0.2,0-0.3,0-0.5,0.1 - c-0.2,0.1-0.4,0.4-0.4,0.7C734.7,180,734.8,180.2,734.9,180.4z"/> - <path fill="#333333" d="M750.3,182.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.3,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1s-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3s1.5-1.1,2.6-1.1 - c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H750.3z"/> - <path fill="#333333" d="M759.9,186.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C760.8,184.9,760.5,185.9,759.9,186.6z M758.3,185.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C757.6,186.2,758,186,758.3,185.6z"/> - <path fill="#333333" d="M768.2,180.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V183c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C767.1,179.9,767.7,180.1,768.2,180.5z"/> - <path fill="#333333" d="M772.3,185.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9H775c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H772.3z" - /> - <path fill="#333333" d="M777.8,181.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H777.8z"/> - <path fill="#333333" d="M787.3,179.9c0,0,0.1,0,0.2,0v2c-0.1,0-0.2,0-0.3,0s-0.2,0-0.2,0c-0.8,0-1.3,0.3-1.6,0.8 - c-0.2,0.3-0.2,0.7-0.2,1.3v3.6h-2v-7.5h1.9v1.3c0.3-0.5,0.6-0.8,0.8-1C786.2,180.1,786.7,179.9,787.3,179.9 - C787.3,179.9,787.3,179.9,787.3,179.9z"/> - <path fill="#333333" d="M791.6,183c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6 - c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7h-1.9c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1 - c0.8,0,1.5,0.2,2.2,0.5c0.6,0.3,1,0.9,1,1.8v3.4c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5c0.1,0.1,0.2,0.2,0.3,0.2v0.3H793 - c-0.1-0.2-0.1-0.3-0.1-0.4c0-0.1,0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6 - c-0.4-0.4-0.7-0.9-0.7-1.6c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L791.6,183z M792.8,183.9c-0.1,0.1-0.3,0.1-0.4,0.2 - c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7 - c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4s0.5-0.7,0.6-1.3V183.9z"/> - <path fill="#333333" d="M798.4,179.2h-2v-1.8h2V179.2z M796.5,180.1h2v7.5h-2V180.1z"/> - <path fill="#333333" d="M806.3,180.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V183c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C805.2,179.9,805.9,180.1,806.3,180.5z"/> - <path fill="#333333" d="M812,181.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4H815v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H812z"/> - <path fill="#333333" d="M823.7,186.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C824.6,184.9,824.3,185.9,823.7,186.6z M822.1,185.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C821.3,186.2,821.8,186,822.1,185.6z"/> - <path fill="#333333" d="M831.6,187.6h-2.4l3.2-5.1l-3.1-4.9h2.5l1.8,3.3l1.8-3.3h2.4l-3.1,4.9l3.3,5.2h-2.6l-1.9-3.4L831.6,187.6z + <path fill="#333333" d="M709.7,196h1.8v1c0.6-0.8,1.4-1.2,2.3-1.2c0.5,0,0.9,0.1,1.2,0.3s0.6,0.5,0.8,0.9c0.3-0.4,0.7-0.7,1-0.9 + s0.8-0.3,1.2-0.3c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.6,0.5,0.8,1c0.1,0.3,0.2,0.8,0.2,1.5v4.6h-1.9v-4.1c0-0.7-0.1-1.2-0.2-1.4 + c-0.2-0.3-0.5-0.4-0.8-0.4c-0.3,0-0.5,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5v3.5h-1.9v-4 + c0-0.7,0-1.2-0.1-1.4s-0.2-0.4-0.3-0.5s-0.3-0.2-0.6-0.2c-0.3,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7s-0.2,0.8-0.2,1.5v3.5 + h-1.9V196z"/> + <path fill="#333333" d="M721.9,199.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C722,201.1,721.9,200.4,721.9,199.5z M723.9,199.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S723.9,198.9,723.9,199.6z"/> + <path fill="#333333" d="M732.9,203.3L730,196h2l1.4,3.7l0.4,1.2c0.1-0.3,0.2-0.5,0.2-0.6c0.1-0.2,0.1-0.4,0.2-0.6l1.4-3.7h2 + l-2.9,7.3H732.9z"/> + <path fill="#333333" d="M742.9,201l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S742.8,201.3,742.9,201z M743,199c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H743z"/> + <path fill="#333333" d="M759.2,202l-1.2,1.5c-0.6-0.3-1.1-0.7-1.6-1.1c-0.4,0.4-0.8,0.6-1.3,0.8c-0.5,0.2-1,0.3-1.6,0.3 + c-1.2,0-2.2-0.4-2.8-1.1c-0.5-0.5-0.7-1.2-0.7-1.9c0-0.6,0.2-1.2,0.6-1.7c0.4-0.5,1-1,1.7-1.3c-0.3-0.4-0.6-0.8-0.8-1.2 + c-0.2-0.4-0.3-0.7-0.3-1c0-0.6,0.2-1.1,0.7-1.5c0.5-0.4,1.2-0.6,2.1-0.6c0.9,0,1.5,0.2,2,0.7c0.5,0.4,0.7,1,0.7,1.6 + c0,0.4-0.1,0.8-0.4,1.2c-0.2,0.4-0.7,0.8-1.5,1.2l1.4,1.8c0.2-0.3,0.3-0.7,0.4-1.1l1.7,0.4c-0.2,0.6-0.3,1.1-0.5,1.4 + c-0.1,0.3-0.3,0.5-0.4,0.7c0.2,0.2,0.5,0.4,0.8,0.7C758.8,201.8,759.1,202,759.2,202z M753.2,198.7c-0.4,0.2-0.8,0.5-1,0.8 + s-0.3,0.6-0.3,1c0,0.4,0.1,0.8,0.4,1c0.3,0.3,0.6,0.4,1.1,0.4c0.3,0,0.6-0.1,0.9-0.2c0.3-0.1,0.6-0.3,0.9-0.6L753.2,198.7z + M754,196.6l0.5-0.4c0.4-0.3,0.6-0.6,0.6-0.9c0-0.2-0.1-0.5-0.3-0.6s-0.4-0.3-0.7-0.3c-0.3,0-0.5,0.1-0.7,0.2 + c-0.2,0.2-0.3,0.3-0.3,0.5c0,0.2,0.1,0.5,0.4,0.9L754,196.6z"/> + <path fill="#333333" d="M770.7,198.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C770.1,196.8,770.5,197.4,770.7,198.2z"/> + <path fill="#333333" d="M771.7,199.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C771.8,201.1,771.7,200.4,771.7,199.5z M773.7,199.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S773.7,198.9,773.7,199.6z"/> + <path fill="#333333" d="M787.3,203.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V196h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V203.3z"/> + <path fill="#333333" d="M788.6,201.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.3,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C789.1,202.4,788.7,201.9,788.6,201.2z"/> + <path fill="#333333" d="M800.4,196v1.5H799v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V196h0.9v-1.4l1.9-1.1v2.6H800.4z"/> + <path fill="#333333" d="M803.5,203.3h-1.9V196h1.8v1c0.3-0.5,0.6-0.8,0.8-1c0.2-0.2,0.5-0.2,0.8-0.2c0.4,0,0.9,0.1,1.3,0.4 + l-0.6,1.7c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.1-0.3,0.4-0.4,0.8c-0.1,0.4-0.2,1.2-0.2,2.4V203.3z"/> + <path fill="#333333" d="M808.6,198.2l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9c0-0.1-0.1-0.3-0.2-0.6 + c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7c-0.4,0.2-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6s-0.6-0.9-0.6-1.5 + c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2c0-0.4-0.1-0.6-0.3-0.8 + c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C808.8,197.7,808.7,197.9,808.6,198.2z M811.1,199.8c-0.2,0.1-0.6,0.2-1.2,0.3 + s-0.9,0.2-1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7c0.2,0.2,0.5,0.3,0.8,0.3c0.3,0,0.7-0.1,1-0.3 + c0.2-0.2,0.4-0.4,0.5-0.6c0.1-0.2,0.1-0.5,0.1-0.9V199.8z"/> + <path fill="#333333" d="M814.9,195v-1.8h1.9v1.8H814.9z M814.9,203.3V196h1.9v7.3H814.9z"/> + <path fill="#333333" d="M825.4,203.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V196h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V203.3z"/> + <path fill="#333333" d="M834.6,196v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V196h0.9v-1.4l1.9-1.1v2.6H834.6z"/> + <path fill="#333333" d="M835.5,199.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C835.6,201.1,835.5,200.4,835.5,199.5z M837.4,199.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S837.4,198.9,837.4,199.6z"/> + <path fill="#333333" d="M847.4,203.3l3.4-5.2l-3.1-4.8h2.4l2,3.2l2-3.2h2.3l-3.1,4.9l3.4,5.2h-2.4l-2.2-3.5l-2.2,3.5H847.4z"/> + <path fill="#333333" d="M856.7,203.4l2.5-10.4h1.4l-2.5,10.4H856.7z"/> + <path fill="#333333" d="M860.7,203.3v-1.8l5.3-6.5h-4.7v-1.7h7.3v1.6l-5.5,6.8h5.7v1.7H860.7z"/> + <path fill="#333333" d="M875.5,198.2l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9c0-0.1-0.1-0.3-0.2-0.6 + c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7c-0.4,0.2-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6s-0.6-0.9-0.6-1.5 + c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2c0-0.4-0.1-0.6-0.3-0.8 + c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C875.7,197.7,875.6,197.9,875.5,198.2z M878,199.8c-0.2,0.1-0.6,0.2-1.2,0.3 + s-0.9,0.2-1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7c0.2,0.2,0.5,0.3,0.8,0.3c0.3,0,0.7-0.1,1-0.3 + c0.2-0.2,0.4-0.4,0.5-0.6c0.1-0.2,0.1-0.5,0.1-0.9V199.8z"/> + <path fill="#333333" d="M880.9,203.3l2.6-3.7L881,196h2.3l1.3,2l1.4-2h2.3l-2.5,3.4l2.7,3.8h-2.4l-1.5-2.2l-1.5,2.2H880.9z"/> + <path fill="#333333" d="M889.6,195v-1.8h1.9v1.8H889.6z M889.6,203.3V196h1.9v7.3H889.6z"/> + <path fill="#333333" d="M892.8,201.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.3,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C893.4,202.4,893,201.9,892.8,201.2z"/> + <path fill="#333333" d="M711.1,220.1l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3h-1.3l-1.2-4.3l-0.3-1.2l-1.5,5.6H711.1z"/> + <path fill="#333333" d="M719.9,211.5V210h1.2v1.4H719.9z M719.9,220.1v-7.3h1.2v7.3H719.9z"/> + <path fill="#333333" d="M725.7,219l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9V211l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C725.3,219,725.5,219,725.7,219z"/> + <path fill="#333333" d="M726.9,220.1v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.6,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H726.9z"/> + <path fill="#333333" d="M738.1,217.9l1.2-0.2c0.1,0.5,0.3,0.9,0.6,1.1c0.3,0.3,0.7,0.4,1.3,0.4c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.4-0.5,0.4-0.8c0-0.3-0.1-0.5-0.4-0.7c-0.2-0.1-0.6-0.2-1.3-0.4c-0.9-0.2-1.5-0.4-1.9-0.6c-0.3-0.2-0.6-0.4-0.8-0.7 + c-0.2-0.3-0.3-0.6-0.3-1c0-0.3,0.1-0.6,0.2-0.9c0.1-0.3,0.3-0.5,0.6-0.7c0.2-0.1,0.5-0.3,0.8-0.4c0.3-0.1,0.7-0.1,1.1-0.1 + c0.6,0,1.1,0.1,1.5,0.2s0.7,0.4,1,0.7c0.2,0.3,0.3,0.7,0.4,1.1l-1.2,0.2c-0.1-0.4-0.2-0.7-0.5-0.9c-0.3-0.2-0.6-0.3-1.1-0.3 + c-0.6,0-1,0.1-1.2,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.2,0.1,0.3,0.2,0.4c0.1,0.1,0.3,0.2,0.5,0.3c0.1,0,0.5,0.2,1.1,0.3 + c0.9,0.2,1.5,0.4,1.8,0.6c0.3,0.1,0.6,0.4,0.8,0.6c0.2,0.3,0.3,0.6,0.3,1.1c0,0.4-0.1,0.8-0.4,1.2c-0.2,0.4-0.6,0.6-1,0.8 + c-0.5,0.2-1,0.3-1.5,0.3c-0.9,0-1.7-0.2-2.2-0.6C738.6,219.3,738.2,218.7,738.1,217.9z"/> + <path fill="#333333" d="M745.6,220.1v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6h-1.2v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.6,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H745.6z"/> + <path fill="#333333" d="M753.4,211.5V210h1.2v1.4H753.4z M753.4,220.1v-7.3h1.2v7.3H753.4z"/> + <path fill="#333333" d="M756.8,220.1v-6.3h-1.1v-1h1.1V212c0-0.5,0-0.8,0.1-1.1c0.1-0.3,0.3-0.6,0.6-0.8c0.3-0.2,0.7-0.3,1.3-0.3 + c0.3,0,0.7,0,1.1,0.1l-0.2,1.1c-0.3,0-0.5-0.1-0.7-0.1c-0.4,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.2,0.5-0.2,0.9v0.7h1.4v1H758v6.3H756.8z "/> - <path fill="#333333" d="M841.4,177.2h1.6l-3.9,10.4h-1.6L841.4,177.2z"/> - <path fill="#333333" d="M842.6,185.8l5.2-6.5h-5v-1.8h7.6v1.7l-5.2,6.6h5.2v1.8h-7.8V185.8z"/> - <path fill="#333333" d="M858.5,183c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6 - c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7h-1.9c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1 - c0.8,0,1.5,0.2,2.2,0.5c0.6,0.3,1,0.9,1,1.8v3.4c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5c0.1,0.1,0.2,0.2,0.3,0.2v0.3h-2.1 - c-0.1-0.2-0.1-0.3-0.1-0.4c0-0.1,0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6 - c-0.4-0.4-0.7-0.9-0.7-1.6c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L858.5,183z M859.7,183.9c-0.1,0.1-0.3,0.1-0.4,0.2 - c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7 - c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4s0.5-0.7,0.6-1.3V183.9z"/> - <path fill="#333333" d="M862.6,187.6l2.5-3.8l-2.4-3.7h2.4l1.2,2.2l1.2-2.2h2.3l-2.4,3.6l2.5,3.8h-2.4l-1.3-2.2l-1.3,2.2H862.6z" - /> - <path fill="#333333" d="M873.1,179.2h-2v-1.8h2V179.2z M871.1,180.1h2v7.5h-2V180.1z"/> - <path fill="#333333" d="M876.5,185.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2c-0.2,0.1-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H876.5z" - /> - <path fill="#333333" d="M692,197l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3H697l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3H692z"/> - <path fill="#333333" d="M701.5,194.3h1.3v1.4h-1.3V194.3z M701.5,197.1h1.3v7.3h-1.3V197.1z"/> - <path fill="#333333" d="M704.9,195h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1V198h-1v-1h1V195z"/> - <path fill="#333333" d="M708.5,194.3h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V194.3z"/> - <path fill="#333333" d="M720.9,202.1c0,0.4,0.1,0.7,0.3,0.9c0.3,0.4,0.9,0.6,1.6,0.6c0.5,0,0.9-0.1,1.2-0.3 - c0.4-0.2,0.5-0.5,0.5-0.9c0-0.3-0.1-0.6-0.4-0.7c-0.2-0.1-0.5-0.2-1.1-0.3l-1-0.2c-0.6-0.2-1.1-0.3-1.4-0.5 - c-0.5-0.3-0.8-0.8-0.8-1.4c0-0.7,0.3-1.3,0.8-1.7s1.2-0.6,2-0.6c1.1,0,1.9,0.3,2.4,1c0.3,0.4,0.5,0.9,0.5,1.3h-1.2 - c0-0.3-0.1-0.5-0.3-0.8c-0.3-0.3-0.8-0.5-1.5-0.5c-0.5,0-0.8,0.1-1.1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.2,0.6,0.5,0.8 - c0.2,0.1,0.5,0.2,0.8,0.3l0.8,0.2c0.9,0.2,1.5,0.4,1.8,0.6c0.5,0.3,0.7,0.8,0.7,1.5c0,0.7-0.2,1.2-0.8,1.7 - c-0.5,0.5-1.3,0.7-2.3,0.7c-1.1,0-1.9-0.2-2.3-0.7c-0.5-0.5-0.7-1.1-0.7-1.8H720.9z"/> - <path fill="#333333" d="M727.2,194.3h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V194.3z"/> - <path fill="#333333" d="M735,194.3h1.3v1.4H735V194.3z M735,197.1h1.3v7.3H735V197.1z"/> - <path fill="#333333" d="M738.7,194.8c0.3-0.4,0.8-0.6,1.7-0.6c0.1,0,0.2,0,0.2,0s0.2,0,0.3,0v1.1c-0.1,0-0.2,0-0.3,0 - c-0.1,0-0.1,0-0.2,0c-0.4,0-0.6,0.1-0.7,0.3c-0.1,0.2-0.1,0.7-0.1,1.5h1.2v1h-1.2v6.3h-1.2V198h-1v-1h1v-1.1 - C738.4,195.4,738.5,195,738.7,194.8z"/> - <path fill="#333333" d="M742.2,195h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1V198h-1v-1h1V195z"/> - <path fill="#333333" d="M749.5,201.4v-1.1h3v-3h1.2v3h3v1.1h-3v3h-1.2v-3H749.5z"/> - <path fill="#333333" d="M761.9,194.3h1.2v10h-1.2V194.3z"/> - <path fill="#333333" d="M769.5,197.2c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8s0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9s1.5-1.1,2.5-1.1C768.5,196.9,769,197,769.5,197.2z M769.9,200.1c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H769.9z"/> - <path fill="#333333" d="M773.3,194.8c0.3-0.4,0.8-0.6,1.7-0.6c0.1,0,0.2,0,0.2,0s0.2,0,0.3,0v1.1c-0.1,0-0.2,0-0.3,0 - c-0.1,0-0.1,0-0.2,0c-0.4,0-0.6,0.1-0.7,0.3c-0.1,0.2-0.1,0.7-0.1,1.5h1.2v1h-1.2v6.3H773V198h-1v-1h1v-1.1 - C773,195.4,773.1,195,773.3,194.8z"/> - <path fill="#333333" d="M776.9,195h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1V198h-1v-1h1V195z"/> - <path fill="#333333" d="M789.2,197.4c0.5,0.4,0.8,1.1,0.9,2.1H789c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C788,196.8,788.7,197,789.2,197.4z"/> - <path fill="#333333" d="M791.4,194.3h1.2v10h-1.2V194.3z"/> - <path fill="#333333" d="M794.5,194.3h1.3v1.4h-1.3V194.3z M794.5,197.1h1.3v7.3h-1.3V197.1z"/> - <path fill="#333333" d="M802.4,197.4c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C801.3,196.8,801.9,197,802.4,197.4z"/> - <path fill="#333333" d="M804.6,194.3h1.2v5.8l3.2-3.1h1.6l-2.8,2.7l3,4.6h-1.6l-2.3-3.7l-1,1v2.7h-1.2V194.3z"/> - <path fill="#333333" d="M815.2,201.4v-1.1h3v-3h1.2v3h3v1.1h-3v3h-1.2v-3H815.2z"/> - <path fill="#333333" d="M831.6,197.3c0.2,0.1,0.5,0.4,0.7,0.7v-3.7h1.2v10.1h-1.1v-1c-0.3,0.5-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.8,0-1.5-0.3-2.1-1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.1,0.3-2,0.8-2.8c0.5-0.8,1.3-1.2,2.3-1.2C830.7,196.9,831.2,197,831.6,197.3z - M828.8,202.8c0.3,0.5,0.9,0.8,1.6,0.8c0.6,0,1-0.2,1.4-0.7c0.4-0.5,0.5-1.2,0.5-2.1c0-0.9-0.2-1.6-0.6-2.1 - c-0.4-0.4-0.8-0.7-1.4-0.7c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.5-0.6,1.2-0.6,2.1C828.3,201.6,828.5,202.2,828.8,202.8z"/> - <path fill="#333333" d="M835.4,197h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0v1.3 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V197z"/> - <path fill="#333333" d="M843.9,199.9c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9H840c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.2,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L843.9,199.9z M841.3,203.3c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C841,202.8,841.1,203,841.3,203.3z"/> - <path fill="#333333" d="M851.9,197.3c0.2,0.2,0.5,0.4,0.7,0.7v-0.9h1.1v6.7c0,0.9-0.1,1.7-0.4,2.2c-0.5,1-1.5,1.5-2.9,1.5 - c-0.8,0-1.4-0.2-2-0.5c-0.5-0.4-0.8-0.9-0.9-1.7h1.3c0.1,0.3,0.2,0.6,0.4,0.8c0.3,0.3,0.7,0.4,1.3,0.4c0.9,0,1.6-0.3,1.8-1 - c0.2-0.4,0.3-1.1,0.2-2.1c-0.2,0.4-0.5,0.7-0.9,0.8s-0.8,0.3-1.4,0.3c-0.8,0-1.5-0.3-2.1-0.8c-0.6-0.6-0.9-1.5-0.9-2.8 - c0-1.2,0.3-2.2,0.9-2.9s1.3-1,2.2-1C850.9,196.9,851.4,197.1,851.9,197.3z M852,198.7c-0.4-0.4-0.8-0.7-1.4-0.7 - c-0.9,0-1.5,0.4-1.8,1.2c-0.2,0.4-0.3,1-0.3,1.7c0,0.8,0.2,1.5,0.5,1.9c0.3,0.4,0.8,0.6,1.3,0.6c0.9,0,1.5-0.4,1.9-1.2 - c0.2-0.5,0.3-1,0.3-1.6C852.6,199.8,852.4,199.1,852,198.7z"/> - </g> - <g> - <path fill="#333333" d="M641.4,253.2c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1C640.6,252.9,641,253,641.4,253.2z - M641.8,258.5c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6 - c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6C641.1,259.2,641.6,258.9,641.8,258.5z"/> - <path fill="#333333" d="M647.9,253.1v4.5c0,0.4,0,0.7,0.1,1c0.2,0.4,0.5,0.6,1,0.6c0.7,0,1.1-0.3,1.4-0.8c0.1-0.3,0.2-0.7,0.2-1.2 - v-4.1h2v7.5h-1.9v-1.1c0,0-0.1,0.1-0.1,0.2c-0.1,0.1-0.2,0.2-0.3,0.3c-0.3,0.3-0.6,0.5-0.9,0.6s-0.6,0.2-1,0.2 - c-1.1,0-1.8-0.4-2.2-1.2c-0.2-0.4-0.3-1.1-0.3-1.9v-4.5H647.9z"/> - <path fill="#333333" d="M660.8,253.9c0.6,0.6,0.9,1.6,0.9,2.8c0,1.3-0.3,2.3-0.9,3c-0.6,0.7-1.4,1-2.3,1c-0.6,0-1.1-0.1-1.5-0.4 - c-0.2-0.2-0.4-0.4-0.6-0.7v3.9h-1.9v-10.4h1.9v1.1c0.2-0.3,0.4-0.6,0.7-0.8c0.4-0.3,1-0.5,1.6-0.5 - C659.4,252.9,660.2,253.3,660.8,253.9z M659.3,255.3c-0.3-0.4-0.7-0.7-1.3-0.7c-0.7,0-1.2,0.3-1.5,1c-0.1,0.4-0.2,0.8-0.2,1.4 - c0,0.9,0.2,1.5,0.7,1.8c0.3,0.2,0.6,0.3,1,0.3c0.5,0,1-0.2,1.3-0.6c0.3-0.4,0.4-1,0.4-1.7C659.7,256.3,659.5,255.8,659.3,255.3z" - /> - <path fill="#333333" d="M665.1,260.6h-1.9v-10.1h1.9V260.6z"/> - <path fill="#333333" d="M669,252.2h-2v-1.8h2V252.2z M667,253.1h2v7.5h-2V253.1z"/> - <path fill="#333333" d="M675.3,255.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.4,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1c-0.6-0.7-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3 - s1.5-1.1,2.6-1.1c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H675.3z"/> - <path fill="#333333" d="M681.6,256c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6 - c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7h-1.9c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1 - c0.8,0,1.5,0.2,2.2,0.5c0.6,0.3,1,0.9,1,1.8v3.4c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5c0.1,0.1,0.2,0.2,0.3,0.2v0.3H683 - c-0.1-0.2-0.1-0.3-0.1-0.4c0-0.1,0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6 - c-0.4-0.4-0.7-0.9-0.7-1.6c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L681.6,256z M682.8,256.9c-0.1,0.1-0.3,0.1-0.4,0.2 - c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7 - c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4c0.4-0.2,0.5-0.7,0.6-1.3V256.9z"/> - <path fill="#333333" d="M685.7,254.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H685.7z"/> - <path fill="#333333" d="M695.9,253.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C694.8,252.9,695.4,253,695.9,253.3 - z M693,254.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C693.7,254.5,693.3,254.7,693,254.9z" - /> - <path fill="#333333" d="M703.1,256.3c0.3-0.4,0.8-0.9,1.5-1.3l0.2-0.1c-0.3-0.3-0.5-0.7-0.7-1c-0.2-0.3-0.2-0.7-0.2-1.1 - c0-0.7,0.2-1.3,0.7-1.7c0.5-0.4,1.1-0.6,1.9-0.6c0.7,0,1.3,0.2,1.8,0.6c0.5,0.4,0.7,1,0.7,1.6c0,0.6-0.1,1.1-0.4,1.4 - c-0.3,0.4-0.7,0.7-1.2,1l1.4,1.8c0.2-0.2,0.3-0.5,0.4-0.8c0.1-0.3,0.1-0.6,0.1-0.9h1.7c0,0.6-0.2,1.2-0.4,1.9 - c-0.1,0.4-0.4,0.7-0.7,1.2l1.8,2.2h-2.4l-0.7-0.9c-0.3,0.3-0.7,0.5-1,0.7c-0.5,0.3-1.1,0.4-1.8,0.4c-1,0-1.8-0.3-2.4-0.9 - c-0.6-0.6-0.9-1.3-0.9-2C702.6,257.3,702.8,256.8,703.1,256.3z M705,258.8c0.3,0.3,0.6,0.4,1.1,0.4c0.3,0,0.6-0.1,0.9-0.2 - c0.3-0.1,0.5-0.3,0.7-0.5l-1.9-2.3c-0.5,0.3-0.8,0.6-1,0.9s-0.2,0.5-0.2,0.8C704.5,258.2,704.7,258.5,705,258.8z M705.8,253.4 - c0.1,0.1,0.3,0.4,0.6,0.7c0.3-0.2,0.5-0.4,0.6-0.5c0.2-0.2,0.4-0.5,0.4-0.8c0-0.2-0.1-0.4-0.2-0.6c-0.1-0.2-0.4-0.2-0.6-0.2 - c-0.2,0-0.3,0-0.5,0.1c-0.2,0.1-0.4,0.4-0.4,0.7C705.6,253,705.7,253.2,705.8,253.4z"/> - <path fill="#333333" d="M726.1,253.1c0.3,0.1,0.6,0.4,0.9,0.7c0.2,0.3,0.4,0.6,0.4,1c0,0.3,0.1,0.6,0.1,1.1l0,4.7h-2v-4.7 - c0-0.3,0-0.5-0.1-0.7c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.1,0.7c-0.1,0.2-0.2,0.5-0.2,0.9v4.4h-2v-4.4c0-0.4,0-0.8-0.1-1 - c-0.2-0.4-0.5-0.5-1-0.5c-0.6,0-0.9,0.2-1.1,0.5c-0.1,0.2-0.2,0.5-0.2,0.9v4.5h-2v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8 - c0.4-0.3,0.9-0.4,1.5-0.4c0.6,0,1,0.1,1.4,0.4c0.3,0.2,0.5,0.5,0.6,0.9c0.3-0.4,0.6-0.8,1-1c0.4-0.2,0.8-0.3,1.3-0.3 - C725.4,252.9,725.7,253,726.1,253.1z"/> - <path fill="#333333" d="M735.4,259.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C736.4,257.9,736,258.9,735.4,259.6z M733.9,258.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C733.1,259.2,733.6,259,733.9,258.6z"/> - <path fill="#333333" d="M742.3,253.1h2.1l-2.7,7.5h-2.1l-2.7-7.5h2.2l1.6,5.5L742.3,253.1z"/> - <path fill="#333333" d="M750.4,253.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C749.3,252.9,749.9,253,750.4,253.3 - z M747.5,254.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C748.1,254.5,747.8,254.7,747.5,254.9z"/> - <path fill="#333333" d="M758.7,258.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H758.7z" - /> - <path fill="#333333" d="M769.9,253.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C768.8,252.9,769.3,253,769.9,253.3 - z M766.9,254.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C767.6,254.5,767.2,254.7,766.9,254.9z"/> - <path fill="#333333" d="M774.8,260.6h-1.9v-10.1h1.9V260.6z"/> - <path fill="#333333" d="M781.5,253.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C780.4,252.9,781,253,781.5,253.3z - M778.6,254.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C779.3,254.5,778.9,254.7,778.6,254.9 + <path fill="#333333" d="M763.1,219l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9V211l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C762.7,219,762.8,219,763.1,219z"/> + <path fill="#333333" d="M770.7,218.4v-2.7H768v-1.1h2.7v-2.7h1.2v2.7h2.7v1.1h-2.7v2.7H770.7z"/> + <path fill="#333333" d="M780.2,220.1v-10h1.2v10H780.2z"/> + <path fill="#333333" d="M788.3,217.7l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3h-5.4 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C787.9,218.6,788.1,218.3,788.3,217.7z M784.3,215.7h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C784.5,214.6,784.3,215.1,784.3,215.7z"/> + <path fill="#333333" d="M791.4,220.1v-6.3h-1.1v-1h1.1V212c0-0.5,0-0.8,0.1-1.1c0.1-0.3,0.3-0.6,0.6-0.8c0.3-0.2,0.7-0.3,1.3-0.3 + c0.3,0,0.7,0,1.1,0.1l-0.2,1.1c-0.3,0-0.5-0.1-0.7-0.1c-0.4,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.2,0.5-0.2,0.9v0.7h1.4v1h-1.4v6.3H791.4 z"/> - <path fill="#333333" d="M788.9,255.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.4,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1c-0.6-0.7-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3 - s1.5-1.1,2.6-1.1c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H788.9z"/> - <path fill="#333333" d="M791.5,254.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H791.5z"/> - <path fill="#333333" d="M798.9,252.2h-2v-1.8h2V252.2z M796.9,253.1h2v7.5h-2V253.1z"/> - <path fill="#333333" d="M807,259.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C808,257.9,807.6,258.9,807,259.6z M805.5,258.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C804.7,259.2,805.2,259,805.5,258.6z"/> - <path fill="#333333" d="M815.4,253.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V256c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C814.2,252.9,814.9,253.1,815.4,253.5z"/> - <path fill="#333333" d="M822.4,253.2l1.4,5.8l1.4-5.8h1.4l1.4,5.7l1.5-5.7h1.2l-2.1,7.3h-1.3l-1.5-5.7l-1.4,5.7h-1.3l-2.1-7.3 - H822.4z"/> - <path fill="#333333" d="M831.9,250.5h1.3v1.4h-1.3V250.5z M831.9,253.3h1.3v7.3h-1.3V253.3z"/> - <path fill="#333333" d="M835.3,251.2h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V251.2z"/> - <path fill="#333333" d="M838.9,250.5h1.2v3.7c0.3-0.4,0.6-0.6,0.8-0.8c0.4-0.3,0.9-0.4,1.5-0.4c1.1,0,1.8,0.4,2.2,1.1 - c0.2,0.4,0.3,1,0.3,1.7v4.7h-1.3v-4.6c0-0.5-0.1-0.9-0.2-1.2c-0.2-0.4-0.6-0.6-1.3-0.6c-0.5,0-1,0.2-1.4,0.5c-0.4,0.4-0.6,1-0.6,2 - v3.9h-1.2V250.5z"/> - <path fill="#333333" d="M854.5,256.1c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.3,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L854.5,256.1z M851.9,259.5c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C851.5,259,851.6,259.2,851.9,259.5z"/> - <path fill="#333333" d="M858.4,250.5h1.2v10h-1.2V250.5z"/> - <path fill="#333333" d="M861.7,251.2h1.2v2h1.2v1H863v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V251.2z"/> - <path fill="#333333" d="M869,257.6v-1.1h3v-3h1.2v3h3v1.1h-3v3H872v-3H869z"/> - <path fill="#333333" d="M881.3,250.5h1.2v10h-1.2V250.5z"/> - <path fill="#333333" d="M888.9,253.4c0.5,0.2,0.9,0.6,1.1,0.9c0.2,0.4,0.4,0.8,0.5,1.3c0.1,0.3,0.1,0.9,0.1,1.6h-5.3 - c0,0.7,0.2,1.3,0.5,1.8c0.3,0.5,0.8,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.6c0.2-0.2,0.4-0.5,0.5-0.9h1.2c0,0.3-0.1,0.6-0.3,0.9 - c-0.2,0.3-0.4,0.6-0.6,0.8c-0.4,0.4-0.8,0.6-1.4,0.7c-0.3,0.1-0.6,0.1-1,0.1c-0.9,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.8 - c0-1.2,0.3-2.1,1-2.9c0.6-0.7,1.5-1.1,2.5-1.1C888,253.1,888.5,253.2,888.9,253.4z M889.4,256.3c0-0.5-0.2-1-0.3-1.3 - c-0.3-0.6-0.9-0.9-1.7-0.9c-0.6,0-1,0.2-1.4,0.6c-0.4,0.4-0.6,0.9-0.6,1.6H889.4z"/> - <path fill="#333333" d="M892.8,251c0.3-0.4,0.8-0.6,1.7-0.6c0.1,0,0.2,0,0.2,0s0.2,0,0.3,0v1.1c-0.1,0-0.2,0-0.3,0 - c-0.1,0-0.1,0-0.2,0c-0.4,0-0.6,0.1-0.7,0.3c-0.1,0.2-0.1,0.7-0.1,1.5h1.2v1h-1.2v6.3h-1.2v-6.3h-1v-1h1v-1.1 - C892.5,251.6,892.6,251.2,892.8,251z"/> - <path fill="#333333" d="M896.3,251.2h1.2v2h1.2v1h-1.2v4.8c0,0.3,0.1,0.4,0.3,0.5c0.1,0,0.3,0.1,0.5,0.1c0.1,0,0.1,0,0.2,0 - s0.1,0,0.2,0v1c-0.1,0-0.3,0.1-0.4,0.1c-0.2,0-0.3,0-0.5,0c-0.6,0-1-0.1-1.2-0.4c-0.2-0.3-0.3-0.7-0.3-1.1v-4.8h-1v-1h1V251.2z"/> - <path fill="#333333" d="M908.7,253.6c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C907.5,253,908.2,253.2,908.7,253.6z"/> - <path fill="#333333" d="M910.9,250.5h1.2v10h-1.2V250.5z"/> - <path fill="#333333" d="M914,250.5h1.3v1.4H914V250.5z M914,253.3h1.3v7.3H914V253.3z"/> - <path fill="#333333" d="M921.9,253.6c0.5,0.4,0.8,1.1,0.9,2.1h-1.2c-0.1-0.5-0.2-0.8-0.5-1.1c-0.3-0.3-0.7-0.4-1.3-0.4 - c-0.8,0-1.3,0.4-1.7,1.1c-0.2,0.5-0.3,1.1-0.3,1.8c0,0.7,0.2,1.3,0.5,1.9c0.3,0.5,0.8,0.8,1.5,0.8c0.5,0,0.9-0.2,1.2-0.5 - c0.3-0.3,0.5-0.7,0.6-1.3h1.2c-0.1,1-0.5,1.7-1,2.1c-0.5,0.4-1.2,0.7-2.1,0.7c-1,0-1.7-0.3-2.3-1c-0.6-0.7-0.9-1.6-0.9-2.6 - c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.4-1.1C920.7,253,921.4,253.2,921.9,253.6z"/> - <path fill="#333333" d="M924.1,250.5h1.2v5.8l3.2-3.1h1.6l-2.8,2.7l3,4.6h-1.6l-2.3-3.7l-1,1v2.7h-1.2V250.5z"/> - <path fill="#333333" d="M934.7,257.6v-1.1h3v-3h1.2v3h3v1.1h-3v3h-1.2v-3H934.7z"/> - <path fill="#333333" d="M951.1,253.5c0.2,0.1,0.5,0.4,0.7,0.7v-3.7h1.2v10.1h-1.1v-1c-0.3,0.5-0.6,0.8-1,1 - c-0.4,0.2-0.8,0.3-1.3,0.3c-0.8,0-1.5-0.3-2.1-1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.1,0.3-2,0.8-2.8c0.5-0.8,1.3-1.2,2.3-1.2 - C950.2,253.1,950.7,253.2,951.1,253.5z M948.3,259c0.3,0.5,0.9,0.8,1.6,0.8c0.6,0,1-0.2,1.4-0.7c0.4-0.5,0.5-1.2,0.5-2.1 - c0-0.9-0.2-1.6-0.6-2.1c-0.4-0.4-0.8-0.7-1.4-0.7c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.5-0.6,1.2-0.6,2.1 - C947.8,257.8,948,258.4,948.3,259z"/> - <path fill="#333333" d="M954.9,253.2h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0v1.3 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V253.2z"/> - <path fill="#333333" d="M963.4,256.1c0.3,0,0.5-0.2,0.6-0.4c0.1-0.1,0.1-0.3,0.1-0.5c0-0.4-0.1-0.7-0.4-0.9 - c-0.3-0.2-0.7-0.3-1.3-0.3c-0.6,0-1.1,0.2-1.4,0.5c-0.2,0.2-0.2,0.5-0.3,0.9h-1.1c0-0.9,0.3-1.5,0.9-1.9c0.6-0.4,1.2-0.5,2-0.5 - c0.9,0,1.6,0.2,2.1,0.5c0.5,0.3,0.8,0.8,0.8,1.5v4.2c0,0.1,0,0.2,0.1,0.3c0.1,0.1,0.2,0.1,0.3,0.1c0.1,0,0.1,0,0.2,0 - c0.1,0,0.1,0,0.2,0v0.9c-0.2,0.1-0.3,0.1-0.4,0.1c-0.1,0-0.2,0-0.4,0c-0.4,0-0.7-0.2-0.9-0.5c-0.1-0.2-0.2-0.4-0.2-0.7 - c-0.3,0.3-0.6,0.6-1.1,0.9c-0.5,0.2-1,0.4-1.6,0.4c-0.7,0-1.2-0.2-1.7-0.6c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.7,0.2-1.2,0.6-1.6 - s1-0.6,1.7-0.7L963.4,256.1z M960.8,259.5c0.3,0.2,0.6,0.3,0.9,0.3c0.4,0,0.9-0.1,1.3-0.3c0.7-0.3,1-0.9,1-1.6v-1 - c-0.2,0.1-0.3,0.2-0.6,0.2c-0.2,0.1-0.5,0.1-0.7,0.1l-0.7,0.1c-0.4,0.1-0.8,0.2-1,0.3c-0.4,0.2-0.6,0.6-0.6,1 - C960.4,259,960.6,259.2,960.8,259.5z"/> - <path fill="#333333" d="M971.4,253.5c0.2,0.2,0.5,0.4,0.7,0.7v-0.9h1.1v6.7c0,0.9-0.1,1.7-0.4,2.2c-0.5,1-1.5,1.5-2.9,1.5 - c-0.8,0-1.4-0.2-2-0.5c-0.5-0.4-0.8-0.9-0.9-1.7h1.3c0.1,0.3,0.2,0.6,0.4,0.8c0.3,0.3,0.7,0.4,1.3,0.4c0.9,0,1.6-0.3,1.8-1 - c0.2-0.4,0.3-1.1,0.2-2.1c-0.2,0.4-0.5,0.7-0.9,0.8c-0.3,0.2-0.8,0.3-1.4,0.3c-0.8,0-1.5-0.3-2.1-0.8c-0.6-0.6-0.9-1.5-0.9-2.8 - c0-1.2,0.3-2.2,0.9-2.9c0.6-0.7,1.3-1,2.2-1C970.4,253.1,970.9,253.3,971.4,253.5z M971.5,254.9c-0.4-0.4-0.8-0.7-1.4-0.7 - c-0.9,0-1.5,0.4-1.8,1.2c-0.2,0.4-0.3,1-0.3,1.7c0,0.8,0.2,1.5,0.5,1.9c0.3,0.4,0.8,0.6,1.3,0.6c0.9,0,1.5-0.4,1.9-1.2 - c0.2-0.5,0.3-1,0.3-1.6C972.1,256,971.9,255.3,971.5,254.9z"/> + <path fill="#333333" d="M797.7,219l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5v-4.2h-0.9v-1h0.9V211l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C797.3,219,797.5,219,797.7,219z"/> + <path fill="#333333" d="M807.5,217.4l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C807.2,218.5,807.4,218,807.5,217.4z"/> + <path fill="#333333" d="M809.8,220.1v-10h1.2v10H809.8z"/> + <path fill="#333333" d="M812.9,211.5V210h1.2v1.4H812.9z M812.9,220.1v-7.3h1.2v7.3H812.9z"/> + <path fill="#333333" d="M820.7,217.4l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C820.5,218.5,820.7,218,820.7,217.4z"/> + <path fill="#333333" d="M823,220.1v-10h1.2v5.7l2.9-3h1.6l-2.8,2.7l3.1,4.6h-1.5l-2.4-3.7l-0.9,0.8v2.9H823z"/> + <path fill="#333333" d="M836.5,218.4v-2.7h-2.7v-1.1h2.7v-2.7h1.2v2.7h2.7v1.1h-2.7v2.7H836.5z"/> + <path fill="#333333" d="M850.7,220.1v-0.9c-0.5,0.7-1.1,1.1-2,1.1c-0.6,0-1.1-0.2-1.6-0.5s-0.9-0.8-1.1-1.3 + c-0.3-0.6-0.4-1.2-0.4-2c0-0.7,0.1-1.4,0.4-2c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.6-0.5c0.4,0,0.8,0.1,1.2,0.3 + c0.3,0.2,0.6,0.4,0.8,0.7V210h1.2v10H850.7z M846.8,216.4c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.4,0.7c0.5,0,1-0.2,1.4-0.7 + c0.4-0.4,0.6-1.1,0.6-2c0-1-0.2-1.7-0.6-2.2s-0.9-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7C847,214.8,846.8,215.5,846.8,216.4z"/> + <path fill="#333333" d="M853.7,220.1v-7.3h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H853.7z"/> + <path fill="#333333" d="M863.1,219.2c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.3-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C863.3,219.8,863.2,219.5,863.1,219.2z M863,216.4c-0.4,0.2-1.1,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.1,0.2 + c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.3-0.3 + c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V216.4z"/> + <path fill="#333333" d="M866,220.7l1.2,0.2c0.1,0.4,0.2,0.6,0.4,0.8c0.3,0.2,0.7,0.3,1.3,0.3c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.5-0.5,0.6-1c0.1-0.3,0.1-0.8,0.1-1.6c-0.5,0.6-1.2,1-2,1c-1,0-1.8-0.4-2.3-1.1s-0.8-1.6-0.8-2.6c0-0.7,0.1-1.3,0.4-1.9 + c0.3-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.7-0.5c0.9,0,1.6,0.3,2.1,1v-0.9h1.1v6.3c0,1.1-0.1,1.9-0.3,2.4c-0.2,0.5-0.6,0.8-1.1,1.1 + s-1.1,0.4-1.8,0.4c-0.9,0-1.6-0.2-2.1-0.6C866.2,222,866,221.5,866,220.7z M867,216.3c0,1,0.2,1.6,0.6,2.1 + c0.4,0.4,0.9,0.7,1.4,0.7c0.6,0,1-0.2,1.4-0.7c0.4-0.4,0.6-1.1,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.4-0.7 + c-0.5,0-1,0.2-1.4,0.7C867.2,214.8,867,215.4,867,216.3z"/> </g> <g> - <path fill="#333333" d="M634.4,312.1v4.5c0,0.4,0,0.7,0.1,1c0.2,0.4,0.5,0.6,1,0.6c0.7,0,1.1-0.3,1.4-0.8c0.1-0.3,0.2-0.7,0.2-1.2 - v-4.1h2v7.5h-1.9v-1.1c0,0-0.1,0.1-0.1,0.2c-0.1,0.1-0.2,0.2-0.3,0.3c-0.3,0.3-0.6,0.5-0.9,0.6s-0.6,0.2-1,0.2 - c-1.1,0-1.8-0.4-2.2-1.2c-0.2-0.4-0.3-1.1-0.3-1.9v-4.5H634.4z"/> - <path fill="#333333" d="M647,312.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V315c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4H641v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C645.9,311.9,646.5,312.1,647,312.5z"/> - <path fill="#333333" d="M653.5,312.2c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1 - C652.7,311.9,653.1,312,653.5,312.2z M653.9,317.5c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4 - c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6 - C653.2,318.2,653.7,317.9,653.9,317.5z"/> - <path fill="#333333" d="M664.3,318.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C665.2,316.9,664.9,317.9,664.3,318.6z M662.7,317.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C662,318.2,662.4,318,662.7,317.6z"/> - </g> - <g> - <path fill="#333333" d="M732.5,377.9c0,0,0.1,0,0.2,0v2c-0.1,0-0.2,0-0.3,0s-0.2,0-0.2,0c-0.8,0-1.3,0.3-1.6,0.8 - c-0.2,0.3-0.2,0.7-0.2,1.3v3.6h-2v-7.5h1.9v1.3c0.3-0.5,0.6-0.8,0.8-1C731.4,378.1,731.9,377.9,732.5,377.9 - C732.5,377.9,732.5,377.9,732.5,377.9z"/> - <path fill="#333333" d="M738.7,378.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C737.6,377.9,738.2,378,738.7,378.3 - z M735.8,379.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C736.5,379.5,736.1,379.7,735.8,379.9z"/> - <path fill="#333333" d="M745.6,378.2c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1 - C744.8,377.9,745.2,378,745.6,378.2z M746.1,383.5c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4 - c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6 - C745.4,384.2,745.8,383.9,746.1,383.5z"/> - <path fill="#333333" d="M756.4,384.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C757.4,382.9,757,383.9,756.4,384.6z M754.9,383.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C754.1,384.2,754.5,384,754.9,383.6z"/> - </g> - <g> - <path fill="#333333" d="M576.6,444.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C577.6,442.9,577.3,443.9,576.6,444.6z M575.1,443.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C574.3,444.2,574.8,444,575.1,443.6z"/> - <path fill="#333333" d="M585.2,438.9c0.6,0.6,0.9,1.6,0.9,2.8c0,1.3-0.3,2.3-0.9,3c-0.6,0.7-1.4,1-2.3,1c-0.6,0-1.1-0.1-1.5-0.4 - c-0.2-0.2-0.4-0.4-0.6-0.7v3.9h-1.9v-10.4h1.9v1.1c0.2-0.3,0.4-0.6,0.7-0.8c0.4-0.3,1-0.5,1.6-0.5 - C583.9,437.9,584.6,438.3,585.2,438.9z M583.7,440.3c-0.3-0.4-0.7-0.7-1.3-0.7c-0.7,0-1.2,0.3-1.5,1c-0.1,0.4-0.2,0.8-0.2,1.4 - c0,0.9,0.2,1.5,0.7,1.8c0.3,0.2,0.6,0.3,1,0.3c0.5,0,1-0.2,1.3-0.6c0.3-0.4,0.4-1,0.4-1.7C584.1,441.3,584,440.8,583.7,440.3z"/> - <path fill="#333333" d="M592.4,438.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C591.3,437.9,591.8,438,592.4,438.3 - z M589.5,439.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C590.1,439.5,589.7,439.7,589.5,439.9z"/> - <path fill="#333333" d="M601.3,438.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V441c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C600.2,437.9,600.8,438.1,601.3,438.5z"/> - <path fill="#333333" d="M614,438.9c0.6,0.6,0.9,1.6,0.9,2.8c0,1.3-0.3,2.3-0.9,3c-0.6,0.7-1.4,1-2.3,1c-0.6,0-1.1-0.1-1.5-0.4 - c-0.2-0.2-0.4-0.4-0.6-0.7v3.9h-1.9v-10.4h1.9v1.1c0.2-0.3,0.4-0.6,0.7-0.8c0.4-0.3,1-0.5,1.6-0.5 - C612.7,437.9,613.4,438.3,614,438.9z M612.5,440.3c-0.3-0.4-0.7-0.7-1.3-0.7c-0.7,0-1.2,0.3-1.5,1c-0.1,0.4-0.2,0.8-0.2,1.4 - c0,0.9,0.2,1.5,0.7,1.8c0.3,0.2,0.6,0.3,1,0.3c0.5,0,1-0.2,1.3-0.6c0.3-0.4,0.4-1,0.4-1.7C612.9,441.3,612.8,440.8,612.5,440.3z" - /> - <path fill="#333333" d="M620.4,437.9c0,0,0.1,0,0.2,0v2c-0.1,0-0.2,0-0.3,0s-0.2,0-0.2,0c-0.8,0-1.3,0.3-1.6,0.8 - c-0.2,0.3-0.2,0.7-0.2,1.3v3.6h-2v-7.5h1.9v1.3c0.3-0.5,0.6-0.8,0.8-1C619.3,438.1,619.8,437.9,620.4,437.9 - C620.4,437.9,620.4,437.9,620.4,437.9z"/> - <path fill="#333333" d="M628,444.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C628.9,442.9,628.6,443.9,628,444.6z M626.4,443.6c0.3-0.4,0.5-1,0.5-1.7 - c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7c0,0.7,0.2,1.3,0.5,1.7 - s0.7,0.6,1.3,0.6C625.7,444.2,626.1,444,626.4,443.6z"/> - <path fill="#333333" d="M636.6,438.9c0.6,0.6,0.9,1.6,0.9,2.8c0,1.3-0.3,2.3-0.9,3c-0.6,0.7-1.4,1-2.3,1c-0.6,0-1.1-0.1-1.5-0.4 - c-0.2-0.2-0.4-0.4-0.6-0.7v3.9h-1.9v-10.4h1.9v1.1c0.2-0.3,0.4-0.6,0.7-0.8c0.4-0.3,1-0.5,1.6-0.5 - C635.2,437.9,636,438.3,636.6,438.9z M635.1,440.3c-0.3-0.4-0.7-0.7-1.3-0.7c-0.7,0-1.2,0.3-1.5,1c-0.1,0.4-0.2,0.8-0.2,1.4 - c0,0.9,0.2,1.5,0.7,1.8c0.3,0.2,0.6,0.3,1,0.3c0.5,0,1-0.2,1.3-0.6c0.3-0.4,0.4-1,0.4-1.7C635.5,441.3,635.3,440.8,635.1,440.3z" - /> - <path fill="#333333" d="M643.7,438.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C642.6,437.9,643.2,438,643.7,438.3 - z M640.8,439.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C641.4,439.5,641.1,439.7,640.8,439.9z"/> - <path fill="#333333" d="M650.8,437.9c0,0,0.1,0,0.2,0v2c-0.1,0-0.2,0-0.3,0s-0.2,0-0.2,0c-0.8,0-1.3,0.3-1.6,0.8 - c-0.2,0.3-0.2,0.7-0.2,1.3v3.6h-2v-7.5h1.9v1.3c0.3-0.5,0.6-0.8,0.8-1C649.6,438.1,650.1,437.9,650.8,437.9 - C650.7,437.9,650.7,437.9,650.8,437.9z"/> - <path fill="#333333" d="M651.3,439.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H651.3z"/> - <path fill="#333333" d="M658.7,437.2h-2v-1.8h2V437.2z M656.8,438.1h2v7.5h-2V438.1z"/> - <path fill="#333333" d="M665.5,438.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5H662 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C664.4,437.9,665,438,665.5,438.3z - M662.6,439.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C663.2,439.5,662.8,439.7,662.6,439.9 + <path fill="#333333" d="M662.5,276.3h-1.8v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V276.3z M657.4,272.5 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C657.6,271.2,657.4,271.8,657.4,272.5z"/> + <path fill="#333333" d="M669.2,276.3v-1.1c-0.3,0.4-0.6,0.7-1,0.9s-0.9,0.3-1.4,0.3c-0.5,0-0.9-0.1-1.3-0.3 + c-0.4-0.2-0.7-0.5-0.8-0.9c-0.2-0.4-0.3-0.9-0.3-1.6V269h1.9v3.3c0,1,0,1.6,0.1,1.9c0.1,0.2,0.2,0.4,0.4,0.5 + c0.2,0.1,0.4,0.2,0.7,0.2c0.3,0,0.6-0.1,0.9-0.3c0.3-0.2,0.4-0.4,0.5-0.7c0.1-0.3,0.1-0.9,0.1-2V269h1.9v7.3H669.2z"/> + <path fill="#333333" d="M672.9,269h1.8v1.1c0.2-0.4,0.5-0.7,0.9-0.9s0.8-0.3,1.3-0.3c0.8,0,1.6,0.3,2.1,1s0.9,1.6,0.9,2.8 + c0,1.2-0.3,2.2-0.9,2.8c-0.6,0.7-1.3,1-2.2,1c-0.4,0-0.8-0.1-1.1-0.2c-0.3-0.2-0.7-0.4-1-0.8v3.7h-1.9V269z M674.8,272.5 + c0,0.8,0.2,1.4,0.5,1.8c0.3,0.4,0.7,0.6,1.2,0.6c0.4,0,0.8-0.2,1.1-0.5c0.3-0.4,0.4-0.9,0.4-1.8c0-0.8-0.2-1.3-0.5-1.7 + c-0.3-0.4-0.7-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.2,0.5C675,271.3,674.8,271.8,674.8,272.5z"/> + <path fill="#333333" d="M681.5,276.3v-10h1.9v10H681.5z"/> + <path fill="#333333" d="M685.4,268v-1.8h1.9v1.8H685.4z M685.4,276.3V269h1.9v7.3H685.4z"/> + <path fill="#333333" d="M695.7,271.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C695,269.8,695.4,270.4,695.7,271.2z"/> + <path fill="#333333" d="M698.5,271.2l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9 + c-0.1-0.1-0.1-0.3-0.2-0.6c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7c-0.4,0.2-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6 + s-0.6-0.9-0.6-1.5c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2 + c0-0.4-0.1-0.6-0.3-0.8c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C698.8,270.7,698.7,270.9,698.5,271.2z M701.1,272.8 + c-0.2,0.1-0.6,0.2-1.2,0.3s-0.9,0.2-1,0.3c-0.3,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7c0.2,0.2,0.5,0.3,0.8,0.3 + c0.3,0,0.7-0.1,1-0.3c0.2-0.2,0.4-0.4,0.5-0.6c0-0.2,0.1-0.5,0.1-0.9V272.8z"/> + <path fill="#333333" d="M708.2,269v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V269h0.9v-1.4l1.9-1.1v2.6H708.2z"/> + <path fill="#333333" d="M713.8,274l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3H711 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S713.7,274.3,713.8,274z M713.9,272c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H713.9z"/> + <path fill="#333333" d="M730.1,275l-1.2,1.5c-0.6-0.3-1.1-0.7-1.6-1.1c-0.4,0.4-0.8,0.6-1.3,0.8c-0.5,0.2-1,0.3-1.6,0.3 + c-1.2,0-2.2-0.4-2.8-1.1c-0.5-0.5-0.7-1.2-0.7-1.9c0-0.6,0.2-1.2,0.6-1.7c0.4-0.5,1-1,1.7-1.3c-0.3-0.4-0.6-0.8-0.8-1.2 + c-0.2-0.4-0.3-0.7-0.3-1c0-0.6,0.2-1.1,0.7-1.5c0.5-0.4,1.2-0.6,2.1-0.6c0.9,0,1.5,0.2,2,0.7c0.5,0.4,0.7,1,0.7,1.6 + c0,0.4-0.1,0.8-0.4,1.2c-0.2,0.4-0.7,0.8-1.5,1.2l1.4,1.8c0.2-0.3,0.3-0.7,0.4-1.1l1.7,0.4c-0.2,0.6-0.3,1.1-0.5,1.4 + c-0.1,0.3-0.3,0.5-0.4,0.7c0.2,0.2,0.5,0.4,0.8,0.7C729.7,274.8,730,275,730.1,275z M724.1,271.7c-0.4,0.2-0.8,0.5-1,0.8 + s-0.3,0.6-0.3,1c0,0.4,0.1,0.8,0.4,1c0.3,0.3,0.6,0.4,1.1,0.4c0.3,0,0.6-0.1,0.9-0.2c0.3-0.1,0.6-0.3,0.9-0.6L724.1,271.7z + M724.9,269.6l0.5-0.4c0.4-0.3,0.6-0.6,0.6-0.9c0-0.2-0.1-0.5-0.3-0.6s-0.4-0.3-0.7-0.3c-0.3,0-0.5,0.1-0.7,0.2 + c-0.2,0.2-0.3,0.3-0.3,0.5c0,0.2,0.1,0.5,0.4,0.9L724.9,269.6z"/> + <path fill="#333333" d="M735.1,269h1.8v1c0.6-0.8,1.4-1.2,2.3-1.2c0.5,0,0.9,0.1,1.2,0.3s0.6,0.5,0.8,0.9c0.3-0.4,0.7-0.7,1-0.9 + s0.8-0.3,1.2-0.3c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.6,0.5,0.8,1c0.1,0.3,0.2,0.8,0.2,1.5v4.6h-1.9v-4.1c0-0.7-0.1-1.2-0.2-1.4 + c-0.2-0.3-0.5-0.4-0.8-0.4c-0.3,0-0.5,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5v3.5h-1.9v-4 + c0-0.7,0-1.2-0.1-1.4s-0.2-0.4-0.3-0.5s-0.3-0.2-0.6-0.2c-0.3,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7s-0.2,0.8-0.2,1.5v3.5 + h-1.9V269z"/> + <path fill="#333333" d="M747.2,272.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C747.4,274.1,747.2,273.4,747.2,272.5z M749.2,272.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S749.2,271.9,749.2,272.6z"/> + <path fill="#333333" d="M758.2,276.3l-2.9-7.3h2l1.4,3.7l0.4,1.2c0.1-0.3,0.2-0.5,0.2-0.6c0.1-0.2,0.1-0.4,0.2-0.6l1.4-3.7h2 + l-2.9,7.3H758.2z"/> + <path fill="#333333" d="M768.2,274l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S768.1,274.3,768.2,274z M768.3,272c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H768.3z"/> + <path fill="#333333" d="M775,274.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C775.6,275.4,775.2,274.9,775,274.2z"/> + <path fill="#333333" d="M787.7,274l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S787.6,274.3,787.7,274z M787.8,272c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H787.8z"/> + <path fill="#333333" d="M791.3,276.3v-10h1.9v10H791.3z"/> + <path fill="#333333" d="M799.4,274l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S799.3,274.3,799.4,274z M799.5,272c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H799.5z"/> + <path fill="#333333" d="M809.3,271.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C808.7,269.8,809,270.4,809.3,271.2z"/> + <path fill="#333333" d="M814.1,269v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V269h0.9v-1.4l1.9-1.1v2.6H814.1z"/> + <path fill="#333333" d="M815.4,268v-1.8h1.9v1.8H815.4z M815.4,276.3V269h1.9v7.3H815.4z"/> + <path fill="#333333" d="M818.8,272.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C819,274.1,818.8,273.4,818.8,272.5z M820.8,272.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S820.8,271.9,820.8,272.6z"/> + <path fill="#333333" d="M834.4,276.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V269h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V276.3z"/> + <path fill="#333333" d="M841.5,276.3l-2.2-7.3h1.3l1.2,4.2l0.4,1.6c0-0.1,0.1-0.6,0.4-1.5l1.2-4.3h1.3l1.1,4.2l0.4,1.4l0.4-1.4 + l1.2-4.2h1.2l-2.3,7.3h-1.3l-1.2-4.3l-0.3-1.2l-1.5,5.6H841.5z"/> + <path fill="#333333" d="M850.3,267.7v-1.4h1.2v1.4H850.3z M850.3,276.3V269h1.2v7.3H850.3z"/> + <path fill="#333333" d="M856.1,275.2l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5V270h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C855.7,275.2,855.9,275.2,856.1,275.2z"/> + <path fill="#333333" d="M857.3,276.3v-10h1.2v3.6c0.6-0.7,1.3-1,2.2-1c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.7,0.5,0.9,0.9 + s0.3,0.9,0.3,1.6v4.6H862v-4.6c0-0.6-0.1-1.1-0.4-1.3c-0.3-0.3-0.6-0.4-1.1-0.4c-0.4,0-0.7,0.1-1,0.3c-0.3,0.2-0.5,0.4-0.7,0.8 + s-0.2,0.8-0.2,1.3v4H857.3z"/> + <path fill="#333333" d="M873.7,275.4c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.2-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9H874C873.8,276,873.8,275.7,873.7,275.4z M873.6,272.6c-0.4,0.2-1.1,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.1,0.2 + c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.3-0.3 + c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V272.6z"/> + <path fill="#333333" d="M876.7,276.3v-10h1.2v10H876.7z"/> + <path fill="#333333" d="M882.6,275.2l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5V270h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1h-1.2v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C882.2,275.2,882.3,275.2,882.6,275.2z"/> + <path fill="#333333" d="M890.2,274.7v-2.7h-2.7v-1.1h2.7V268h1.2v2.7h2.7v1.1h-2.7v2.7H890.2z"/> + <path fill="#333333" d="M899.7,276.3v-10h1.2v10H899.7z"/> + <path fill="#333333" d="M907.8,273.9l1.3,0.2c-0.2,0.7-0.6,1.3-1.1,1.7c-0.5,0.4-1.2,0.6-2.1,0.6c-1.1,0-1.9-0.3-2.5-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8s1.4-1,2.4-1c1,0,1.8,0.3,2.4,1s0.9,1.6,0.9,2.8c0,0.1,0,0.2,0,0.3h-5.4 + c0,0.8,0.3,1.4,0.7,1.8c0.4,0.4,0.9,0.6,1.5,0.6c0.5,0,0.8-0.1,1.2-0.4C907.4,274.8,907.6,274.5,907.8,273.9z M903.8,271.9h4.1 + c-0.1-0.6-0.2-1.1-0.5-1.4c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1,0.2-1.4,0.6C904,270.8,903.8,271.3,903.8,271.9z"/> + <path fill="#333333" d="M910.9,276.3V270h-1.1v-1h1.1v-0.8c0-0.5,0-0.8,0.1-1.1c0.1-0.3,0.3-0.6,0.6-0.8c0.3-0.2,0.7-0.3,1.3-0.3 + c0.3,0,0.7,0,1.1,0.1l-0.2,1.1c-0.3,0-0.5-0.1-0.7-0.1c-0.4,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.2,0.5-0.2,0.9v0.7h1.4v1h-1.4v6.3H910.9 z"/> - <path fill="#333333" d="M669.9,443.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H669.9z" - /> - <path fill="#333333" d="M689.4,438.1c0.3,0.1,0.6,0.4,0.9,0.7c0.2,0.3,0.4,0.6,0.4,1c0,0.3,0.1,0.6,0.1,1.1l0,4.7h-2v-4.7 - c0-0.3,0-0.5-0.1-0.7c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.1,0.7c-0.1,0.2-0.2,0.5-0.2,0.9v4.4h-2v-4.4c0-0.4,0-0.8-0.1-1 - c-0.2-0.4-0.5-0.5-1-0.5c-0.6,0-0.9,0.2-1.1,0.5c-0.1,0.2-0.2,0.5-0.2,0.9v4.5h-2v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8 - c0.4-0.3,0.9-0.4,1.5-0.4c0.6,0,1,0.1,1.4,0.4c0.3,0.2,0.5,0.5,0.6,0.9c0.3-0.4,0.6-0.8,1-1c0.4-0.2,0.8-0.3,1.3-0.3 - C688.7,437.9,689.1,438,689.4,438.1z"/> - <path fill="#333333" d="M697.4,438.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C696.3,437.9,696.9,438,697.4,438.3 - z M694.5,439.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C695.1,439.5,694.8,439.7,694.5,439.9z"/> - <path fill="#333333" d="M706.3,438.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V441c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C705.2,437.9,705.8,438.1,706.3,438.5z"/> - <path fill="#333333" d="M710.8,438.1v4.5c0,0.4,0,0.7,0.1,1c0.2,0.4,0.5,0.6,1,0.6c0.7,0,1.1-0.3,1.4-0.8c0.1-0.3,0.2-0.7,0.2-1.2 - v-4.1h2v7.5h-1.9v-1.1c0,0-0.1,0.1-0.1,0.2c-0.1,0.1-0.2,0.2-0.3,0.3c-0.3,0.3-0.6,0.5-0.9,0.6s-0.6,0.2-1,0.2 - c-1.1,0-1.8-0.4-2.2-1.2c-0.2-0.4-0.3-1.1-0.3-1.9v-4.5H710.8z"/> - <path fill="#333333" d="M724.4,435.4c0.1,0,0.2,0,0.4,0v1.6c-0.1,0-0.3,0-0.6,0c-0.3,0-0.4,0-0.5,0.2c-0.1,0.1-0.1,0.3-0.1,0.4 - s0,0.4,0,0.6h1.3v1.4h-1.3v6h-1.9v-6h-1.1v-1.4h1.1v-0.5c0-0.8,0.1-1.3,0.4-1.6c0.3-0.4,1-0.7,2-0.7 - C724.2,435.4,724.3,435.4,724.4,435.4z"/> - <path fill="#333333" d="M732.2,444.6c-0.6,0.8-1.6,1.2-2.9,1.2c-1.3,0-2.2-0.4-2.9-1.2s-0.9-1.7-0.9-2.8c0-1.1,0.3-2,0.9-2.8 - s1.6-1.2,2.9-1.2c1.3,0,2.2,0.4,2.9,1.2s0.9,1.7,0.9,2.8C733.1,442.9,732.8,443.9,732.2,444.6z M730.6,443.6 - c0.3-0.4,0.5-1,0.5-1.7c0-0.7-0.2-1.3-0.5-1.7c-0.3-0.4-0.7-0.6-1.3-0.6c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.5,1-0.5,1.7 - c0,0.7,0.2,1.3,0.5,1.7s0.7,0.6,1.3,0.6C729.9,444.2,730.3,444,730.6,443.6z"/> - <path fill="#333333" d="M738.7,437.9c0,0,0.1,0,0.2,0v2c-0.1,0-0.2,0-0.3,0s-0.2,0-0.2,0c-0.8,0-1.3,0.3-1.6,0.8 - c-0.2,0.3-0.2,0.7-0.2,1.3v3.6h-2v-7.5h1.9v1.3c0.3-0.5,0.6-0.8,0.8-1C737.5,438.1,738,437.9,738.7,437.9 - C738.6,437.9,738.6,437.9,738.7,437.9z"/> - <path fill="#333333" d="M745.4,443.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H745.4z" - /> - <path fill="#333333" d="M756.5,438.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5H753 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C755.4,437.9,756,438,756.5,438.3z - M753.6,439.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C754.3,439.5,753.9,439.7,753.6,439.9 - z"/> - <path fill="#333333" d="M761.4,445.6h-1.9v-10.1h1.9V445.6z"/> - <path fill="#333333" d="M768.2,438.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C767.1,437.9,767.7,438,768.2,438.3 - z M765.3,439.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C765.9,439.5,765.5,439.7,765.3,439.9z"/> - <path fill="#333333" d="M775.6,440.8c0-0.3-0.1-0.5-0.3-0.8c-0.2-0.3-0.6-0.5-1-0.5c-0.7,0-1.1,0.3-1.4,1 - c-0.1,0.3-0.2,0.8-0.2,1.4c0,0.5,0.1,1,0.2,1.3c0.2,0.6,0.7,0.9,1.3,0.9c0.5,0,0.8-0.1,1-0.4c0.2-0.2,0.3-0.6,0.3-1h2 - c0,0.6-0.3,1.2-0.6,1.7c-0.6,0.9-1.5,1.3-2.7,1.3c-1.2,0-2.1-0.4-2.6-1.1c-0.6-0.7-0.8-1.6-0.8-2.8c0-1.3,0.3-2.3,0.9-3 - s1.5-1.1,2.6-1.1c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1.2,1.1,2.2H775.6z"/> - <path fill="#333333" d="M778.1,439.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H778.1z"/> - <path fill="#333333" d="M788.4,438.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C787.3,437.9,787.9,438,788.4,438.3 - z M785.5,439.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4 - C786.2,439.5,785.8,439.7,785.5,439.9z"/> - <path fill="#333333" d="M795.3,438.2c0.4,0.2,0.6,0.5,0.9,0.8v-3.6h2v10.1h-1.9v-1c-0.3,0.4-0.6,0.8-1,1s-0.8,0.3-1.3,0.3 - c-0.9,0-1.6-0.4-2.2-1.1c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.3,0.3-2.3,0.9-3c0.6-0.7,1.4-1.1,2.3-1.1C794.6,437.9,795,438,795.3,438.2z - M795.8,443.5c0.3-0.4,0.4-0.9,0.4-1.6c0-0.9-0.2-1.6-0.7-2c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1,0.2-1.3,0.6c-0.3,0.4-0.4,1-0.4,1.6 - c0,0.7,0.1,1.2,0.4,1.7c0.3,0.4,0.7,0.6,1.2,0.6C795.1,444.2,795.5,443.9,795.8,443.5z"/> - <path fill="#333333" d="M808.7,438.3c0.5,0.2,0.9,0.6,1.3,1.1c0.3,0.4,0.5,1,0.6,1.5c0.1,0.3,0.1,0.8,0.1,1.5h-5.4 - c0,0.7,0.3,1.3,0.8,1.6c0.3,0.2,0.7,0.3,1.1,0.3c0.4,0,0.8-0.1,1.1-0.3c0.2-0.1,0.3-0.3,0.4-0.5h2c-0.1,0.4-0.3,0.9-0.7,1.3 - c-0.7,0.7-1.6,1.1-2.8,1.1c-1,0-1.9-0.3-2.6-0.9s-1.1-1.6-1.1-3c0-1.3,0.3-2.3,1-3s1.6-1,2.7-1C807.5,437.9,808.1,438,808.7,438.3 - z M805.7,439.9c-0.3,0.3-0.4,0.7-0.5,1.2h3.4c0-0.5-0.2-0.9-0.5-1.2c-0.3-0.3-0.7-0.4-1.2-0.4C806.4,439.5,806,439.7,805.7,439.9z - "/> - <path fill="#333333" d="M817.6,438.5c0.5,0.4,0.7,1.1,0.7,2v5h-2V441c0-0.4-0.1-0.7-0.2-0.9c-0.2-0.4-0.6-0.6-1.1-0.6 - c-0.7,0-1.1,0.3-1.4,0.8c-0.1,0.3-0.2,0.7-0.2,1.1v4h-1.9v-7.4h1.9v1.1c0.2-0.4,0.5-0.7,0.7-0.8c0.4-0.3,0.9-0.5,1.5-0.5 - C816.5,437.9,817.1,438.1,817.6,438.5z"/> - <path fill="#333333" d="M819.4,439.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H819.4z"/> - <path fill="#333333" d="M826.8,437.2h-2v-1.8h2V437.2z M824.8,438.1h2v7.5h-2V438.1z"/> - <path fill="#333333" d="M827.9,439.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H827.9z"/> - <path fill="#333333" d="M833.6,447l0.2,0c0.2,0,0.4,0,0.5,0c0.2,0,0.3-0.1,0.4-0.2c0.1-0.1,0.2-0.2,0.3-0.5 - c0.1-0.2,0.1-0.4,0.1-0.5l-2.7-7.8h2.2l1.6,5.5l1.5-5.5h2.1l-2.6,7.3c-0.5,1.4-0.9,2.3-1.2,2.6c-0.3,0.3-0.9,0.5-1.7,0.5 - c-0.2,0-0.3,0-0.4,0c-0.1,0-0.3,0-0.5,0V447z"/> - </g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M556.5,138.7c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V138.7z"/> - <g> - <path fill="#078876" d="M535.2,126c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6 - c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7H532c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1 - c0.8,0,1.5,0.2,2.2,0.5s1,0.9,1,1.8v3.4c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5s0.2,0.2,0.3,0.2v0.3h-2.1 - c-0.1-0.2-0.1-0.3-0.1-0.4s0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6 - c-0.4-0.4-0.7-0.9-0.7-1.6c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L535.2,126z M536.4,126.9c-0.1,0.1-0.3,0.1-0.4,0.2 - c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7 - c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4c0.4-0.2,0.5-0.7,0.6-1.3V126.9z"/> - <path fill="#078876" d="M542,130.6h-1.9v-10.1h1.9V130.6z"/> - <path fill="#078876" d="M543.2,124.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H543.2z"/> - </g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M658.5,138.7c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V138.7z"/> - <g> - <path fill="#078876" d="M637.2,126c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6 - c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7H634c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1 - c0.8,0,1.5,0.2,2.2,0.5s1,0.9,1,1.8v3.4c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5s0.2,0.2,0.3,0.2v0.3h-2.1 - c-0.1-0.2-0.1-0.3-0.1-0.4s0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6 - c-0.4-0.4-0.7-0.9-0.7-1.6c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L637.2,126z M638.4,126.9c-0.1,0.1-0.3,0.1-0.4,0.2 - c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7 - c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4c0.4-0.2,0.5-0.7,0.6-1.3V126.9z"/> - <path fill="#078876" d="M644,130.6h-1.9v-10.1h1.9V130.6z"/> - <path fill="#078876" d="M645.2,124.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H645.2z"/> + <path fill="#333333" d="M917.2,275.2l0.2,1.1c-0.3,0.1-0.7,0.1-0.9,0.1c-0.4,0-0.8-0.1-1-0.2s-0.4-0.3-0.5-0.6 + c-0.1-0.2-0.2-0.7-0.2-1.5V270h-0.9v-1h0.9v-1.8l1.2-0.7v2.5h1.2v1H916v4.2c0,0.4,0,0.6,0.1,0.7c0,0.1,0.1,0.2,0.2,0.2 + c0.1,0.1,0.2,0.1,0.4,0.1C916.8,275.2,917,275.2,917.2,275.2z"/> + <path fill="#333333" d="M927,273.6l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C926.7,274.7,926.9,274.2,927,273.6z"/> + <path fill="#333333" d="M929.3,276.3v-10h1.2v10H929.3z"/> + <path fill="#333333" d="M932.4,267.7v-1.4h1.2v1.4H932.4z M932.4,276.3V269h1.2v7.3H932.4z"/> + <path fill="#333333" d="M940.2,273.6l1.2,0.2c-0.1,0.8-0.5,1.5-1,2c-0.5,0.5-1.2,0.7-2,0.7c-1,0-1.8-0.3-2.4-1 + c-0.6-0.6-0.9-1.6-0.9-2.8c0-0.8,0.1-1.5,0.4-2.1s0.7-1,1.2-1.3c0.5-0.3,1.1-0.4,1.7-0.4c0.8,0,1.4,0.2,1.9,0.6 + c0.5,0.4,0.8,1,1,1.7l-1.2,0.2c-0.1-0.5-0.3-0.9-0.6-1.1c-0.3-0.2-0.6-0.4-1-0.4c-0.6,0-1.1,0.2-1.5,0.7c-0.4,0.4-0.6,1.1-0.6,2.1 + c0,1,0.2,1.7,0.6,2.1c0.4,0.4,0.9,0.7,1.5,0.7c0.5,0,0.9-0.1,1.2-0.4C940,274.7,940.2,274.2,940.2,273.6z"/> + <path fill="#333333" d="M942.5,276.3v-10h1.2v5.7l2.9-3h1.6l-2.8,2.7l3.1,4.6H947l-2.4-3.7l-0.9,0.8v2.9H942.5z"/> + <path fill="#333333" d="M956,274.7v-2.7h-2.7v-1.1h2.7V268h1.2v2.7h2.7v1.1h-2.7v2.7H956z"/> + <path fill="#333333" d="M970.2,276.3v-0.9c-0.5,0.7-1.1,1.1-2,1.1c-0.6,0-1.1-0.2-1.6-0.5s-0.9-0.8-1.1-1.3 + c-0.3-0.6-0.4-1.2-0.4-2c0-0.7,0.1-1.4,0.4-2c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.6-0.5c0.4,0,0.8,0.1,1.2,0.3 + c0.3,0.2,0.6,0.4,0.8,0.7v-3.6h1.2v10H970.2z M966.3,272.6c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.4,0.7c0.5,0,1-0.2,1.4-0.7 + c0.4-0.4,0.6-1.1,0.6-2c0-1-0.2-1.7-0.6-2.2s-0.9-0.7-1.4-0.7c-0.5,0-1,0.2-1.4,0.7C966.5,271,966.3,271.7,966.3,272.6z"/> + <path fill="#333333" d="M973.2,276.3V269h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H973.2z"/> + <path fill="#333333" d="M982.6,275.4c-0.5,0.4-0.9,0.7-1.3,0.8c-0.4,0.2-0.9,0.2-1.4,0.2c-0.8,0-1.4-0.2-1.8-0.6 + c-0.4-0.4-0.6-0.9-0.6-1.5c0-0.4,0.1-0.7,0.2-1c0.2-0.3,0.4-0.5,0.6-0.7c0.3-0.2,0.6-0.3,0.9-0.4c0.2-0.1,0.6-0.1,1.1-0.2 + c1-0.1,1.7-0.3,2.2-0.4c0-0.2,0-0.3,0-0.3c0-0.5-0.1-0.9-0.3-1.1c-0.3-0.3-0.8-0.4-1.4-0.4c-0.6,0-1,0.1-1.3,0.3 + c-0.3,0.2-0.5,0.6-0.6,1.1l-1.2-0.2c0.1-0.5,0.3-0.9,0.5-1.2c0.2-0.3,0.6-0.6,1.1-0.7c0.5-0.2,1-0.3,1.6-0.3 + c0.6,0,1.1,0.1,1.5,0.2c0.4,0.1,0.7,0.3,0.9,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0,0.2,0.1,0.6,0.1,1.1v1.6c0,1.1,0,1.9,0.1,2.2 + c0.1,0.3,0.2,0.6,0.3,0.9h-1.3C982.8,276,982.7,275.7,982.6,275.4z M982.5,272.6c-0.4,0.2-1.1,0.3-2,0.5c-0.5,0.1-0.9,0.2-1.1,0.2 + c-0.2,0.1-0.4,0.2-0.5,0.4c-0.1,0.2-0.2,0.4-0.2,0.6c0,0.3,0.1,0.6,0.4,0.8c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.3-0.3 + c0.4-0.2,0.6-0.5,0.8-0.9c0.1-0.3,0.2-0.7,0.2-1.2V272.6z"/> + <path fill="#333333" d="M985.5,276.9l1.2,0.2c0,0.4,0.2,0.6,0.4,0.8c0.3,0.2,0.7,0.3,1.3,0.3c0.6,0,1-0.1,1.3-0.3 + c0.3-0.2,0.5-0.5,0.6-1c0.1-0.3,0.1-0.8,0.1-1.6c-0.5,0.6-1.2,1-2,1c-1,0-1.8-0.4-2.3-1.1s-0.8-1.6-0.8-2.6c0-0.7,0.1-1.3,0.4-1.9 + c0.2-0.6,0.6-1,1.1-1.4c0.5-0.3,1-0.5,1.7-0.5c0.9,0,1.6,0.3,2.1,1V269h1.1v6.3c0,1.1-0.1,1.9-0.3,2.4c-0.2,0.5-0.6,0.8-1.1,1.1 + s-1.1,0.4-1.8,0.4c-0.9,0-1.6-0.2-2.1-0.6C985.7,278.2,985.5,277.7,985.5,276.9z M986.5,272.5c0,1,0.2,1.6,0.6,2.1 + c0.4,0.4,0.9,0.7,1.4,0.7c0.6,0,1-0.2,1.4-0.7c0.4-0.4,0.6-1.1,0.6-2c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.4-0.7 + c-0.5,0-1,0.2-1.4,0.7C986.7,271,986.5,271.6,986.5,272.5z"/> </g> <g> - <path fill="#333333" d="M608.7,124c0.6,0.6,1,1.6,1,2.8c0,1.2-0.3,2.2-0.9,2.9s-1.5,1.2-2.7,1.2c-1,0-1.8-0.3-2.4-1 - c-0.6-0.7-0.9-1.6-0.9-2.7c0-1.2,0.3-2.2,0.9-2.9s1.5-1.1,2.5-1.1C607.3,123,608.1,123.3,608.7,124z M607.9,128.8 - c0.3-0.6,0.5-1.3,0.5-2.1c0-0.7-0.1-1.2-0.3-1.7c-0.3-0.7-0.9-1-1.8-1c-0.7,0-1.3,0.3-1.6,0.9s-0.5,1.3-0.5,2.1 - c0,0.8,0.2,1.4,0.5,1.9s0.9,0.8,1.6,0.8C607.1,129.7,607.6,129.4,607.9,128.8z"/> - <path fill="#333333" d="M611.2,123.2h1.2v1.3c0.1-0.2,0.3-0.5,0.7-0.9c0.4-0.4,0.8-0.5,1.3-0.5c0,0,0.1,0,0.1,0s0.1,0,0.3,0v1.3 - c-0.1,0-0.1,0-0.2,0s-0.1,0-0.2,0c-0.6,0-1.1,0.2-1.4,0.6c-0.3,0.4-0.5,0.9-0.5,1.4v4.2h-1.2V123.2z"/> + <path fill="#333333" d="M655.7,335.3v-1.1c-0.3,0.4-0.6,0.7-1,0.9s-0.9,0.3-1.4,0.3c-0.5,0-0.9-0.1-1.3-0.3 + c-0.4-0.2-0.7-0.5-0.8-0.9c-0.2-0.4-0.3-0.9-0.3-1.6V328h1.9v3.3c0,1,0,1.6,0.1,1.9c0.1,0.2,0.2,0.4,0.4,0.5 + c0.2,0.1,0.4,0.2,0.7,0.2c0.3,0,0.6-0.1,0.9-0.3c0.3-0.2,0.4-0.4,0.5-0.7c0.1-0.3,0.1-0.9,0.1-2V328h1.9v7.3H655.7z"/> + <path fill="#333333" d="M666,335.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V328h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V335.3z"/> + <path fill="#333333" d="M674.6,335.3h-1.8v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V335.3z M669.5,331.5 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C669.7,330.2,669.5,330.8,669.5,331.5z"/> + <path fill="#333333" d="M676.1,331.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C676.3,333.1,676.1,332.4,676.1,331.5z M678.1,331.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S678.1,330.9,678.1,331.6z"/> </g> - <path fill="#B6B6B7" d="M636.2,170.7c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 - c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C633.6,170.7,635.5,170.7,636.2,170.7z"/> - <path fill="#078876" d="M620.5,179.9c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 - c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C620.6,184.5,620.5,181.9,620.5,179.9z"/> - <path fill="#B6B6B7" d="M632.6,215.3l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 - c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C644.4,209.4,639.1,215.2,632.6,215.3z"/> <g> - <path fill="#078876" d="M668.7,192.7l4.4,3.1l1.2-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.3,0.1,0.5,0.3,0.5,0.5l0.9,4.7 + <path fill="#333333" d="M748.7,401.3h-1.9V394h1.8v1c0.3-0.5,0.6-0.8,0.8-1c0.2-0.2,0.5-0.2,0.8-0.2c0.4,0,0.9,0.1,1.3,0.4 + l-0.6,1.7c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.1-0.3,0.4-0.4,0.8c-0.1,0.4-0.2,1.2-0.2,2.4V401.3z"/> + <path fill="#333333" d="M756.5,399l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S756.4,399.3,756.5,399z M756.6,397c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H756.6z"/> + <path fill="#333333" d="M766.8,401.3H765v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V401.3z M761.7,397.5 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C761.8,396.2,761.7,396.8,761.7,397.5z"/> + <path fill="#333333" d="M768.2,397.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C768.4,399.1,768.2,398.4,768.2,397.5z M770.2,397.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S770.2,396.9,770.2,397.6z"/> + </g> + <g> + <path fill="#333333" d="M588.4,457.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C588.6,459.1,588.4,458.4,588.4,457.5z M590.4,457.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S590.4,456.9,590.4,457.6z"/> + <path fill="#333333" d="M597.4,454h1.8v1.1c0.2-0.4,0.5-0.7,0.9-0.9s0.8-0.3,1.3-0.3c0.8,0,1.6,0.3,2.1,1s0.9,1.6,0.9,2.8 + c0,1.2-0.3,2.2-0.9,2.8c-0.6,0.7-1.3,1-2.2,1c-0.4,0-0.8-0.1-1.1-0.2c-0.3-0.2-0.7-0.4-1-0.8v3.7h-1.9V454z M599.3,457.5 + c0,0.8,0.2,1.4,0.5,1.8c0.3,0.4,0.7,0.6,1.2,0.6c0.4,0,0.8-0.2,1.1-0.5c0.3-0.4,0.4-0.9,0.4-1.8c0-0.8-0.2-1.3-0.5-1.7 + c-0.3-0.4-0.7-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.2,0.5C599.4,456.3,599.3,456.8,599.3,457.5z"/> + <path fill="#333333" d="M610.2,459l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S610.1,459.3,610.2,459z M610.3,457c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H610.3z"/> + <path fill="#333333" d="M620.4,461.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V454h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V461.3z"/> + <path fill="#333333" d="M626.2,454h1.8v1.1c0.2-0.4,0.5-0.7,0.9-0.9s0.8-0.3,1.3-0.3c0.8,0,1.6,0.3,2.1,1s0.9,1.6,0.9,2.8 + c0,1.2-0.3,2.2-0.9,2.8c-0.6,0.7-1.3,1-2.2,1c-0.4,0-0.8-0.1-1.1-0.2c-0.3-0.2-0.7-0.4-1-0.8v3.7h-1.9V454z M628.1,457.5 + c0,0.8,0.2,1.4,0.5,1.8c0.3,0.4,0.7,0.6,1.2,0.6c0.4,0,0.8-0.2,1.1-0.5c0.3-0.4,0.4-0.9,0.4-1.8c0-0.8-0.2-1.3-0.5-1.7 + c-0.3-0.4-0.7-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.2,0.5C628.2,456.3,628.1,456.8,628.1,457.5z"/> + <path fill="#333333" d="M636.6,461.3h-1.9V454h1.8v1c0.3-0.5,0.6-0.8,0.8-1c0.2-0.2,0.5-0.2,0.8-0.2c0.4,0,0.9,0.1,1.3,0.4 + l-0.6,1.7c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.1-0.3,0.4-0.4,0.8c-0.1,0.4-0.2,1.2-0.2,2.4V461.3z"/> + <path fill="#333333" d="M639.8,457.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C639.9,459.1,639.8,458.4,639.8,457.5z M641.7,457.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S641.7,456.9,641.7,457.6z"/> + <path fill="#333333" d="M648.7,454h1.8v1.1c0.2-0.4,0.5-0.7,0.9-0.9s0.8-0.3,1.3-0.3c0.8,0,1.6,0.3,2.1,1s0.9,1.6,0.9,2.8 + c0,1.2-0.3,2.2-0.9,2.8c-0.6,0.7-1.3,1-2.2,1c-0.4,0-0.8-0.1-1.1-0.2c-0.3-0.2-0.7-0.4-1-0.8v3.7h-1.9V454z M650.6,457.5 + c0,0.8,0.2,1.4,0.5,1.8c0.3,0.4,0.7,0.6,1.2,0.6c0.4,0,0.8-0.2,1.1-0.5c0.3-0.4,0.4-0.9,0.4-1.8c0-0.8-0.2-1.3-0.5-1.7 + c-0.3-0.4-0.7-0.6-1.1-0.6c-0.5,0-0.9,0.2-1.2,0.5C650.8,456.3,650.6,456.8,650.6,457.5z"/> + <path fill="#333333" d="M661.5,459l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S661.4,459.3,661.5,459z M661.6,457c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H661.6z"/> + <path fill="#333333" d="M666.9,461.3H665V454h1.8v1c0.3-0.5,0.6-0.8,0.8-1c0.2-0.2,0.5-0.2,0.8-0.2c0.4,0,0.9,0.1,1.3,0.4 + l-0.6,1.7c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.1-0.3,0.4-0.4,0.8c-0.1,0.4-0.2,1.2-0.2,2.4V461.3z"/> + <path fill="#333333" d="M673.9,454v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V454h0.9v-1.4l1.9-1.1v2.6H673.9z"/> + <path fill="#333333" d="M675.2,453v-1.8h1.9v1.8H675.2z M675.2,461.3V454h1.9v7.3H675.2z"/> + <path fill="#333333" d="M683.3,459l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S683.2,459.3,683.3,459z M683.4,457c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H683.4z"/> + <path fill="#333333" d="M686.2,459.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C686.8,460.4,686.4,459.9,686.2,459.2z"/> + <path fill="#333333" d="M698.4,454h1.8v1c0.6-0.8,1.4-1.2,2.3-1.2c0.5,0,0.9,0.1,1.2,0.3s0.6,0.5,0.8,0.9c0.3-0.4,0.7-0.7,1-0.9 + s0.8-0.3,1.2-0.3c0.5,0,1,0.1,1.4,0.3c0.4,0.2,0.6,0.5,0.8,1c0.1,0.3,0.2,0.8,0.2,1.5v4.6h-1.9v-4.1c0-0.7-0.1-1.2-0.2-1.4 + c-0.2-0.3-0.5-0.4-0.8-0.4c-0.3,0-0.5,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.2,0.8-0.2,1.5v3.5h-1.9v-4 + c0-0.7,0-1.2-0.1-1.4s-0.2-0.4-0.3-0.5s-0.3-0.2-0.6-0.2c-0.3,0-0.6,0.1-0.8,0.2c-0.2,0.2-0.4,0.4-0.5,0.7s-0.2,0.8-0.2,1.5v3.5 + h-1.9V454z"/> + <path fill="#333333" d="M715.2,459l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S715.1,459.3,715.2,459z M715.3,457c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H715.3z"/> + <path fill="#333333" d="M725.4,461.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3h-1.9V454h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V461.3z"/> + <path fill="#333333" d="M732.1,461.3v-1.1c-0.3,0.4-0.6,0.7-1,0.9s-0.9,0.3-1.4,0.3c-0.5,0-0.9-0.1-1.3-0.3 + c-0.4-0.2-0.7-0.5-0.8-0.9c-0.2-0.4-0.3-0.9-0.3-1.6V454h1.9v3.3c0,1,0,1.6,0.1,1.9c0.1,0.2,0.2,0.4,0.4,0.5 + c0.2,0.1,0.4,0.2,0.7,0.2c0.3,0,0.6-0.1,0.9-0.3c0.3-0.2,0.4-0.4,0.5-0.7c0.1-0.3,0.1-0.9,0.1-2V454h1.9v7.3H732.1z"/> + <path fill="#333333" d="M739,454h1.1v-0.5c0-0.6,0.1-1.1,0.2-1.4s0.4-0.5,0.7-0.7c0.3-0.2,0.8-0.3,1.3-0.3c0.5,0,1.1,0.1,1.6,0.2 + l-0.3,1.3c-0.3-0.1-0.6-0.1-0.9-0.1c-0.3,0-0.5,0.1-0.6,0.2c-0.1,0.1-0.2,0.4-0.2,0.7v0.5h1.4v1.5h-1.4v5.7H740v-5.7H739V454z"/> + <path fill="#333333" d="M744,457.5c0-0.6,0.2-1.3,0.5-1.9s0.8-1.1,1.3-1.4c0.6-0.3,1.2-0.5,1.9-0.5c1.1,0,2,0.4,2.7,1.1 + c0.7,0.7,1.1,1.6,1.1,2.7c0,1.1-0.4,2-1.1,2.7c-0.7,0.7-1.6,1.1-2.7,1.1c-0.7,0-1.3-0.2-1.9-0.5c-0.6-0.3-1.1-0.7-1.4-1.3 + C744.2,459.1,744,458.4,744,457.5z M746,457.6c0,0.7,0.2,1.3,0.5,1.7s0.8,0.6,1.3,0.6c0.5,0,0.9-0.2,1.3-0.6 + c0.3-0.4,0.5-0.9,0.5-1.7c0-0.7-0.2-1.3-0.5-1.6c-0.3-0.4-0.8-0.6-1.3-0.6c-0.5,0-0.9,0.2-1.3,0.6S746,456.9,746,457.6z"/> + <path fill="#333333" d="M754.9,461.3h-1.9V454h1.8v1c0.3-0.5,0.6-0.8,0.8-1c0.2-0.2,0.5-0.2,0.8-0.2c0.4,0,0.9,0.1,1.3,0.4 + l-0.6,1.7c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.1-0.3,0.4-0.4,0.8c-0.1,0.4-0.2,1.2-0.2,2.4V461.3z"/> + <path fill="#333333" d="M761.7,459.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C762.2,460.4,761.9,459.9,761.7,459.2z"/> + <path fill="#333333" d="M774.3,459l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S774.2,459.3,774.3,459z M774.4,457c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H774.4z"/> + <path fill="#333333" d="M777.9,461.3v-10h1.9v10H777.9z"/> + <path fill="#333333" d="M786,459l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S785.9,459.3,786,459z M786.1,457c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H786.1z"/> + <path fill="#333333" d="M795.9,456.2l-1.9,0.3c-0.1-0.4-0.2-0.7-0.4-0.9s-0.5-0.3-0.9-0.3c-0.5,0-0.9,0.2-1.1,0.5 + c-0.3,0.3-0.4,0.9-0.4,1.7c0,0.9,0.1,1.5,0.4,1.8c0.3,0.4,0.7,0.5,1.2,0.5c0.4,0,0.7-0.1,0.9-0.3c0.2-0.2,0.4-0.6,0.5-1.1l1.9,0.3 + c-0.2,0.9-0.6,1.5-1.1,2c-0.6,0.4-1.3,0.7-2.2,0.7c-1.1,0-1.9-0.3-2.5-1c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.1,1-2.8 + c0.6-0.7,1.5-1,2.6-1c0.9,0,1.6,0.2,2.1,0.6C795.3,454.8,795.7,455.4,795.9,456.2z"/> + <path fill="#333333" d="M800.7,454v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V454h0.9v-1.4l1.9-1.1v2.6H800.7z"/> + <path fill="#333333" d="M806.2,459l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S806.1,459.3,806.2,459z M806.4,457c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H806.4z"/> + <path fill="#333333" d="M816.5,461.3h-1.8v-1.1c-0.3,0.4-0.6,0.7-1,0.9c-0.4,0.2-0.8,0.3-1.2,0.3c-0.8,0-1.5-0.3-2.1-1 + c-0.6-0.7-0.9-1.6-0.9-2.8c0-1.2,0.3-2.2,0.9-2.8c0.6-0.6,1.3-1,2.2-1c0.8,0,1.5,0.3,2.1,1v-3.6h1.9V461.3z M811.4,457.5 + c0,0.8,0.1,1.3,0.3,1.7c0.3,0.5,0.7,0.8,1.3,0.8c0.4,0,0.8-0.2,1.1-0.6c0.3-0.4,0.5-0.9,0.5-1.7c0-0.8-0.2-1.4-0.5-1.8 + c-0.3-0.4-0.7-0.5-1.2-0.5c-0.5,0-0.8,0.2-1.1,0.5C811.5,456.2,811.4,456.8,811.4,457.5z"/> + <path fill="#333333" d="M826.5,459l1.9,0.3c-0.2,0.7-0.6,1.2-1.2,1.6c-0.5,0.4-1.2,0.6-2,0.6c-1.3,0-2.2-0.4-2.8-1.2 + c-0.5-0.7-0.7-1.5-0.7-2.5c0-1.2,0.3-2.1,0.9-2.8c0.6-0.7,1.4-1,2.4-1c1.1,0,1.9,0.4,2.6,1.1c0.6,0.7,0.9,1.8,0.9,3.3h-4.8 + c0,0.6,0.2,1,0.5,1.3c0.3,0.3,0.7,0.5,1.1,0.5c0.3,0,0.6-0.1,0.8-0.2S826.4,459.3,826.5,459z M826.6,457c0-0.6-0.2-1-0.4-1.3 + c-0.3-0.3-0.6-0.4-1-0.4c-0.4,0-0.8,0.2-1,0.5s-0.4,0.7-0.4,1.2H826.6z"/> + <path fill="#333333" d="M836.7,461.3h-1.9v-3.7c0-0.8,0-1.3-0.1-1.5c-0.1-0.2-0.2-0.4-0.4-0.5s-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.3c-0.3,0.2-0.4,0.4-0.5,0.7c-0.1,0.3-0.1,0.9-0.1,1.7v3.3H830V454h1.8v1.1c0.6-0.8,1.4-1.2,2.4-1.2 + c0.4,0,0.8,0.1,1.2,0.2c0.4,0.2,0.6,0.3,0.8,0.6c0.2,0.2,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.7,0.1,1.3V461.3z"/> + <path fill="#333333" d="M841.9,454v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V454h0.9v-1.4l1.9-1.1v2.6H841.9z"/> + <path fill="#333333" d="M843.3,453v-1.8h1.9v1.8H843.3z M843.3,461.3V454h1.9v7.3H843.3z"/> + <path fill="#333333" d="M850.5,454v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V454h0.9v-1.4l1.9-1.1v2.6H850.5z"/> + <path fill="#333333" d="M850.9,454h2l1.7,5.2l1.7-5.2h2l-2.6,7l-0.5,1.3c-0.2,0.4-0.3,0.7-0.5,1c-0.2,0.2-0.3,0.4-0.5,0.5 + c-0.2,0.1-0.4,0.2-0.7,0.3c-0.3,0.1-0.6,0.1-1,0.1c-0.4,0-0.7,0-1.1-0.1l-0.2-1.5c0.3,0.1,0.6,0.1,0.8,0.1c0.4,0,0.8-0.1,1-0.4 + c0.2-0.3,0.4-0.6,0.5-1L850.9,454z"/> + </g> + <g> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M574.9,154.4c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V154.4z"/> + </g> + <g> + <g> + <path fill="#048876" d="M552.2,141.2l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9c0-0.1-0.1-0.3-0.2-0.6 + c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7s-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6c-0.4-0.4-0.6-0.9-0.6-1.5 + c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2c0-0.4-0.1-0.6-0.3-0.8 + c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C552.4,140.7,552.3,140.9,552.2,141.2z M554.7,142.8c-0.2,0.1-0.6,0.2-1.2,0.3 + s-0.9,0.2-1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7s0.5,0.3,0.8,0.3c0.3,0,0.7-0.1,1-0.3c0.2-0.2,0.4-0.4,0.5-0.6 + c0-0.2,0.1-0.5,0.1-0.9V142.8z"/> + <path fill="#048876" d="M558.5,146.3v-10h1.9v10H558.5z"/> + <path fill="#048876" d="M565.7,139v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2c0.1,0.1,0.2,0.1,0.3,0.1 + c0.2,0,0.4-0.1,0.8-0.2l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5 + c-0.1-0.2-0.2-0.4-0.3-0.7c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V139h0.9v-1.4l1.9-1.1v2.6H565.7z"/> + </g> + </g> + <g> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M676.9,154.4c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V154.4z"/> + </g> + <g> + <g> + <path fill="#048876" d="M654.2,141.2l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9c0-0.1-0.1-0.3-0.2-0.6 + c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7s-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6c-0.4-0.4-0.6-0.9-0.6-1.5 + c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2c0-0.4-0.1-0.6-0.3-0.8 + c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C654.4,140.7,654.3,140.9,654.2,141.2z M656.7,142.8c-0.2,0.1-0.6,0.2-1.2,0.3 + s-0.9,0.2-1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7s0.5,0.3,0.8,0.3c0.3,0,0.7-0.1,1-0.3c0.2-0.2,0.4-0.4,0.5-0.6 + c0-0.2,0.1-0.5,0.1-0.9V142.8z"/> + <path fill="#048876" d="M660.5,146.3v-10h1.9v10H660.5z"/> + <path fill="#048876" d="M667.7,139v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2c0.1,0.1,0.2,0.1,0.3,0.1 + c0.2,0,0.4-0.1,0.8-0.2l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5 + c-0.1-0.2-0.2-0.4-0.3-0.7c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V139h0.9v-1.4l1.9-1.1v2.6H667.7z"/> + </g> + </g> + <g> + <path fill="#333333" d="M621.3,142.6c0-1.3,0.4-2.3,1.1-3c0.6-0.5,1.4-0.8,2.3-0.8c1,0,1.8,0.3,2.4,1c0.6,0.7,1,1.6,1,2.7 + c0,0.9-0.1,1.7-0.4,2.2c-0.3,0.5-0.7,1-1.2,1.2c-0.5,0.3-1.1,0.4-1.8,0.4c-1,0-1.8-0.3-2.5-1C621.7,144.8,621.3,143.8,621.3,142.6 + z M622.6,142.6c0,0.9,0.2,1.6,0.6,2.1c0.4,0.5,0.9,0.7,1.5,0.7c0.6,0,1.1-0.2,1.5-0.7c0.4-0.5,0.6-1.2,0.6-2.1 + c0-0.9-0.2-1.6-0.6-2c-0.4-0.5-0.9-0.7-1.5-0.7c-0.6,0-1.1,0.2-1.5,0.7C622.8,141,622.6,141.7,622.6,142.6z"/> + <path fill="#333333" d="M629.6,146.3V139h1.1v1.1c0.3-0.5,0.5-0.9,0.8-1s0.5-0.2,0.8-0.2c0.4,0,0.8,0.1,1.3,0.4l-0.4,1.1 + c-0.3-0.2-0.6-0.3-0.9-0.3c-0.3,0-0.5,0.1-0.7,0.2c-0.2,0.2-0.4,0.4-0.5,0.7c-0.1,0.4-0.2,0.9-0.2,1.4v3.8H629.6z"/> + </g> + <path fill="#B6B6B6" d="M654.5,186.4c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 + c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C652,186.4,653.9,186.4,654.5,186.4z"/> + <path fill="#048876" d="M638.9,195.6c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 + c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C639,200.2,638.9,197.6,638.9,195.6z"/> + <path fill="#B6B6B6" d="M651,231l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 + c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C662.8,225.1,657.5,231,651,231z"/> + <g> + <path fill="#048876" d="M687.1,208.4l4.4,3.1l1.2-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.3,0.1,0.5,0.3,0.5,0.5l0.9,4.7 c0.1,0.4-0.2,0.7-0.6,0.8l-4.7,0.9c-0.3,0.1-0.5-0.1-0.7-0.3c-0.2-0.2-0.2-0.5,0-0.8l1.2-1.8l-4.4-3.1l-3.1,4.4l1.8,1.2 c0.2,0.2,0.3,0.4,0.3,0.7c-0.1,0.3-0.3,0.5-0.5,0.5l-4.7,0.9c-0.4,0.1-0.7-0.2-0.8-0.6l-0.9-4.7c-0.1-0.3,0.1-0.5,0.3-0.7 c0.2-0.2,0.5-0.2,0.8,0l1.8,1.2l3.1-4.4l-4.4-3.1l-1.2,1.8c-0.1,0.2-0.3,0.3-0.4,0.3c-0.1,0-0.2,0-0.3,0c-0.3-0.1-0.5-0.3-0.5-0.5 l-0.9-4.7c-0.1-0.4,0.2-0.7,0.6-0.8l4.7-0.9c0.3-0.1,0.5,0.1,0.7,0.3c0.2,0.2,0.2,0.5,0,0.8l-1.2,1.8l4.4,3.1l3.1-4.4l-1.8-1.2 c-0.2-0.2-0.3-0.4-0.3-0.7c0.1-0.3,0.3-0.5,0.5-0.5l4.7-0.9c0.4-0.1,0.7,0.2,0.8,0.6l0.9,4.7c0.1,0.3-0.1,0.5-0.3,0.7 - c-0.1,0-0.2,0.1-0.3,0.1c-0.2,0-0.4,0-0.5-0.1l-1.8-1.2L668.7,192.7z"/> + c-0.1,0-0.2,0.1-0.3,0.1c-0.2,0-0.4,0-0.5-0.1l-1.8-1.2L687.1,208.4z"/> </g> <g> - <path fill="#078876" d="M535.1,193.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H535.1z" - /> - <path fill="#078876" d="M546.7,188.2c0.4,0.2,0.7,0.4,0.9,0.7c0.2,0.3,0.3,0.6,0.4,0.9c0,0.3,0.1,0.8,0.1,1.4v4.4h-2V191 - c0-0.4-0.1-0.7-0.2-1c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.2,0.5s-0.4,0.8-0.4,1.5v4h-1.9v-10h1.9v3.6c0.3-0.4,0.6-0.7,1-0.9 - c0.4-0.2,0.8-0.3,1.2-0.3C545.9,187.9,546.3,188,546.7,188.2z"/> - <path fill="#078876" d="M551.9,187.2h-2v-1.8h2V187.2z M549.9,188.1h2v7.5h-2V188.1z"/> - <path fill="#078876" d="M556.9,185.4c0.1,0,0.2,0,0.4,0v1.6c-0.1,0-0.3,0-0.6,0c-0.3,0-0.4,0-0.5,0.2c-0.1,0.1-0.1,0.3-0.1,0.4 - s0,0.4,0,0.6h1.3v1.4h-1.3v6h-1.9v-6H553v-1.4h1.1v-0.5c0-0.8,0.1-1.3,0.4-1.6c0.3-0.4,1-0.7,2-0.7 - C556.7,185.4,556.8,185.4,556.9,185.4z"/> - <path fill="#078876" d="M557.7,189.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H557.7z"/> + <path fill="#048876" d="M551.4,209.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C551.9,210.4,551.6,209.9,551.4,209.2z"/> + <path fill="#048876" d="M561.8,201.2v3.7c0.6-0.7,1.4-1.1,2.2-1.1c0.4,0,0.8,0.1,1.2,0.2s0.6,0.4,0.8,0.6c0.2,0.3,0.3,0.5,0.4,0.8 + c0.1,0.3,0.1,0.8,0.1,1.4v4.3h-1.9v-3.8c0-0.8,0-1.2-0.1-1.4c-0.1-0.2-0.2-0.4-0.4-0.5c-0.2-0.1-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.2c-0.3,0.2-0.4,0.4-0.6,0.7c-0.1,0.3-0.2,0.8-0.2,1.4v3.6h-1.9v-10H561.8z"/> + <path fill="#048876" d="M568.4,203v-1.8h1.9v1.8H568.4z M568.4,211.3V204h1.9v7.3H568.4z"/> + <path fill="#048876" d="M571.4,204h1.1v-0.5c0-0.6,0.1-1.1,0.2-1.4s0.4-0.5,0.7-0.7c0.3-0.2,0.8-0.3,1.3-0.3 + c0.5,0,1.1,0.1,1.6,0.2l-0.3,1.3c-0.3-0.1-0.6-0.1-0.9-0.1c-0.3,0-0.5,0.1-0.6,0.2c-0.1,0.1-0.2,0.4-0.2,0.7v0.5h1.4v1.5h-1.4v5.7 + h-1.9v-5.7h-1.1V204z"/> + <path fill="#048876" d="M580.3,204v1.5H579v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V204h0.9v-1.4l1.9-1.1v2.6H580.3z"/> + </g> + <g> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M629.9,220.4c0,2.2-1.8,4-4,4h-81c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h81c2.2,0,4,1.8,4,4V220.4z"/> </g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M611.5,204.7c0,2.2-1.8,4-4,4h-81c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h81c2.2,0,4,1.8,4,4V204.7z"/> <g> <g> - <path fill="#078876" d="M535.1,508.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H535.1z - "/> - <path fill="#078876" d="M546.7,503.2c0.4,0.2,0.7,0.4,0.9,0.7c0.2,0.3,0.3,0.6,0.4,0.9c0,0.3,0.1,0.8,0.1,1.4v4.4h-2V506 - c0-0.4-0.1-0.7-0.2-1c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.2,0.5s-0.4,0.8-0.4,1.5v4h-1.9v-10h1.9v3.6c0.3-0.4,0.6-0.7,1-0.9 - c0.4-0.2,0.8-0.3,1.2-0.3C545.9,502.9,546.3,503,546.7,503.2z"/> - <path fill="#078876" d="M551.9,502.2h-2v-1.8h2V502.2z M549.9,503.1h2v7.5h-2V503.1z"/> - <path fill="#078876" d="M556.9,500.4c0.1,0,0.2,0,0.4,0v1.6c-0.1,0-0.3,0-0.6,0c-0.3,0-0.4,0-0.5,0.2c-0.1,0.1-0.1,0.3-0.1,0.4 - s0,0.4,0,0.6h1.3v1.4h-1.3v6h-1.9v-6H553v-1.4h1.1v-0.5c0-0.8,0.1-1.3,0.4-1.6c0.3-0.4,1-0.7,2-0.7 - C556.7,500.4,556.8,500.4,556.9,500.4z"/> - <path fill="#078876" d="M557.7,504.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H557.7z"/> + <path fill="#048876" d="M551.4,524.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C551.9,525.4,551.6,524.9,551.4,524.2z"/> + <path fill="#048876" d="M561.8,516.2v3.7c0.6-0.7,1.4-1.1,2.2-1.1c0.4,0,0.8,0.1,1.2,0.2s0.6,0.4,0.8,0.6 + c0.2,0.3,0.3,0.5,0.4,0.8c0.1,0.3,0.1,0.8,0.1,1.4v4.3h-1.9v-3.8c0-0.8,0-1.2-0.1-1.4c-0.1-0.2-0.2-0.4-0.4-0.5 + c-0.2-0.1-0.4-0.2-0.7-0.2c-0.3,0-0.6,0.1-0.9,0.2c-0.3,0.2-0.4,0.4-0.6,0.7c-0.1,0.3-0.2,0.8-0.2,1.4v3.6h-1.9v-10H561.8z"/> + <path fill="#048876" d="M568.4,518v-1.8h1.9v1.8H568.4z M568.4,526.3V519h1.9v7.3H568.4z"/> + <path fill="#048876" d="M571.4,519h1.1v-0.5c0-0.6,0.1-1.1,0.2-1.4s0.4-0.5,0.7-0.7c0.3-0.2,0.8-0.3,1.3-0.3 + c0.5,0,1.1,0.1,1.6,0.2l-0.3,1.3c-0.3-0.1-0.6-0.1-0.9-0.1c-0.3,0-0.5,0.1-0.6,0.2c-0.1,0.1-0.2,0.4-0.2,0.7v0.5h1.4v1.5h-1.4 + v5.7h-1.9v-5.7h-1.1V519z"/> + <path fill="#048876" d="M580.3,519v1.5H579v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V519h0.9v-1.4l1.9-1.1v2.6H580.3z"/> </g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M611.5,519.7c0,2.2-1.8,4-4,4h-81c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h81c2.2,0,4,1.8,4,4V519.7z"/> - </g> - <g> - <path fill="#078876" d="M596.1,383.2c0,0.3,0.1,0.6,0.3,0.7c0.2,0.3,0.7,0.4,1.3,0.4c0.4,0,0.7-0.1,0.9-0.2s0.3-0.3,0.3-0.5 - c0-0.2-0.1-0.4-0.3-0.5s-0.9-0.3-2-0.6c-0.8-0.2-1.4-0.5-1.8-0.8c-0.3-0.3-0.5-0.8-0.5-1.3c0-0.7,0.3-1.3,0.8-1.8 - c0.5-0.5,1.3-0.7,2.3-0.7c0.9,0,1.7,0.2,2.3,0.6c0.6,0.4,0.9,1,1,1.9h-1.9c0-0.3-0.1-0.4-0.2-0.6c-0.2-0.3-0.6-0.4-1.1-0.4 - c-0.4,0-0.7,0.1-0.9,0.2s-0.3,0.3-0.3,0.5c0,0.2,0.1,0.4,0.3,0.5c0.2,0.1,0.9,0.3,2,0.5c0.8,0.2,1.4,0.5,1.7,0.8 - c0.4,0.4,0.6,0.8,0.6,1.4c0,0.7-0.3,1.3-0.8,1.8c-0.6,0.5-1.4,0.7-2.6,0.7c-1.2,0-2-0.2-2.6-0.7c-0.6-0.5-0.8-1.1-0.8-1.9H596.1z" - /> - <path fill="#078876" d="M607.7,378.2c0.4,0.2,0.7,0.4,0.9,0.7c0.2,0.3,0.3,0.6,0.4,0.9c0,0.3,0.1,0.8,0.1,1.4v4.4h-2V381 - c0-0.4-0.1-0.7-0.2-1c-0.2-0.3-0.5-0.5-1-0.5c-0.5,0-0.9,0.2-1.2,0.5s-0.4,0.8-0.4,1.5v4h-1.9v-10h1.9v3.6c0.3-0.4,0.6-0.7,1-0.9 - c0.4-0.2,0.8-0.3,1.2-0.3C606.9,377.9,607.3,378,607.7,378.2z"/> - <path fill="#078876" d="M612.9,377.2h-2v-1.8h2V377.2z M610.9,378.1h2v7.5h-2V378.1z"/> - <path fill="#078876" d="M617.9,375.4c0.1,0,0.2,0,0.4,0v1.6c-0.1,0-0.3,0-0.6,0c-0.3,0-0.4,0-0.5,0.2c-0.1,0.1-0.1,0.3-0.1,0.4 - s0,0.4,0,0.6h1.3v1.4h-1.3v6h-1.9v-6H614v-1.4h1.1v-0.5c0-0.8,0.1-1.3,0.4-1.6c0.3-0.4,1-0.7,2-0.7 - C617.7,375.4,617.8,375.4,617.9,375.4z"/> - <path fill="#078876" d="M618.7,379.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H618.7z"/> - </g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M672.5,394.7c0,2.2-1.8,4-4,4h-81c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h81c2.2,0,4,1.8,4,4V394.7z"/> - <g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M556.5,266.7c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V266.7z"/> <g> - <path fill="#078876" d="M535.2,254c0.4,0,0.6-0.1,0.8-0.2c0.3-0.1,0.4-0.3,0.4-0.6c0-0.3-0.1-0.5-0.3-0.6 - c-0.2-0.1-0.5-0.2-0.9-0.2c-0.5,0-0.8,0.1-1,0.3c-0.1,0.2-0.2,0.4-0.3,0.7H532c0-0.7,0.2-1.2,0.5-1.6c0.5-0.7,1.4-1,2.7-1 - c0.8,0,1.5,0.2,2.2,0.5s1,0.9,1,1.8v3.4c0,0.2,0,0.5,0,0.9c0,0.3,0.1,0.4,0.1,0.5s0.2,0.2,0.3,0.2v0.3h-2.1 - c-0.1-0.2-0.1-0.3-0.1-0.4s0-0.3-0.1-0.5c-0.3,0.3-0.6,0.5-0.9,0.7c-0.4,0.2-0.9,0.4-1.4,0.4c-0.7,0-1.2-0.2-1.7-0.6 - c-0.4-0.4-0.7-0.9-0.7-1.6c0-0.9,0.4-1.6,1.1-2c0.4-0.2,1-0.4,1.7-0.5L535.2,254z M536.4,254.9c-0.1,0.1-0.3,0.1-0.4,0.2 - c-0.1,0-0.3,0.1-0.5,0.1l-0.4,0.1c-0.4,0.1-0.7,0.2-0.9,0.3c-0.3,0.2-0.5,0.5-0.5,0.8c0,0.3,0.1,0.6,0.3,0.7 - c0.2,0.1,0.4,0.2,0.7,0.2c0.4,0,0.8-0.1,1.2-0.4c0.4-0.2,0.5-0.7,0.6-1.3V254.9z"/> - <path fill="#078876" d="M542,258.6h-1.9v-10.1h1.9V258.6z"/> - <path fill="#078876" d="M543.2,252.6v-1.4h1v-2.1h1.9v2.1h1.2v1.4h-1.2v3.9c0,0.3,0,0.5,0.1,0.6c0.1,0.1,0.3,0.1,0.7,0.1 - c0.1,0,0.1,0,0.2,0c0.1,0,0.1,0,0.2,0v1.5l-0.9,0c-0.9,0-1.5-0.1-1.9-0.5c-0.2-0.2-0.3-0.6-0.3-1v-4.6H543.2z"/> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M629.9,535.4c0,2.2-1.8,4-4,4h-81c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h81c2.2,0,4,1.8,4,4V535.4z"/> </g> </g> <g> - <path fill="none" stroke="#979797" stroke-miterlimit="10" d="M556.5,455.7c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 - c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V455.7z"/> + <path fill="#048876" d="M612.4,399.2l1.9-0.3c0.1,0.4,0.2,0.7,0.5,0.9c0.2,0.2,0.6,0.3,1.1,0.3c0.5,0,0.9-0.1,1.1-0.3 + c0.2-0.1,0.3-0.3,0.3-0.5c0-0.1,0-0.3-0.1-0.4c-0.1-0.1-0.3-0.2-0.6-0.3c-1.5-0.3-2.5-0.7-2.9-0.9c-0.6-0.4-0.9-0.9-0.9-1.6 + c0-0.6,0.2-1.2,0.7-1.6c0.5-0.4,1.3-0.6,2.3-0.6c1,0,1.7,0.2,2.2,0.5c0.5,0.3,0.8,0.8,1,1.4l-1.8,0.3c-0.1-0.3-0.2-0.5-0.4-0.6 + c-0.2-0.2-0.5-0.2-0.9-0.2c-0.5,0-0.9,0.1-1.1,0.2c-0.1,0.1-0.2,0.2-0.2,0.4c0,0.1,0.1,0.3,0.2,0.3c0.2,0.1,0.8,0.3,1.8,0.5 + c1,0.2,1.7,0.5,2.1,0.9c0.4,0.3,0.6,0.8,0.6,1.4c0,0.7-0.3,1.2-0.8,1.7c-0.6,0.5-1.4,0.7-2.5,0.7c-1,0-1.8-0.2-2.3-0.6 + C612.9,400.4,612.6,399.9,612.4,399.2z"/> + <path fill="#048876" d="M622.8,391.2v3.7c0.6-0.7,1.4-1.1,2.2-1.1c0.4,0,0.8,0.1,1.2,0.2s0.6,0.4,0.8,0.6c0.2,0.3,0.3,0.5,0.4,0.8 + c0.1,0.3,0.1,0.8,0.1,1.4v4.3h-1.9v-3.8c0-0.8,0-1.2-0.1-1.4c-0.1-0.2-0.2-0.4-0.4-0.5c-0.2-0.1-0.4-0.2-0.7-0.2 + c-0.3,0-0.6,0.1-0.9,0.2c-0.3,0.2-0.4,0.4-0.6,0.7c-0.1,0.3-0.2,0.8-0.2,1.4v3.6h-1.9v-10H622.8z"/> + <path fill="#048876" d="M629.4,393v-1.8h1.9v1.8H629.4z M629.4,401.3V394h1.9v7.3H629.4z"/> + <path fill="#048876" d="M632.4,394h1.1v-0.5c0-0.6,0.1-1.1,0.2-1.4s0.4-0.5,0.7-0.7c0.3-0.2,0.8-0.3,1.3-0.3 + c0.5,0,1.1,0.1,1.6,0.2l-0.3,1.3c-0.3-0.1-0.6-0.1-0.9-0.1c-0.3,0-0.5,0.1-0.6,0.2c-0.1,0.1-0.2,0.4-0.2,0.7v0.5h1.4v1.5h-1.4v5.7 + h-1.9v-5.7h-1.1V394z"/> + <path fill="#048876" d="M641.3,394v1.5H640v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2s0.2,0.1,0.3,0.1c0.2,0,0.4-0.1,0.8-0.2 + l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5c-0.1-0.2-0.2-0.4-0.3-0.7 + c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V394h0.9v-1.4l1.9-1.1v2.6H641.3z"/> + </g> + <g> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M690.9,410.4c0,2.2-1.8,4-4,4h-81c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h81c2.2,0,4,1.8,4,4V410.4z"/> + </g> + <g> <g> - <path fill="#078876" d="M540.9,438.1h-2.4l-3.6-3.5h3.7L540.9,438.1z"/> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M574.9,282.4c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V282.4z"/> + </g> + <g> + <g> + <path fill="#048876" d="M552.2,269.2l-1.7-0.3c0.2-0.7,0.5-1.2,1-1.6s1.2-0.5,2.1-0.5c0.9,0,1.5,0.1,1.9,0.3 + c0.4,0.2,0.7,0.5,0.9,0.8c0.2,0.3,0.3,0.9,0.3,1.7l0,2.2c0,0.6,0,1.1,0.1,1.4c0.1,0.3,0.2,0.6,0.3,1h-1.9c0-0.1-0.1-0.3-0.2-0.6 + c0-0.1-0.1-0.2-0.1-0.2c-0.3,0.3-0.7,0.6-1.1,0.7s-0.8,0.2-1.2,0.2c-0.7,0-1.3-0.2-1.8-0.6c-0.4-0.4-0.6-0.9-0.6-1.5 + c0-0.4,0.1-0.8,0.3-1.1c0.2-0.3,0.5-0.6,0.8-0.7c0.4-0.2,0.9-0.3,1.5-0.4c0.9-0.2,1.5-0.3,1.9-0.5v-0.2c0-0.4-0.1-0.6-0.3-0.8 + c-0.2-0.2-0.5-0.2-1-0.2c-0.3,0-0.6,0.1-0.8,0.2C552.4,268.7,552.3,268.9,552.2,269.2z M554.7,270.8c-0.2,0.1-0.6,0.2-1.2,0.3 + s-0.9,0.2-1,0.3c-0.2,0.2-0.4,0.4-0.4,0.7c0,0.3,0.1,0.5,0.3,0.7s0.5,0.3,0.8,0.3c0.3,0,0.7-0.1,1-0.3c0.2-0.2,0.4-0.4,0.5-0.6 + c0-0.2,0.1-0.5,0.1-0.9V270.8z"/> + <path fill="#048876" d="M558.5,274.3v-10h1.9v10H558.5z"/> + <path fill="#048876" d="M565.7,267v1.5h-1.3v2.9c0,0.6,0,0.9,0,1c0,0.1,0.1,0.2,0.2,0.2c0.1,0.1,0.2,0.1,0.3,0.1 + c0.2,0,0.4-0.1,0.8-0.2l0.2,1.5c-0.4,0.2-1,0.3-1.5,0.3c-0.3,0-0.7-0.1-0.9-0.2c-0.3-0.1-0.5-0.3-0.6-0.5 + c-0.1-0.2-0.2-0.4-0.3-0.7c0-0.2-0.1-0.7-0.1-1.4v-3.2h-0.9V267h0.9v-1.4l1.9-1.1v2.6H565.7z"/> + </g> </g> </g> - <path fill="#B6B6B7" d="M580.6,232.9c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 - c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C578,232.9,579.9,232.9,580.6,232.9z"/> - <path fill="#078876" d="M564.9,242.1c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 - c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C565,246.7,564.9,244.2,564.9,242.1z"/> - <path fill="#B6B6B7" d="M577.1,277.6l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 - c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C588.8,271.6,583.6,277.5,577.1,277.6z"/> <g> - <path fill="#078876" d="M613.1,254.9l4.4,3.1l1.2-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.3,0.1,0.5,0.3,0.5,0.5l0.9,4.7 + <g> + <path fill="none" stroke="#989898" stroke-miterlimit="10" d="M574.9,471.4c0,2.2-1.8,4-4,4h-26c-2.2,0-4-1.8-4-4v-26 + c0-2.2,1.8-4,4-4h26c2.2,0,4,1.8,4,4V471.4z"/> + </g> + <g> + <g> + <path fill="#048876" d="M559.7,454.3h-2.1l-3.2-3.5h3.7L559.7,454.3z"/> + </g> + </g> + </g> + <path fill="#B6B6B6" d="M599,248.6c0.8,0,8.5,1.1,8.4,9.3c0,2-0.1,4.6-0.2,7.4c-0.2,0-5.8-0.4-11.5-0.4l0-4.2 + c0.7-0.4,1.3-1.8,1.3-3.6c0-1.8-0.5-3.2-1.3-3.6l0-4.9C596.4,248.6,598.3,248.6,599,248.6z"/> + <path fill="#048876" d="M583.3,257.8c-0.1-8.2,7.6-9.3,8.4-9.3c0.7,0,2.6,0,3.3,0l0,4.9c-0.7,0.4-1.3,1.8-1.3,3.6 + c0,1.8,0.5,3.2,1.3,3.6l0,4.2c-5.7,0-11.2,0.3-11.5,0.3C583.4,262.4,583.3,259.9,583.3,257.8z"/> + <path fill="#B6B6B6" d="M595.4,293.3l-0.6,0c-6.5-0.1-11.7-6-11.4-11c0.4-5.4,0.2-11.4,0.1-16.6l0,0.3c0.1,0,5.9-0.3,11.7-0.3 + c5.8,0,11.7,0.4,11.7,0.4l0,0c-0.2,5.1-0.4,11,0,16.3C607.2,287.3,601.9,293.2,595.4,293.3z"/> + <g> + <path fill="#048876" d="M631.5,270.6l4.4,3.1l1.2-1.8c0.2-0.2,0.4-0.3,0.7-0.3c0.3,0.1,0.5,0.3,0.5,0.5l0.9,4.7 c0.1,0.4-0.2,0.7-0.6,0.8l-4.7,0.9c-0.3,0.1-0.5-0.1-0.7-0.3c-0.2-0.2-0.2-0.5,0-0.8l1.2-1.8l-4.4-3.1l-3.1,4.4l1.8,1.2 c0.2,0.2,0.3,0.4,0.3,0.7c-0.1,0.3-0.3,0.5-0.5,0.5l-4.7,0.9c-0.4,0.1-0.7-0.2-0.8-0.6l-0.9-4.7c-0.1-0.3,0.1-0.5,0.3-0.7 c0.2-0.2,0.5-0.2,0.8,0l1.8,1.2l3.1-4.4l-4.4-3.1l-1.2,1.8c-0.1,0.2-0.3,0.3-0.4,0.3c-0.1,0-0.2,0-0.3,0c-0.3-0.1-0.5-0.3-0.5-0.5 l-0.9-4.7c-0.1-0.4,0.2-0.7,0.6-0.8l4.7-0.9c0.3-0.1,0.5,0.1,0.7,0.3c0.2,0.2,0.2,0.5,0,0.8l-1.2,1.8l4.4,3.1l3.1-4.4l-1.8-1.2 c-0.2-0.2-0.3-0.4-0.3-0.7c0.1-0.3,0.3-0.5,0.5-0.5l4.7-0.9c0.4-0.1,0.7,0.2,0.8,0.6l0.9,4.7c0.1,0.3-0.1,0.5-0.3,0.7 - c-0.1,0-0.2,0.1-0.3,0.1c-0.2,0-0.4,0-0.5-0.1l-1.8-1.2L613.1,254.9z"/> + c-0.1,0-0.2,0.1-0.3,0.1c-0.2,0-0.4,0-0.5-0.1l-1.8-1.2L631.5,270.6z"/> </g> - <path fill="#078876" d="M693.2,132.1c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4v-11.4c0-0.8,1.2-1.4,2.7-1.4h22.3 - c1.5,0,2.7,0.6,2.7,1.4V132.1z"/> + <path fill="#048876" d="M711.6,147.8c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4v-11.4c0-0.8,1.2-1.4,2.7-1.4h22.3 + c1.5,0,2.7,0.6,2.7,1.4V147.8z"/> <g> - <path fill="#FFFFFF" d="M683.2,125.4l-3.5,3.5c-0.1,0.1-0.2,0.1-0.4,0.1s-0.3-0.1-0.4-0.1l-3.5-3.5c-0.1-0.1-0.1-0.2-0.1-0.4 - c0-0.3,0.2-0.5,0.5-0.5h7c0.3,0,0.5,0.2,0.5,0.5C683.4,125.2,683.3,125.3,683.2,125.4z"/> + <path fill="#FFFFFF" d="M701.6,141.1l-3.5,3.5c-0.1,0.1-0.2,0.1-0.4,0.1s-0.3-0.1-0.4-0.1l-3.5-3.5c-0.1-0.1-0.1-0.2-0.1-0.4 + c0-0.3,0.2-0.5,0.5-0.5h7c0.3,0,0.5,0.2,0.5,0.5C701.7,140.9,701.7,141,701.6,141.1z"/> </g> - <path fill="#078876" d="M591.5,132.1c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4v-11.4c0-0.8,1.2-1.4,2.7-1.4h22.3 - c1.5,0,2.7,0.6,2.7,1.4V132.1z"/> + <path fill="#048876" d="M609.9,147.8c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4v-11.4c0-0.8,1.2-1.4,2.7-1.4h22.3 + c1.5,0,2.7,0.6,2.7,1.4V147.8z"/> <g> - <path fill="#FFFFFF" d="M581.1,128.8h-7c-0.3,0-0.5-0.2-0.5-0.5c0-0.1,0.1-0.3,0.1-0.4l3.5-3.5c0.1-0.1,0.2-0.1,0.4-0.1 - s0.3,0.1,0.4,0.1l3.5,3.5c0.1,0.1,0.1,0.2,0.1,0.4C581.6,128.6,581.4,128.8,581.1,128.8z"/> + <path fill="#FFFFFF" d="M599.5,144.5h-7c-0.3,0-0.5-0.2-0.5-0.5c0-0.1,0.1-0.3,0.1-0.4l3.5-3.5c0.1-0.1,0.2-0.1,0.4-0.1 + s0.3,0.1,0.4,0.1l3.5,3.5c0.1,0.1,0.1,0.2,0.1,0.4C600,144.3,599.8,144.5,599.5,144.5z"/> </g> <g> - <path fill="#078876" d="M552.6,76.8c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4V65.4c0-0.8,1.2-1.4,2.7-1.4h22.3 - c1.5,0,2.7,0.6,2.7,1.4V76.8z"/> - <path fill="#078876" d="M584.7,77.1c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4V65.8c0-0.8,1.2-1.4,2.7-1.4H582 - c1.5,0,2.7,0.6,2.7,1.4V77.1z"/> - <path fill="#078876" d="M584.7,60.9c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4V49.5c0-0.8,1.2-1.4,2.7-1.4H582 - c1.5,0,2.7,0.6,2.7,1.4V60.9z"/> - <path fill="#078876" d="M616.5,76.7c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4V65.4c0-0.8,1.2-1.4,2.7-1.4h22.3 - c1.5,0,2.7,0.6,2.7,1.4V76.7z"/> + <path fill="#048876" d="M571,92.5c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4V81.2c0-0.8,1.2-1.4,2.7-1.4h22.3 + c1.5,0,2.7,0.6,2.7,1.4V92.5z"/> + <path fill="#048876" d="M603.1,92.8c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4V81.5c0-0.8,1.2-1.4,2.7-1.4h22.3 + c1.5,0,2.7,0.6,2.7,1.4V92.8z"/> + <path fill="#048876" d="M603.1,76.6c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4V65.3c0-0.8,1.2-1.4,2.7-1.4h22.3 + c1.5,0,2.7,0.6,2.7,1.4V76.6z"/> + <path fill="#048876" d="M634.9,92.5c0,0.8-1.2,1.4-2.7,1.4h-22.3c-1.5,0-2.7-0.6-2.7-1.4V81.1c0-0.8,1.2-1.4,2.7-1.4h22.3 + c1.5,0,2.7,0.6,2.7,1.4V92.5z"/> <g> - <path fill="#FFFFFF" d="M574.7,70.4l-3.5,3.5c-0.1,0.1-0.2,0.1-0.4,0.1s-0.3-0.1-0.4-0.1l-3.5-3.5c-0.1-0.1-0.1-0.2-0.1-0.4 - c0-0.3,0.2-0.5,0.5-0.5h7c0.3,0,0.5,0.2,0.5,0.5C574.8,70.2,574.8,70.3,574.7,70.4z"/> + <path fill="#FFFFFF" d="M593.1,86.1l-3.5,3.5c-0.1,0.1-0.2,0.1-0.4,0.1s-0.3-0.1-0.4-0.1l-3.5-3.5c-0.1-0.1-0.1-0.2-0.1-0.4 + c0-0.3,0.2-0.5,0.5-0.5h7c0.3,0,0.5,0.2,0.5,0.5C593.2,85.9,593.2,86,593.1,86.1z"/> </g> <g> - <path fill="#FFFFFF" d="M574.3,57.6h-7c-0.3,0-0.5-0.2-0.5-0.5c0-0.1,0.1-0.3,0.1-0.4l3.5-3.5c0.1-0.1,0.2-0.1,0.4-0.1 - s0.3,0.1,0.4,0.1l3.5,3.5c0.1,0.1,0.1,0.2,0.1,0.4C574.8,57.3,574.6,57.6,574.3,57.6z"/> + <path fill="#FFFFFF" d="M592.7,73.3h-7c-0.3,0-0.5-0.2-0.5-0.5c0-0.1,0.1-0.3,0.1-0.4l3.5-3.5c0.1-0.1,0.2-0.1,0.4-0.1 + s0.3,0.1,0.4,0.1l3.5,3.5c0.1,0.1,0.1,0.2,0.1,0.4C593.2,73,593,73.3,592.7,73.3z"/> </g> <g> - <path fill="#FFFFFF" d="M604.5,71.9l-3.5,3.5c-0.1,0.1-0.2,0.1-0.4,0.1c-0.3,0-0.5-0.2-0.5-0.5v-7c0-0.3,0.2-0.5,0.5-0.5 - c0.1,0,0.3,0.1,0.4,0.1l3.5,3.5c0.1,0.1,0.1,0.2,0.1,0.4S604.6,71.8,604.5,71.9z"/> + <path fill="#FFFFFF" d="M622.9,87.6l-3.5,3.5c-0.1,0.1-0.2,0.1-0.4,0.1c-0.3,0-0.5-0.2-0.5-0.5v-7c0-0.3,0.2-0.5,0.5-0.5 + c0.1,0,0.3,0.1,0.4,0.1l3.5,3.5c0.1,0.1,0.1,0.2,0.1,0.4S623,87.5,622.9,87.6z"/> </g> <g> - <path fill="#FFFFFF" d="M541.2,75.1c0,0.3-0.2,0.5-0.5,0.5c-0.1,0-0.3-0.1-0.4-0.1l-3.5-3.5c-0.1-0.1-0.1-0.2-0.1-0.4 - s0.1-0.3,0.1-0.4l3.5-3.5c0.1-0.1,0.2-0.1,0.4-0.1c0.3,0,0.5,0.2,0.5,0.5V75.1z"/> + <path fill="#FFFFFF" d="M559.6,90.8c0,0.3-0.2,0.5-0.5,0.5c-0.1,0-0.3-0.1-0.4-0.1l-3.5-3.5c-0.1-0.1-0.1-0.2-0.1-0.4 + s0.1-0.3,0.1-0.4l3.5-3.5c0.1-0.1,0.2-0.1,0.4-0.1c0.3,0,0.5,0.2,0.5,0.5V90.8z"/> </g> </g> - <rect x="635.7" y="498.4" transform="matrix(0.1245 0.9922 -0.9922 0.1245 1056.6464 -194.6891)" width="5.9" height="5.9"/> - <polygon points="634.7,507.8 636.1,505.6 642,504.9 640.6,507.1 "/> - <polygon points="633.7,501.1 634.8,499.2 635.5,505.1 634.4,507 "/> + <rect x="654.1" y="514.1" transform="matrix(0.1245 0.9922 -0.9922 0.1245 1088.3284 -199.1745)" width="5.9" height="5.9"/> + <polygon points="653.1,523.6 654.5,521.3 660.4,520.6 659,522.8 "/> + <polygon points="652.1,516.9 653.2,514.9 653.9,520.8 652.8,522.7 "/> </g> </svg> </div> From 3f986229d150875275a868ab940a37766a11988b Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Tue, 24 Mar 2015 13:43:10 -0700 Subject: [PATCH 075/177] Rename edit-entities-commands.html to edit-commands.html --- .../html/{edit-entities-commands.html => edit-commands.html} | 0 interface/src/Application.h | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename interface/resources/html/{edit-entities-commands.html => edit-commands.html} (100%) diff --git a/interface/resources/html/edit-entities-commands.html b/interface/resources/html/edit-commands.html similarity index 100% rename from interface/resources/html/edit-entities-commands.html rename to interface/resources/html/edit-commands.html diff --git a/interface/src/Application.h b/interface/src/Application.h index 4038b21739..898db76f07 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -113,7 +113,7 @@ static const float MIRROR_FIELD_OF_VIEW = 30.0f; static const quint64 TOO_LONG_SINCE_LAST_SEND_DOWNSTREAM_AUDIO_STATS = 1 * USECS_PER_SECOND; static const QString INFO_HELP_PATH = "html/interface-welcome.html"; -static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-entities-commands.html"; +static const QString INFO_EDIT_ENTITIES_PATH = "html/edit-commands.html"; #ifdef Q_OS_WIN static const UINT UWM_IDENTIFY_INSTANCES = From 3563efb584d7b56b25beee653ded7b39ddabd05d Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Tue, 24 Mar 2015 21:52:53 +0100 Subject: [PATCH 076/177] extra ; --- libraries/entities/src/EntityItemID.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities/src/EntityItemID.cpp b/libraries/entities/src/EntityItemID.cpp index aaf6e33128..cd2202eead 100644 --- a/libraries/entities/src/EntityItemID.cpp +++ b/libraries/entities/src/EntityItemID.cpp @@ -25,7 +25,7 @@ EntityItemID::EntityItemID() : creatorTokenID(UNKNOWN_ENTITY_TOKEN), isKnownID(false) { -}; +} EntityItemID::EntityItemID(const EntityItemID& other) : id(other.id), From f43b8bbe8edc744d99f3d43fc665d014ee6f001d Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Tue, 24 Mar 2015 13:59:46 -0700 Subject: [PATCH 077/177] make AvatarLODMultiplier based on octreeSizeScale --- interface/src/LODManager.cpp | 46 +++++++---------------------- interface/src/LODManager.h | 14 ++++----- interface/src/ui/LodToolsDialog.cpp | 13 -------- interface/src/ui/LodToolsDialog.h | 2 -- 4 files changed, 16 insertions(+), 59 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 5c55952e3a..6d08b8e242 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -20,13 +20,14 @@ Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS); Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS); - -Setting::Handle<float> avatarLODDistanceMultiplier("avatarLODDistanceMultiplier", - DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER); Setting::Handle<int> boundaryLevelAdjust("boundaryLevelAdjust", 0); Setting::Handle<float> octreeSizeScale("octreeSizeScale", DEFAULT_OCTREE_SIZE_SCALE); +LODManager::LODManager() { + calculateAvatarLODDistanceMultiplier(); +} + float LODManager::getLODDecreaseFPS() { if (Application::getInstance()->isHMDMode()) { return getHMDLODDecreaseFPS(); @@ -64,21 +65,6 @@ void LODManager::autoAdjustLOD(float currentFPS) { // LOD Downward adjustment if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < getLODDecreaseFPS()) { - // Avatars... attempt to lower the detail in proportion to the fps difference - float targetFps = (getLODDecreaseFPS() + getLODIncreaseFPS()) * 0.5f; - float averageFps = _fastFPSAverage.getAverage(); - const float MAXIMUM_MULTIPLIER_SCALE = 2.0f; - float oldAvatarLODDistanceMultiplier = _avatarLODDistanceMultiplier; - _avatarLODDistanceMultiplier = qMin(MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, _avatarLODDistanceMultiplier * - (averageFps < EPSILON ? MAXIMUM_MULTIPLIER_SCALE : - qMin(MAXIMUM_MULTIPLIER_SCALE, targetFps / averageFps))); - - if (oldAvatarLODDistanceMultiplier != _avatarLODDistanceMultiplier) { - qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() - << "_avatarLODDistanceMultiplier=" << _avatarLODDistanceMultiplier; - changed = true; - } - // Octree items... stepwise adjustment if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) { _octreeSizeScale *= ADJUST_LOD_DOWN_BY; @@ -100,20 +86,6 @@ void LODManager::autoAdjustLOD(float currentFPS) { // LOD Upward adjustment if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > getLODIncreaseFPS()) { - // Avatars... let the detail level creep slowly upwards - if (_avatarLODDistanceMultiplier < MAXIMUM_AUTO_ADJUST_AVATAR_LOD_DISTANCE_MULTIPLIER) { - const float DISTANCE_DECREASE_RATE = 0.05f; - float oldAvatarLODDistanceMultiplier = _avatarLODDistanceMultiplier; - _avatarLODDistanceMultiplier = qMax(MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, - _avatarLODDistanceMultiplier - DISTANCE_DECREASE_RATE); - - if (oldAvatarLODDistanceMultiplier != _avatarLODDistanceMultiplier) { - qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() - << "_avatarLODDistanceMultiplier=" << _avatarLODDistanceMultiplier; - changed = true; - } - } - // Octee items... stepwise adjustment if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { @@ -137,6 +109,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { } if (changed) { + calculateAvatarLODDistanceMultiplier(); _shouldRenderTableNeedsRebuilding = true; auto lodToolsDialog = DependencyManager::get<DialogsManager>()->getLodToolsDialog(); if (lodToolsDialog) { @@ -231,9 +204,14 @@ bool LODManager::shouldRenderMesh(float largestDimension, float distanceToCamera void LODManager::setOctreeSizeScale(float sizeScale) { _octreeSizeScale = sizeScale; + calculateAvatarLODDistanceMultiplier(); _shouldRenderTableNeedsRebuilding = true; } +void LODManager::calculateAvatarLODDistanceMultiplier() { + _avatarLODDistanceMultiplier = AVATAR_TO_ENTITY_RATIO / (_octreeSizeScale / DEFAULT_OCTREE_SIZE_SCALE); +} + void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) { _boundaryLevelAdjust = boundaryLevelAdjust; _shouldRenderTableNeedsRebuilding = true; @@ -243,8 +221,6 @@ void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) { void LODManager::loadSettings() { setDesktopLODDecreaseFPS(desktopLODDecreaseFPS.get()); setHMDLODDecreaseFPS(hmdLODDecreaseFPS.get()); - - setAvatarLODDistanceMultiplier(avatarLODDistanceMultiplier.get()); setBoundaryLevelAdjust(boundaryLevelAdjust.get()); setOctreeSizeScale(octreeSizeScale.get()); } @@ -252,8 +228,6 @@ void LODManager::loadSettings() { void LODManager::saveSettings() { desktopLODDecreaseFPS.set(getDesktopLODDecreaseFPS()); hmdLODDecreaseFPS.set(getHMDLODDecreaseFPS()); - - avatarLODDistanceMultiplier.set(getAvatarLODDistanceMultiplier()); boundaryLevelAdjust.set(getBoundaryLevelAdjust()); octreeSizeScale.set(getOctreeSizeScale()); } diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 7d63fbd172..c14f17ca61 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -33,10 +33,9 @@ const float ADJUST_LOD_UP_BY = 1.1f; const float ADJUST_LOD_MIN_SIZE_SCALE = 1.0f; const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; -const float MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 0.1f; -const float MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER = 15.0f; -const float DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER = 1.0f; -const float MAXIMUM_AUTO_ADJUST_AVATAR_LOD_DISTANCE_MULTIPLIER = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER; +// The ratio of "visibility" of avatars to other content. A value larger than 1 will mean Avatars "cull" later than entities +// do. But both are still culled using the same angular size logic. +const float AVATAR_TO_ENTITY_RATIO = 2.0f; const int ONE_SECOND_OF_FRAMES = 60; const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; @@ -58,7 +57,6 @@ public: Q_INVOKABLE float getHMDLODDecreaseFPS() const { return _hmdLODDecreaseFPS; } Q_INVOKABLE float getHMDLODIncreaseFPS() const { return _hmdLODDecreaseFPS + INCREASE_LOD_GAP; } - Q_INVOKABLE void setAvatarLODDistanceMultiplier(float multiplier) { _avatarLODDistanceMultiplier = multiplier; } Q_INVOKABLE float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; } // User Tweakable LOD Items @@ -87,14 +85,14 @@ signals: void LODDecreased(); private: - LODManager() {} + LODManager(); + void calculateAvatarLODDistanceMultiplier(); bool _automaticLODAdjust = true; float _desktopLODDecreaseFPS = DEFAULT_DESKTOP_LOD_DOWN_FPS; float _hmdLODDecreaseFPS = DEFAULT_HMD_LOD_DOWN_FPS; - float _avatarLODDistanceMultiplier = DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER; - + float _avatarLODDistanceMultiplier; float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; int _boundaryLevelAdjust = 0; diff --git a/interface/src/ui/LodToolsDialog.cpp b/interface/src/ui/LodToolsDialog.cpp index 7635012bc2..97991c62a4 100644 --- a/interface/src/ui/LodToolsDialog.cpp +++ b/interface/src/ui/LodToolsDialog.cpp @@ -50,13 +50,6 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : _automaticLODAdjust->setChecked(lodManager->getAutomaticLODAdjust()); connect(_automaticLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust())); - form->addRow("Avatar LOD:", _avatarLOD = new QDoubleSpinBox(this)); - _avatarLOD->setDecimals(3); - _avatarLOD->setRange(1.0 / MAXIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER, 1.0 / MINIMUM_AVATAR_LOD_DISTANCE_MULTIPLIER); - _avatarLOD->setSingleStep(0.001); - _avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier()); - connect(_avatarLOD, SIGNAL(valueChanged(double)), SLOT(updateAvatarLODValues())); - _lodSize = new QSlider(Qt::Horizontal, this); const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER; const int MIN_LOD_SIZE = ADJUST_LOD_MIN_SIZE_SCALE; @@ -89,9 +82,6 @@ void LodToolsDialog::reloadSliders() { auto lodManager = DependencyManager::get<LODManager>(); _lodSize->setValue(lodManager->getOctreeSizeScale() / TREE_SCALE); _feedback->setText(lodManager->getLODFeedbackText()); - - _avatarLOD->setValue(1.0 / lodManager->getAvatarLODDistanceMultiplier()); - } void LodToolsDialog::updateAutomaticLODAdjust() { @@ -101,9 +91,7 @@ void LodToolsDialog::updateAutomaticLODAdjust() { void LodToolsDialog::updateLODValues() { auto lodManager = DependencyManager::get<LODManager>(); - lodManager->setAutomaticLODAdjust(_automaticLODAdjust->isChecked()); - lodManager->setAvatarLODDistanceMultiplier(1.0 / _avatarLOD->value()); } void LodToolsDialog::sizeScaleValueChanged(int value) { @@ -119,7 +107,6 @@ void LodToolsDialog::resetClicked(bool checked) { int sliderValue = DEFAULT_OCTREE_SIZE_SCALE / TREE_SCALE; _lodSize->setValue(sliderValue); _automaticLODAdjust->setChecked(true); - _avatarLOD->setValue(1.0 / DEFAULT_AVATAR_LOD_DISTANCE_MULTIPLIER); updateLODValues(); // tell our LOD manager about the reset } diff --git a/interface/src/ui/LodToolsDialog.h b/interface/src/ui/LodToolsDialog.h index 709357fddd..91be04e0ed 100644 --- a/interface/src/ui/LodToolsDialog.h +++ b/interface/src/ui/LodToolsDialog.h @@ -50,8 +50,6 @@ private: QDoubleSpinBox* _hmdLODDecreaseFPS; - - QDoubleSpinBox* _avatarLOD; QLabel* _feedback; }; From b67cf3af2435cd772302c1f8ce5bda7ef471c7f5 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Tue, 24 Mar 2015 14:33:06 -0700 Subject: [PATCH 078/177] more tweaks to LOD tools dialog --- interface/src/LODManager.cpp | 8 -------- interface/src/ui/LodToolsDialog.cpp | 29 +++++++++++++++++------------ interface/src/ui/LodToolsDialog.h | 3 +-- 3 files changed, 18 insertions(+), 22 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 6d08b8e242..8b942dcfe1 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -20,10 +20,6 @@ Setting::Handle<float> desktopLODDecreaseFPS("desktopLODDecreaseFPS", DEFAULT_DESKTOP_LOD_DOWN_FPS); Setting::Handle<float> hmdLODDecreaseFPS("hmdLODDecreaseFPS", DEFAULT_HMD_LOD_DOWN_FPS); -Setting::Handle<int> boundaryLevelAdjust("boundaryLevelAdjust", 0); -Setting::Handle<float> octreeSizeScale("octreeSizeScale", DEFAULT_OCTREE_SIZE_SCALE); - - LODManager::LODManager() { calculateAvatarLODDistanceMultiplier(); } @@ -221,15 +217,11 @@ void LODManager::setBoundaryLevelAdjust(int boundaryLevelAdjust) { void LODManager::loadSettings() { setDesktopLODDecreaseFPS(desktopLODDecreaseFPS.get()); setHMDLODDecreaseFPS(hmdLODDecreaseFPS.get()); - setBoundaryLevelAdjust(boundaryLevelAdjust.get()); - setOctreeSizeScale(octreeSizeScale.get()); } void LODManager::saveSettings() { desktopLODDecreaseFPS.set(getDesktopLODDecreaseFPS()); hmdLODDecreaseFPS.set(getHMDLODDecreaseFPS()); - boundaryLevelAdjust.set(getBoundaryLevelAdjust()); - octreeSizeScale.set(getOctreeSizeScale()); } diff --git a/interface/src/ui/LodToolsDialog.cpp b/interface/src/ui/LodToolsDialog.cpp index 97991c62a4..378a1391f4 100644 --- a/interface/src/ui/LodToolsDialog.cpp +++ b/interface/src/ui/LodToolsDialog.cpp @@ -46,9 +46,9 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : _feedback->setFixedWidth(FEEDBACK_WIDTH); form->addRow("You can see... ", _feedback); - form->addRow("Automatic LOD Adjustment:", _automaticLODAdjust = new QCheckBox(this)); - _automaticLODAdjust->setChecked(lodManager->getAutomaticLODAdjust()); - connect(_automaticLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust())); + form->addRow("Manually Adjust Level of Detail:", _manualLODAdjust = new QCheckBox(this)); + _manualLODAdjust->setChecked(!lodManager->getAutomaticLODAdjust()); + connect(_manualLODAdjust, SIGNAL(toggled(bool)), SLOT(updateAutomaticLODAdjust())); _lodSize = new QSlider(Qt::Horizontal, this); const int MAX_LOD_SIZE = MAX_LOD_SIZE_MULTIPLIER; @@ -65,7 +65,7 @@ LodToolsDialog::LodToolsDialog(QWidget* parent) : _lodSize->setPageStep(PAGE_STEP_LOD_SIZE); int sliderValue = lodManager->getOctreeSizeScale() / TREE_SCALE; _lodSize->setValue(sliderValue); - form->addRow("Non-Avatar Content LOD:", _lodSize); + form->addRow("Level of Detail:", _lodSize); connect(_lodSize,SIGNAL(valueChanged(int)),this,SLOT(sizeScaleValueChanged(int))); // Add a button to reset @@ -86,12 +86,8 @@ void LodToolsDialog::reloadSliders() { void LodToolsDialog::updateAutomaticLODAdjust() { auto lodManager = DependencyManager::get<LODManager>(); - lodManager->setAutomaticLODAdjust(_automaticLODAdjust->isChecked()); -} - -void LodToolsDialog::updateLODValues() { - auto lodManager = DependencyManager::get<LODManager>(); - lodManager->setAutomaticLODAdjust(_automaticLODAdjust->isChecked()); + lodManager->setAutomaticLODAdjust(!_manualLODAdjust->isChecked()); + _lodSize->setEnabled(_manualLODAdjust->isChecked()); } void LodToolsDialog::sizeScaleValueChanged(int value) { @@ -106,9 +102,9 @@ void LodToolsDialog::resetClicked(bool checked) { int sliderValue = DEFAULT_OCTREE_SIZE_SCALE / TREE_SCALE; _lodSize->setValue(sliderValue); - _automaticLODAdjust->setChecked(true); + _manualLODAdjust->setChecked(false); - updateLODValues(); // tell our LOD manager about the reset + updateAutomaticLODAdjust(); // tell our LOD manager about the reset } void LodToolsDialog::reject() { @@ -119,6 +115,15 @@ void LodToolsDialog::reject() { void LodToolsDialog::closeEvent(QCloseEvent* event) { this->QDialog::closeEvent(event); emit closed(); + auto lodManager = DependencyManager::get<LODManager>(); + + // always revert back to automatic LOD adjustment when closed + lodManager->setAutomaticLODAdjust(true); + + // if the user adjusted the LOD above "normal" then always revert back to default + if (lodManager->getOctreeSizeScale() > DEFAULT_OCTREE_SIZE_SCALE) { + lodManager->setOctreeSizeScale(DEFAULT_OCTREE_SIZE_SCALE); + } } diff --git a/interface/src/ui/LodToolsDialog.h b/interface/src/ui/LodToolsDialog.h index 91be04e0ed..e5a2dae836 100644 --- a/interface/src/ui/LodToolsDialog.h +++ b/interface/src/ui/LodToolsDialog.h @@ -34,7 +34,6 @@ public slots: void resetClicked(bool checked); void reloadSliders(); void updateAutomaticLODAdjust(); - void updateLODValues(); protected: @@ -44,7 +43,7 @@ protected: private: QSlider* _lodSize; - QCheckBox* _automaticLODAdjust; + QCheckBox* _manualLODAdjust; QDoubleSpinBox* _desktopLODDecreaseFPS; From 6e3be260137bbd129d8ed3a19b4d0de5ad3d5344 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Tue, 24 Mar 2015 15:28:21 -0700 Subject: [PATCH 079/177] attempting to figure out why physics motion object doesn't get updated when collision model url changes --- .../src/RenderableModelEntityItem.cpp | 49 ++++++++++ .../src/RenderableModelEntityItem.h | 6 ++ libraries/entities/src/EntitySimulation.cpp | 10 +-- libraries/entities/src/EntitySimulation.h | 6 +- libraries/entities/src/EntityTree.cpp | 6 ++ libraries/entities/src/EntityTree.h | 4 +- libraries/entities/src/EntityTreeElement.h | 1 + libraries/entities/src/ModelEntityItem.cpp | 14 ++- libraries/entities/src/ModelEntityItem.h | 6 +- .../entities/src/SimpleEntitySimulation.cpp | 3 +- .../entities/src/SimpleEntitySimulation.h | 2 +- libraries/physics/src/EntityMotionState.cpp | 8 +- libraries/physics/src/EntityMotionState.h | 2 +- libraries/physics/src/ObjectMotionState.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 89 ++++++++++++++----- libraries/physics/src/PhysicsEngine.h | 4 +- 16 files changed, 172 insertions(+), 40 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index bb3f00d154..0a7d672189 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -22,6 +22,7 @@ #include "EntityTreeRenderer.h" #include "RenderableModelEntityItem.h" + EntityItem* RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return new RenderableModelEntityItem(entityID, properties); } @@ -266,6 +267,50 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking); } +// void RenderableModelEntityItem::setCollisionModelURL(const QString& url) { + +// // XXX PhysicsEngine::entityChangedInternal(this); +// // EntityTree* x = this->getElement()->_myTree; +// // EntityTreeRenderer* _myRenderer; + +// qDebug() << "--------------------------------"; +// this->ModelEntityItem::setCollisionModelURL(url); + +// if ((_dirtyFlags & (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS)) == +// (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS)) { + +// EntityTreeElement* element = this->getElement(); +// if (element) { +// qDebug() << "element =" << element; +// EntityTree* tree = element->getTree(); +// qDebug() << "tree =" << tree; +// tree->reconfigureEntity(this); +// } +// } +// } + + +void RenderableModelEntityItem::setCollisionModelURL(const QString& url) { + ModelEntityItem::setCollisionModelURL(url); + _model->setCollisionModelURL(QUrl(url)); +} + + +bool RenderableModelEntityItem::hasCollisionModel() const { + // return !_collisionModelURL.isEmpty(); + return ! _model->getCollisionURL().isEmpty(); +} + + +const QString& RenderableModelEntityItem::getCollisionModelURL() const { + // return _collisionModelURL; + _collisionModelURL = _model->getCollisionURL().toString(); + return _collisionModelURL; +} + + + + void RenderableModelEntityItem::updateDimensions(const glm::vec3& value) { if (glm::distance(_dimensions, value) > MIN_DIMENSIONS_DELTA) { _dimensions = value; @@ -288,6 +333,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry(); if (! collisionNetworkGeometry.isNull() && collisionNetworkGeometry->isLoadedWithTextures()) { // we have a _collisionModelURL AND a collisionNetworkGeometry AND it's fully loaded. + // _dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS); return true; } @@ -296,9 +342,12 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { } void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { + qDebug() << "RenderableModelEntityItem::computeShapeInfo"; if (_model->getCollisionURL().isEmpty()) { + qDebug() << " _model->getCollisionURL().isEmpty()"; info.setParams(getShapeType(), 0.5f * getDimensions()); } else { + qDebug() << " _model->getCollisionURL() wasn't empty."; const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry(); const FBXGeometry& fbxGeometry = collisionNetworkGeometry->getFBXGeometry(); diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 8742fb50eb..3586bd9941 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -49,9 +49,15 @@ public: void** intersectedObject, bool precisionPicking) const; Model* getModel(EntityTreeRenderer* renderer); + // virtual void setCollisionModelURL(const QString& url); bool needsToCallUpdate() const; + virtual void setCollisionModelURL(const QString& url); + virtual bool hasCollisionModel() const; + virtual const QString& getCollisionModelURL() const; + + virtual void updateDimensions(const glm::vec3& value); bool isReadyToComputeShape(); diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index b093dbe4f4..555f2061e8 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -126,11 +126,11 @@ void EntitySimulation::addEntity(EntityItem* entity) { if (entity->needsToCallUpdate()) { _updateableEntities.insert(entity); } - addEntityInternal(entity); - - // DirtyFlags are used to signal changes to entities that have already been added, - // so we can clear them for this entity which has just been added. - entity->clearDirtyFlags(); + if (addEntityInternal(entity)) { + // DirtyFlags are used to signal changes to entities that have already been added, + // so we can clear them for this entity which has just been added. + entity->clearDirtyFlags(); + } } void EntitySimulation::removeEntity(EntityItem* entity) { diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 1eb4fdc951..9dd86011fa 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -63,6 +63,10 @@ public: EntityTree* getEntityTree() { return _entityTree; } + /* virtual void reconfigureEntity(EntityItem* entity) { */ + /* qDebug() << "EntitySimulation::reconfigureEntity"; */ + /* } */ + signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); @@ -74,7 +78,7 @@ protected: // NOTE: updateEntitiesInternal() should clear all dirty flags on each changed entity as side effect virtual void updateEntitiesInternal(const quint64& now) = 0; - virtual void addEntityInternal(EntityItem* entity) = 0; + virtual bool addEntityInternal(EntityItem* entity) = 0; virtual void removeEntityInternal(EntityItem* entity) = 0; diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 3ccff46a04..da7194e4bc 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -315,6 +315,12 @@ void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs, bool force, bool i } } +void EntityTree::reconfigureEntity(EntityItem* entity) { + qDebug() << "EntityTree::reconfigureEntity"; + // _simulation->reconfigureEntity(entity); + _simulation->entityChanged(entity); +} + void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) { const RemovedEntities& entities = theOperator.getEntities(); if (_simulation) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8536e74e9a..25cc0b0bf4 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -95,7 +95,8 @@ public: void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = false); void deleteEntities(QSet<EntityItemID> entityIDs, bool force = false, bool ignoreWarnings = false); - void removeEntityFromSimulation(EntityItem* entity); + // void removeEntityFromSimulation(EntityItem* entity); + void reconfigureEntity(EntityItem* entity); /// \param position point of query in world-frame (meters) /// \param targetRadius radius of query (meters) @@ -161,6 +162,7 @@ public: void emitEntityScriptChanging(const EntityItemID& entityItemID); void setSimulation(EntitySimulation* simulation); + EntitySimulation* getSimulation() { return _simulation; } bool wantEditLogging() const { return _wantEditLogging; } void setWantEditLogging(bool value) { _wantEditLogging = value; } diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index 0b28dd30d0..e93e00cc1c 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -147,6 +147,7 @@ public: bool hasEntities() const { return _entityItems ? _entityItems->size() > 0 : false; } void setTree(EntityTree* tree) { _myTree = tree; } + EntityTree* getTree() { return _myTree; } bool updateEntity(const EntityItem& entity); void addEntityItem(EntityItem* entity); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 181f537daa..13eaf0449f 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -74,7 +74,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType); if (somethingChanged) { - bool wantDebug = false; + bool wantDebug = true; if (wantDebug) { uint64_t now = usecTimestampNow(); int elapsed = now - getLastEdited(); @@ -281,6 +281,18 @@ void ModelEntityItem::updateShapeType(ShapeType type) { } } +void ModelEntityItem::setCollisionModelURL(const QString& url) +{ + if (_collisionModelURL != url) { + + qDebug() << "\n\n----"; + qDebug() << "ModelEntityItem::setCollisionModelURL"; + + _collisionModelURL = url; + _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; + } +} + void ModelEntityItem::setAnimationURL(const QString& url) { _dirtyFlags |= EntityItem::DIRTY_UPDATEABLE; _animationURL = url; diff --git a/libraries/entities/src/ModelEntityItem.h b/libraries/entities/src/ModelEntityItem.h index 081cb429ed..9e34de445b 100644 --- a/libraries/entities/src/ModelEntityItem.h +++ b/libraries/entities/src/ModelEntityItem.h @@ -57,13 +57,13 @@ public: const rgbColor& getColor() const { return _color; } xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; } bool hasModel() const { return !_modelURL.isEmpty(); } - bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); } + virtual bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); } static const QString DEFAULT_MODEL_URL; const QString& getModelURL() const { return _modelURL; } static const QString DEFAULT_COLLISION_MODEL_URL; - const QString& getCollisionModelURL() const { return _collisionModelURL; } + virtual const QString& getCollisionModelURL() const { return _collisionModelURL; } bool hasAnimation() const { return !_animationURL.isEmpty(); } static const QString DEFAULT_ANIMATION_URL; @@ -78,7 +78,7 @@ public: // model related properties void setModelURL(const QString& url) { _modelURL = url; } - void setCollisionModelURL(const QString& url) { _collisionModelURL = url; } + virtual void setCollisionModelURL(const QString& url); void setAnimationURL(const QString& url); static const float DEFAULT_ANIMATION_FRAME_INDEX; void setAnimationFrameIndex(float value); diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index 6d45768c26..ee62c00246 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -29,12 +29,13 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { } } -void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { +bool SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { if (entity->isMoving()) { _movingEntities.insert(entity); } else if (entity->getCollisionsWillMove()) { _movableButStoppedEntities.insert(entity); } + return true; } void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index 92b6a28215..6a748c3e1f 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -23,7 +23,7 @@ public: protected: virtual void updateEntitiesInternal(const quint64& now); - virtual void addEntityInternal(EntityItem* entity); + virtual bool addEntityInternal(EntityItem* entity); virtual void removeEntityInternal(EntityItem* entity); virtual void entityChangedInternal(EntityItem* entity); virtual void clearEntitiesInternal(); diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index cd0769255b..3ca016c5d8 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -168,8 +168,12 @@ void EntityMotionState::updateObjectVelocities() { } } -void EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) { - _entity->computeShapeInfo(shapeInfo); +bool EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) { + if (_entity->isReadyToComputeShape()) { + _entity->computeShapeInfo(shapeInfo); + return true; + } + return false; } float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const { diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 7214626fc4..1910e92150 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -53,7 +53,7 @@ public: virtual void updateObjectEasy(uint32_t flags, uint32_t frame); virtual void updateObjectVelocities(); - virtual void computeShapeInfo(ShapeInfo& shapeInfo); + virtual bool computeShapeInfo(ShapeInfo& shapeInfo); virtual float computeMass(const ShapeInfo& shapeInfo) const; virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index fb402a178d..12d1d14c2d 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -67,7 +67,7 @@ public: MotionStateType getType() const { return _type; } virtual MotionType getMotionType() const { return _motionType; } - virtual void computeShapeInfo(ShapeInfo& info) = 0; + virtual bool computeShapeInfo(ShapeInfo& info) = 0; virtual float computeMass(const ShapeInfo& shapeInfo) const = 0; void setFriction(float friction); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index a46ba9f819..7dd989c9ab 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -58,31 +58,49 @@ void PhysicsEngine::updateEntitiesInternal(const quint64& now) { } } -void PhysicsEngine::addEntityInternal(EntityItem* entity) { +bool PhysicsEngine::addEntityInternal(EntityItem* entity) { + + qDebug() << "PhysicsEngine::addEntityInternal"; + assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { - if (entity->isReadyToComputeShape()) { - ShapeInfo shapeInfo; - entity->computeShapeInfo(shapeInfo); - btCollisionShape* shape = _shapeManager.getShape(shapeInfo); - if (shape) { - EntityMotionState* motionState = new EntityMotionState(entity); - entity->setPhysicsInfo(static_cast<void*>(motionState)); - _entityMotionStates.insert(motionState); - addObject(shapeInfo, shape, motionState); - } else if (entity->isMoving()) { - EntityMotionState* motionState = new EntityMotionState(entity); - entity->setPhysicsInfo(static_cast<void*>(motionState)); - _entityMotionStates.insert(motionState); - - motionState->setKinematic(true, _numSubsteps); - _nonPhysicalKinematicObjects.insert(motionState); - // We failed to add the entity to the simulation. Probably because we couldn't create a shape for it. - //qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine"; - } + qDebug() << " PhysicsEngine::addEntityInternal no physicsInfo"; + if (! entity->isReadyToComputeShape()) { + qDebug() << " PhysicsEngine::addEntityInternal not ready to compute"; + return false; } + qDebug() << " PhysicsEngine::addEntityInternal ready to compute"; + ShapeInfo shapeInfo; + entity->computeShapeInfo(shapeInfo); + + DoubleHashKey hkey = shapeInfo.getHash(); + qDebug() << " shapeInfo hash:" << hkey.getHash() << hkey.getHash2(); + + btCollisionShape* shape = _shapeManager.getShape(shapeInfo); + if (shape) { + qDebug() << " got a shape"; + EntityMotionState* motionState = new EntityMotionState(entity); + entity->setPhysicsInfo(static_cast<void*>(motionState)); + _entityMotionStates.insert(motionState); + addObject(shapeInfo, shape, motionState); + } else if (entity->isMoving()) { + qDebug() << " no shape but is moving"; + EntityMotionState* motionState = new EntityMotionState(entity); + entity->setPhysicsInfo(static_cast<void*>(motionState)); + _entityMotionStates.insert(motionState); + + motionState->setKinematic(true, _numSubsteps); + _nonPhysicalKinematicObjects.insert(motionState); + // We failed to add the entity to the simulation. Probably because we couldn't create a shape for it. + //qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine"; + } else { + qDebug() << " no shape and not moving"; + } + } else { + qDebug() << " PhysicsEngine::addEntityInternal already had physicsInfo"; } + return true; } void PhysicsEngine::removeEntityInternal(EntityItem* entity) { @@ -105,18 +123,28 @@ void PhysicsEngine::removeEntityInternal(EntityItem* entity) { } void PhysicsEngine::entityChangedInternal(EntityItem* entity) { + + qDebug() << "PhysicsEngine::entityChangedInternal"; + // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { + qDebug() << " PhysicsEngine::entityChangedInternal had physicsInfo"; ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo); _incomingChanges.insert(motionState); } else { + qDebug() << " PhysicsEngine::entityChangedInternal had no physicsInfo"; // try to add this entity again (maybe something changed such that it will work this time) addEntity(entity); } } +// void PhysicsEngine::reconfigureEntity(EntityItem* entity) { +// qDebug() << "PhysicsEngine::reconfigureEntity"; +// entityChangedInternal(entity); +// } + void PhysicsEngine::sortEntitiesThatMovedInternal() { // entities that have been simulated forward (hence in the _entitiesToBeSorted list) // also need to be put in the outgoingPackets list @@ -509,8 +537,20 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio // get new shape btCollisionShape* oldShape = body->getCollisionShape(); ShapeInfo shapeInfo; - motionState->computeShapeInfo(shapeInfo); + + + bool computeShapeInfoResult = motionState->computeShapeInfo(shapeInfo); + qDebug() << "\n\n---"; + qDebug() << "PhysicsEngine::updateObjectHard #1 computeShapeInfoResult =" << computeShapeInfoResult; + + btCollisionShape* newShape = _shapeManager.getShape(shapeInfo); + + DoubleHashKey hkey = shapeInfo.getHash(); + qDebug() << " shapeInfo hash:" << hkey.getHash() << hkey.getHash2(); + qDebug() << " newShape =" << newShape; + + if (!newShape) { // FAIL! we are unable to support these changes! _shapeManager.releaseShape(oldShape); @@ -563,7 +603,12 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio if (! (flags & EntityItem::DIRTY_MASS)) { // always update mass properties when going dynamic (unless it's already been done above) ShapeInfo shapeInfo; - motionState->computeShapeInfo(shapeInfo); + bool computeShapeInfoResult = motionState->computeShapeInfo(shapeInfo); + + qDebug() << "\n\n---"; + qDebug() << "PhysicsEngine::updateObjectHard #2 computeShapeInfoResult =" << computeShapeInfoResult; + + float mass = motionState->computeMass(shapeInfo); btVector3 inertia(0.0f, 0.0f, 0.0f); body->getCollisionShape()->calculateLocalInertia(mass, inertia); diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index cb637c60b9..68161f5c12 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -60,7 +60,7 @@ public: // overrides for EntitySimulation void updateEntitiesInternal(const quint64& now); - void addEntityInternal(EntityItem* entity); + bool addEntityInternal(EntityItem* entity); void removeEntityInternal(EntityItem* entity); void entityChangedInternal(EntityItem* entity); void sortEntitiesThatMovedInternal(); @@ -88,6 +88,8 @@ public: void setAvatarData(AvatarData *avatarData); + // virtual void reconfigureEntity(EntityItem* entity); + private: /// \param motionState pointer to Object's MotionState void removeObjectFromBullet(ObjectMotionState* motionState); From 1eeb2e89f803008a892ec93382aefbfc68e0303a Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Tue, 24 Mar 2015 16:23:51 -0700 Subject: [PATCH 080/177] remove some debug spam --- .../src/RenderableModelEntityItem.cpp | 45 ++++-------------- libraries/entities/src/ModelEntityItem.cpp | 6 +-- libraries/physics/src/EntityMotionState.cpp | 4 +- libraries/physics/src/EntityMotionState.h | 2 +- libraries/physics/src/ObjectMotionState.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 47 +------------------ 6 files changed, 15 insertions(+), 91 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 0a7d672189..88827d066c 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -267,50 +267,26 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking); } -// void RenderableModelEntityItem::setCollisionModelURL(const QString& url) { - -// // XXX PhysicsEngine::entityChangedInternal(this); -// // EntityTree* x = this->getElement()->_myTree; -// // EntityTreeRenderer* _myRenderer; - -// qDebug() << "--------------------------------"; -// this->ModelEntityItem::setCollisionModelURL(url); - -// if ((_dirtyFlags & (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS)) == -// (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS)) { - -// EntityTreeElement* element = this->getElement(); -// if (element) { -// qDebug() << "element =" << element; -// EntityTree* tree = element->getTree(); -// qDebug() << "tree =" << tree; -// tree->reconfigureEntity(this); -// } -// } -// } - - void RenderableModelEntityItem::setCollisionModelURL(const QString& url) { ModelEntityItem::setCollisionModelURL(url); - _model->setCollisionModelURL(QUrl(url)); + if (_model) { + _model->setCollisionModelURL(QUrl(url)); + } } - bool RenderableModelEntityItem::hasCollisionModel() const { - // return !_collisionModelURL.isEmpty(); - return ! _model->getCollisionURL().isEmpty(); + if (_model) { + return ! _model->getCollisionURL().isEmpty(); + } else { + return !_collisionModelURL.isEmpty(); + } } - const QString& RenderableModelEntityItem::getCollisionModelURL() const { - // return _collisionModelURL; - _collisionModelURL = _model->getCollisionURL().toString(); + assert (!_model || _collisionModelURL == _model->getCollisionURL().toString()); return _collisionModelURL; } - - - void RenderableModelEntityItem::updateDimensions(const glm::vec3& value) { if (glm::distance(_dimensions, value) > MIN_DIMENSIONS_DELTA) { _dimensions = value; @@ -342,12 +318,9 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { } void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { - qDebug() << "RenderableModelEntityItem::computeShapeInfo"; if (_model->getCollisionURL().isEmpty()) { - qDebug() << " _model->getCollisionURL().isEmpty()"; info.setParams(getShapeType(), 0.5f * getDimensions()); } else { - qDebug() << " _model->getCollisionURL() wasn't empty."; const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry(); const FBXGeometry& fbxGeometry = collisionNetworkGeometry->getFBXGeometry(); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index 13eaf0449f..f135f617f4 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -74,7 +74,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType); if (somethingChanged) { - bool wantDebug = true; + bool wantDebug = false; if (wantDebug) { uint64_t now = usecTimestampNow(); int elapsed = now - getLastEdited(); @@ -284,10 +284,6 @@ void ModelEntityItem::updateShapeType(ShapeType type) { void ModelEntityItem::setCollisionModelURL(const QString& url) { if (_collisionModelURL != url) { - - qDebug() << "\n\n----"; - qDebug() << "ModelEntityItem::setCollisionModelURL"; - _collisionModelURL = url; _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; } diff --git a/libraries/physics/src/EntityMotionState.cpp b/libraries/physics/src/EntityMotionState.cpp index 3ca016c5d8..35eb006655 100644 --- a/libraries/physics/src/EntityMotionState.cpp +++ b/libraries/physics/src/EntityMotionState.cpp @@ -168,12 +168,10 @@ void EntityMotionState::updateObjectVelocities() { } } -bool EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) { +void EntityMotionState::computeShapeInfo(ShapeInfo& shapeInfo) { if (_entity->isReadyToComputeShape()) { _entity->computeShapeInfo(shapeInfo); - return true; } - return false; } float EntityMotionState::computeMass(const ShapeInfo& shapeInfo) const { diff --git a/libraries/physics/src/EntityMotionState.h b/libraries/physics/src/EntityMotionState.h index 1910e92150..7214626fc4 100644 --- a/libraries/physics/src/EntityMotionState.h +++ b/libraries/physics/src/EntityMotionState.h @@ -53,7 +53,7 @@ public: virtual void updateObjectEasy(uint32_t flags, uint32_t frame); virtual void updateObjectVelocities(); - virtual bool computeShapeInfo(ShapeInfo& shapeInfo); + virtual void computeShapeInfo(ShapeInfo& shapeInfo); virtual float computeMass(const ShapeInfo& shapeInfo) const; virtual void sendUpdate(OctreeEditPacketSender* packetSender, uint32_t frame); diff --git a/libraries/physics/src/ObjectMotionState.h b/libraries/physics/src/ObjectMotionState.h index 12d1d14c2d..fb402a178d 100644 --- a/libraries/physics/src/ObjectMotionState.h +++ b/libraries/physics/src/ObjectMotionState.h @@ -67,7 +67,7 @@ public: MotionStateType getType() const { return _type; } virtual MotionType getMotionType() const { return _motionType; } - virtual bool computeShapeInfo(ShapeInfo& info) = 0; + virtual void computeShapeInfo(ShapeInfo& info) = 0; virtual float computeMass(const ShapeInfo& shapeInfo) const = 0; void setFriction(float friction); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 7dd989c9ab..5f668b4f37 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -59,33 +59,21 @@ void PhysicsEngine::updateEntitiesInternal(const quint64& now) { } bool PhysicsEngine::addEntityInternal(EntityItem* entity) { - - qDebug() << "PhysicsEngine::addEntityInternal"; - assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { - qDebug() << " PhysicsEngine::addEntityInternal no physicsInfo"; if (! entity->isReadyToComputeShape()) { - qDebug() << " PhysicsEngine::addEntityInternal not ready to compute"; return false; } - qDebug() << " PhysicsEngine::addEntityInternal ready to compute"; ShapeInfo shapeInfo; entity->computeShapeInfo(shapeInfo); - - DoubleHashKey hkey = shapeInfo.getHash(); - qDebug() << " shapeInfo hash:" << hkey.getHash() << hkey.getHash2(); - btCollisionShape* shape = _shapeManager.getShape(shapeInfo); if (shape) { - qDebug() << " got a shape"; EntityMotionState* motionState = new EntityMotionState(entity); entity->setPhysicsInfo(static_cast<void*>(motionState)); _entityMotionStates.insert(motionState); addObject(shapeInfo, shape, motionState); } else if (entity->isMoving()) { - qDebug() << " no shape but is moving"; EntityMotionState* motionState = new EntityMotionState(entity); entity->setPhysicsInfo(static_cast<void*>(motionState)); _entityMotionStates.insert(motionState); @@ -94,11 +82,7 @@ bool PhysicsEngine::addEntityInternal(EntityItem* entity) { _nonPhysicalKinematicObjects.insert(motionState); // We failed to add the entity to the simulation. Probably because we couldn't create a shape for it. //qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine"; - } else { - qDebug() << " no shape and not moving"; } - } else { - qDebug() << " PhysicsEngine::addEntityInternal already had physicsInfo"; } return true; } @@ -123,28 +107,18 @@ void PhysicsEngine::removeEntityInternal(EntityItem* entity) { } void PhysicsEngine::entityChangedInternal(EntityItem* entity) { - - qDebug() << "PhysicsEngine::entityChangedInternal"; - // queue incoming changes: from external sources (script, EntityServer, etc) to physics engine assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (physicsInfo) { - qDebug() << " PhysicsEngine::entityChangedInternal had physicsInfo"; ObjectMotionState* motionState = static_cast<ObjectMotionState*>(physicsInfo); _incomingChanges.insert(motionState); } else { - qDebug() << " PhysicsEngine::entityChangedInternal had no physicsInfo"; // try to add this entity again (maybe something changed such that it will work this time) addEntity(entity); } } -// void PhysicsEngine::reconfigureEntity(EntityItem* entity) { -// qDebug() << "PhysicsEngine::reconfigureEntity"; -// entityChangedInternal(entity); -// } - void PhysicsEngine::sortEntitiesThatMovedInternal() { // entities that have been simulated forward (hence in the _entitiesToBeSorted list) // also need to be put in the outgoingPackets list @@ -537,20 +511,8 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio // get new shape btCollisionShape* oldShape = body->getCollisionShape(); ShapeInfo shapeInfo; - - - bool computeShapeInfoResult = motionState->computeShapeInfo(shapeInfo); - qDebug() << "\n\n---"; - qDebug() << "PhysicsEngine::updateObjectHard #1 computeShapeInfoResult =" << computeShapeInfoResult; - - + motionState->computeShapeInfo(shapeInfo); btCollisionShape* newShape = _shapeManager.getShape(shapeInfo); - - DoubleHashKey hkey = shapeInfo.getHash(); - qDebug() << " shapeInfo hash:" << hkey.getHash() << hkey.getHash2(); - qDebug() << " newShape =" << newShape; - - if (!newShape) { // FAIL! we are unable to support these changes! _shapeManager.releaseShape(oldShape); @@ -603,12 +565,7 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio if (! (flags & EntityItem::DIRTY_MASS)) { // always update mass properties when going dynamic (unless it's already been done above) ShapeInfo shapeInfo; - bool computeShapeInfoResult = motionState->computeShapeInfo(shapeInfo); - - qDebug() << "\n\n---"; - qDebug() << "PhysicsEngine::updateObjectHard #2 computeShapeInfoResult =" << computeShapeInfoResult; - - + motionState->computeShapeInfo(shapeInfo); float mass = motionState->computeMass(shapeInfo); btVector3 inertia(0.0f, 0.0f, 0.0f); body->getCollisionShape()->calculateLocalInertia(mass, inertia); From 8d2c9425096a9d09768d2fed747738557ad087de Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Tue, 24 Mar 2015 16:38:11 -0700 Subject: [PATCH 081/177] diff minimization --- .../src/RenderableModelEntityItem.cpp | 7 ------- .../entities-renderer/src/RenderableModelEntityItem.h | 2 -- libraries/entities/src/EntitySimulation.cpp | 10 +++++----- libraries/entities/src/EntitySimulation.h | 2 +- libraries/entities/src/SimpleEntitySimulation.cpp | 3 +-- libraries/entities/src/SimpleEntitySimulation.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 6 +++--- libraries/physics/src/PhysicsEngine.h | 2 +- 8 files changed, 12 insertions(+), 22 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 88827d066c..025da1d285 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -22,7 +22,6 @@ #include "EntityTreeRenderer.h" #include "RenderableModelEntityItem.h" - EntityItem* RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { return new RenderableModelEntityItem(entityID, properties); } @@ -309,7 +308,6 @@ bool RenderableModelEntityItem::isReadyToComputeShape() { const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry(); if (! collisionNetworkGeometry.isNull() && collisionNetworkGeometry->isLoadedWithTextures()) { // we have a _collisionModelURL AND a collisionNetworkGeometry AND it's fully loaded. - // _dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS); return true; } @@ -342,11 +340,6 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { assert(p1Index < (unsigned int)mesh.vertices.size()); assert(p2Index < (unsigned int)mesh.vertices.size()); - // glm::vec3 p0 = mesh.vertices[p0Index] * scale[0]; - // glm::vec3 p1 = mesh.vertices[p1Index] * scale[1]; - // glm::vec3 p2 = mesh.vertices[p2Index] * scale[2]; - - glm::vec3 p0 = mesh.vertices[p0Index]; glm::vec3 p1 = mesh.vertices[p1Index]; glm::vec3 p2 = mesh.vertices[p2Index]; diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 3586bd9941..90535954b4 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -49,7 +49,6 @@ public: void** intersectedObject, bool precisionPicking) const; Model* getModel(EntityTreeRenderer* renderer); - // virtual void setCollisionModelURL(const QString& url); bool needsToCallUpdate() const; @@ -57,7 +56,6 @@ public: virtual bool hasCollisionModel() const; virtual const QString& getCollisionModelURL() const; - virtual void updateDimensions(const glm::vec3& value); bool isReadyToComputeShape(); diff --git a/libraries/entities/src/EntitySimulation.cpp b/libraries/entities/src/EntitySimulation.cpp index 555f2061e8..b093dbe4f4 100644 --- a/libraries/entities/src/EntitySimulation.cpp +++ b/libraries/entities/src/EntitySimulation.cpp @@ -126,11 +126,11 @@ void EntitySimulation::addEntity(EntityItem* entity) { if (entity->needsToCallUpdate()) { _updateableEntities.insert(entity); } - if (addEntityInternal(entity)) { - // DirtyFlags are used to signal changes to entities that have already been added, - // so we can clear them for this entity which has just been added. - entity->clearDirtyFlags(); - } + addEntityInternal(entity); + + // DirtyFlags are used to signal changes to entities that have already been added, + // so we can clear them for this entity which has just been added. + entity->clearDirtyFlags(); } void EntitySimulation::removeEntity(EntityItem* entity) { diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 9dd86011fa..68b42e5ac9 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -78,7 +78,7 @@ protected: // NOTE: updateEntitiesInternal() should clear all dirty flags on each changed entity as side effect virtual void updateEntitiesInternal(const quint64& now) = 0; - virtual bool addEntityInternal(EntityItem* entity) = 0; + virtual void addEntityInternal(EntityItem* entity) = 0; virtual void removeEntityInternal(EntityItem* entity) = 0; diff --git a/libraries/entities/src/SimpleEntitySimulation.cpp b/libraries/entities/src/SimpleEntitySimulation.cpp index ee62c00246..6d45768c26 100644 --- a/libraries/entities/src/SimpleEntitySimulation.cpp +++ b/libraries/entities/src/SimpleEntitySimulation.cpp @@ -29,13 +29,12 @@ void SimpleEntitySimulation::updateEntitiesInternal(const quint64& now) { } } -bool SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { +void SimpleEntitySimulation::addEntityInternal(EntityItem* entity) { if (entity->isMoving()) { _movingEntities.insert(entity); } else if (entity->getCollisionsWillMove()) { _movableButStoppedEntities.insert(entity); } - return true; } void SimpleEntitySimulation::removeEntityInternal(EntityItem* entity) { diff --git a/libraries/entities/src/SimpleEntitySimulation.h b/libraries/entities/src/SimpleEntitySimulation.h index 6a748c3e1f..92b6a28215 100644 --- a/libraries/entities/src/SimpleEntitySimulation.h +++ b/libraries/entities/src/SimpleEntitySimulation.h @@ -23,7 +23,7 @@ public: protected: virtual void updateEntitiesInternal(const quint64& now); - virtual bool addEntityInternal(EntityItem* entity); + virtual void addEntityInternal(EntityItem* entity); virtual void removeEntityInternal(EntityItem* entity); virtual void entityChangedInternal(EntityItem* entity); virtual void clearEntitiesInternal(); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 5f668b4f37..37b7035101 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -58,12 +58,12 @@ void PhysicsEngine::updateEntitiesInternal(const quint64& now) { } } -bool PhysicsEngine::addEntityInternal(EntityItem* entity) { +void PhysicsEngine::addEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { if (! entity->isReadyToComputeShape()) { - return false; + return; } ShapeInfo shapeInfo; entity->computeShapeInfo(shapeInfo); @@ -84,7 +84,7 @@ bool PhysicsEngine::addEntityInternal(EntityItem* entity) { //qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine"; } } - return true; + return; } void PhysicsEngine::removeEntityInternal(EntityItem* entity) { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index 68161f5c12..a8c9edf2f8 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -60,7 +60,7 @@ public: // overrides for EntitySimulation void updateEntitiesInternal(const quint64& now); - bool addEntityInternal(EntityItem* entity); + void addEntityInternal(EntityItem* entity); void removeEntityInternal(EntityItem* entity); void entityChangedInternal(EntityItem* entity); void sortEntitiesThatMovedInternal(); From 0e441261069f5b009931ec4c9d8ddaa7dbe0e74a Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Tue, 24 Mar 2015 16:38:13 -0700 Subject: [PATCH 082/177] added LOD Warnings to notifications.js --- examples/defaultScripts.js | 1 - examples/hmdDefaults.js | 1 - examples/notifications.js | 36 ++++++++-- examples/utilities/LODWarning.js | 115 ------------------------------- 4 files changed, 31 insertions(+), 122 deletions(-) delete mode 100644 examples/utilities/LODWarning.js diff --git a/examples/defaultScripts.js b/examples/defaultScripts.js index f52d6be87e..05ffb0bd3f 100644 --- a/examples/defaultScripts.js +++ b/examples/defaultScripts.js @@ -18,4 +18,3 @@ Script.load("lobby.js"); Script.load("notifications.js"); Script.load("look.js"); Script.load("users.js"); -Script.load("utilities/LODWarning.js"); diff --git a/examples/hmdDefaults.js b/examples/hmdDefaults.js index 1e96d41713..0096b11777 100644 --- a/examples/hmdDefaults.js +++ b/examples/hmdDefaults.js @@ -13,5 +13,4 @@ Script.load("progress.js"); Script.load("lobby.js"); Script.load("notifications.js"); Script.load("controllers/oculus/goTo.js"); -Script.load("utilities/LODWarning.js"); //Script.load("scripts.js"); // Not created yet diff --git a/examples/notifications.js b/examples/notifications.js index 0c2a06c878..7e56c1b50d 100644 --- a/examples/notifications.js +++ b/examples/notifications.js @@ -43,7 +43,6 @@ // after that we will send it to createNotification(text). // If the message is 42 chars or less you should bypass wordWrap() and call createNotification() directly. - // To add a keypress driven notification: // // 1. Add a key to the keyPressEvent(key). @@ -85,16 +84,19 @@ var PLAY_NOTIFICATION_SOUNDS_MENU_ITEM = "Play Notification Sounds"; var NOTIFICATION_MENU_ITEM_POST = " Notifications"; var PLAY_NOTIFICATION_SOUNDS_SETTING = "play_notification_sounds"; var PLAY_NOTIFICATION_SOUNDS_TYPE_SETTING_PRE = "play_notification_sounds_type_"; +var lodTextID = false; var NotificationType = { UNKNOWN: 0, MUTE_TOGGLE: 1, SNAPSHOT: 2, WINDOW_RESIZE: 3, + LOD_WARNING: 4, properties: [ { text: "Mute Toggle" }, { text: "Snapshot" }, - { text: "Window Resize" } + { text: "Window Resize" }, + { text: "Level of Detail" } ], getTypeFromMenuItem: function(menuItemName) { if (menuItemName.substr(menuItemName.length - NOTIFICATION_MENU_ITEM_POST.length) !== NOTIFICATION_MENU_ITEM_POST) { @@ -143,6 +145,10 @@ function createArrays(notice, button, createTime, height, myAlpha) { // This handles the final dismissal of a notification after fading function dismiss(firstNoteOut, firstButOut, firstOut) { + if (firstNoteOut == lodTextID) { + lodTextID = false; + } + Overlays.deleteOverlay(firstNoteOut); Overlays.deleteOverlay(firstButOut); notifications.splice(firstOut, 1); @@ -261,7 +267,8 @@ function notify(notice, button, height) { height: noticeHeight }); } else { - notifications.push((Overlays.addOverlay("text", notice))); + var notificationText = Overlays.addOverlay("text", notice); + notifications.push((notificationText)); buttons.push((Overlays.addOverlay("image", button))); } @@ -272,6 +279,7 @@ function notify(notice, button, height) { last = notifications.length - 1; createArrays(notifications[last], buttons[last], times[last], heights[last], myAlpha[last]); fadeIn(notifications[last], buttons[last]); + return notificationText; } // This function creates and sizes the overlays @@ -331,11 +339,15 @@ function createNotification(text, notificationType) { randomSounds.playRandom(); } - notify(noticeProperties, buttonProperties, height); + return notify(noticeProperties, buttonProperties, height); } function deleteNotification(index) { - Overlays.deleteOverlay(notifications[index]); + var notificationTextID = notifications[index]; + if (notificationTextID == lodTextID) { + lodTextID = false; + } + Overlays.deleteOverlay(notificationTextID); Overlays.deleteOverlay(buttons[index]); notifications.splice(index, 1); buttons.splice(index, 1); @@ -575,6 +587,20 @@ function menuItemEvent(menuItem) { } } +LODManager.LODDecreased.connect(function() { + var warningText = "\n" + + "Due to the complexity of the content, the \n" + + "level of detail has been decreased." + + "You can now see: \n" + + LODManager.getLODFeedbackText(); + + if (lodTextID == false) { + lodTextID = createNotification(warningText, NotificationType.LOD_WARNING); + } else { + Overlays.editOverlay(lodTextID, { text: warningText }); + } +}); + AudioDevice.muteToggled.connect(onMuteStateChanged); Controller.keyPressEvent.connect(keyPressEvent); Controller.mousePressEvent.connect(mousePressEvent); diff --git a/examples/utilities/LODWarning.js b/examples/utilities/LODWarning.js deleted file mode 100644 index 644d98ebf4..0000000000 --- a/examples/utilities/LODWarning.js +++ /dev/null @@ -1,115 +0,0 @@ -// LODWarning.js -// examples -// -// Created by Brad Hefta-Gaub on 3/17/15. -// Copyright 2015 High Fidelity, Inc. -// -// This script will display a warning when the LOD is adjusted to do scene complexity. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -var DISPLAY_WARNING_FOR = 3; // in seconds -var DISTANCE_FROM_CAMERA = 2; -var SHOW_LOD_UP_MESSAGE = false; // By default we only display the LOD message when reducing LOD - - -var warningIsVisible = false; // initially the warning is hidden -var warningShownAt = 0; -var billboardPosition = Vec3.sum(Camera.getPosition(), - Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation()))); - -var warningOverlay = Overlays.addOverlay("text3d", { - position: billboardPosition, - dimensions: { x: 2, y: 1.25 }, - width: 2, - height: 1.25, - backgroundColor: { red: 0, green: 0, blue: 0 }, - color: { red: 255, green: 255, blue: 255}, - topMargin: 0.1, - leftMargin: 0.1, - lineHeight: 0.07, - text: "", - alpha: 0.5, - backgroundAlpha: 0.7, - isFacingAvatar: true, - visible: warningIsVisible, - }); - -// Handle moving the billboard to remain in front of the camera -var billboardNeedsMoving = false; -Script.update.connect(function() { - - if (warningIsVisible) { - var bestBillboardPosition = Vec3.sum(Camera.getPosition(), - Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation()))); - - var MAX_DISTANCE = 0.5; - var CLOSE_ENOUGH = 0.01; - if (!billboardNeedsMoving && Vec3.distance(bestBillboardPosition, billboardPosition) > MAX_DISTANCE) { - billboardNeedsMoving = true; - } - - if (billboardNeedsMoving && Vec3.distance(bestBillboardPosition, billboardPosition) <= CLOSE_ENOUGH) { - billboardNeedsMoving = false; - } - - if (billboardNeedsMoving) { - // slurp the billboard to the best location - moveVector = Vec3.multiply(0.05, Vec3.subtract(bestBillboardPosition, billboardPosition)); - billboardPosition = Vec3.sum(billboardPosition, moveVector); - Overlays.editOverlay(warningOverlay, { position: billboardPosition }); - } - - var now = new Date(); - var sinceWarningShown = now - warningShownAt; - if (sinceWarningShown > 1000 * DISPLAY_WARNING_FOR) { - warningIsVisible = false; - Overlays.editOverlay(warningOverlay, { visible: warningIsVisible }); - } - } -}); - -LODManager.LODIncreased.connect(function() { - if (SHOW_LOD_UP_MESSAGE) { - // if the warning wasn't visible, then move it before showing it. - if (!warningIsVisible) { - billboardPosition = Vec3.sum(Camera.getPosition(), - Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation()))); - Overlays.editOverlay(warningOverlay, { position: billboardPosition }); - } - - warningShownAt = new Date(); - warningIsVisible = true; - warningText = "Level of detail has been increased. \n" - + "You can now see: \n" - + LODManager.getLODFeedbackText(); - - Overlays.editOverlay(warningOverlay, { visible: warningIsVisible, text: warningText }); - } -}); - -LODManager.LODDecreased.connect(function() { - // if the warning wasn't visible, then move it before showing it. - if (!warningIsVisible) { - billboardPosition = Vec3.sum(Camera.getPosition(), - Vec3.multiply(DISTANCE_FROM_CAMERA, Quat.getFront(Camera.getOrientation()))); - Overlays.editOverlay(warningOverlay, { position: billboardPosition }); - } - - warningShownAt = new Date(); - warningIsVisible = true; - warningText = "\n" - + "Due to the complexity of the content, the \n" - + "level of detail has been decreased. \n" - + "You can now see: \n" - + LODManager.getLODFeedbackText(); - - Overlays.editOverlay(warningOverlay, { visible: warningIsVisible, text: warningText }); -}); - - -Script.scriptEnding.connect(function() { - Overlays.deleteOverlay(warningOverlay); -}); \ No newline at end of file From 2f47f7c7bad1361fd5a7884827ba20b31105f9cd Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Tue, 24 Mar 2015 16:51:42 -0700 Subject: [PATCH 083/177] diff minimization --- .../src/RenderableModelEntityItem.cpp | 1 - libraries/entities/src/EntitySimulation.h | 4 -- libraries/entities/src/EntityTree.cpp | 6 --- libraries/entities/src/EntityTree.h | 3 -- libraries/entities/src/EntityTreeElement.h | 1 - libraries/physics/src/PhysicsEngine.cpp | 38 +++++++++---------- libraries/physics/src/PhysicsEngine.h | 2 - 7 files changed, 18 insertions(+), 37 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 025da1d285..aab9786762 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -369,7 +369,6 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { glm::vec3 aaBoxDim = aaBox.getDimensions(); aaBoxDim = glm::clamp(aaBoxDim, glm::vec3(FLT_EPSILON), aaBoxDim); - // scale = dimensions / aabox glm::vec3 scale = _dimensions / aaBoxDim; // multiply each point by scale before handing the point-set off to the physics engine diff --git a/libraries/entities/src/EntitySimulation.h b/libraries/entities/src/EntitySimulation.h index 68b42e5ac9..1eb4fdc951 100644 --- a/libraries/entities/src/EntitySimulation.h +++ b/libraries/entities/src/EntitySimulation.h @@ -63,10 +63,6 @@ public: EntityTree* getEntityTree() { return _entityTree; } - /* virtual void reconfigureEntity(EntityItem* entity) { */ - /* qDebug() << "EntitySimulation::reconfigureEntity"; */ - /* } */ - signals: void entityCollisionWithEntity(const EntityItemID& idA, const EntityItemID& idB, const Collision& collision); diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index da7194e4bc..3ccff46a04 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -315,12 +315,6 @@ void EntityTree::deleteEntities(QSet<EntityItemID> entityIDs, bool force, bool i } } -void EntityTree::reconfigureEntity(EntityItem* entity) { - qDebug() << "EntityTree::reconfigureEntity"; - // _simulation->reconfigureEntity(entity); - _simulation->entityChanged(entity); -} - void EntityTree::processRemovedEntities(const DeleteEntityOperator& theOperator) { const RemovedEntities& entities = theOperator.getEntities(); if (_simulation) { diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 25cc0b0bf4..29fecc88b4 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -95,8 +95,6 @@ public: void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = false); void deleteEntities(QSet<EntityItemID> entityIDs, bool force = false, bool ignoreWarnings = false); - // void removeEntityFromSimulation(EntityItem* entity); - void reconfigureEntity(EntityItem* entity); /// \param position point of query in world-frame (meters) /// \param targetRadius radius of query (meters) @@ -162,7 +160,6 @@ public: void emitEntityScriptChanging(const EntityItemID& entityItemID); void setSimulation(EntitySimulation* simulation); - EntitySimulation* getSimulation() { return _simulation; } bool wantEditLogging() const { return _wantEditLogging; } void setWantEditLogging(bool value) { _wantEditLogging = value; } diff --git a/libraries/entities/src/EntityTreeElement.h b/libraries/entities/src/EntityTreeElement.h index e93e00cc1c..0b28dd30d0 100644 --- a/libraries/entities/src/EntityTreeElement.h +++ b/libraries/entities/src/EntityTreeElement.h @@ -147,7 +147,6 @@ public: bool hasEntities() const { return _entityItems ? _entityItems->size() > 0 : false; } void setTree(EntityTree* tree) { _myTree = tree; } - EntityTree* getTree() { return _myTree; } bool updateEntity(const EntityItem& entity); void addEntityItem(EntityItem* entity); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 37b7035101..a46ba9f819 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -62,29 +62,27 @@ void PhysicsEngine::addEntityInternal(EntityItem* entity) { assert(entity); void* physicsInfo = entity->getPhysicsInfo(); if (!physicsInfo) { - if (! entity->isReadyToComputeShape()) { - return; - } - ShapeInfo shapeInfo; - entity->computeShapeInfo(shapeInfo); - btCollisionShape* shape = _shapeManager.getShape(shapeInfo); - if (shape) { - EntityMotionState* motionState = new EntityMotionState(entity); - entity->setPhysicsInfo(static_cast<void*>(motionState)); - _entityMotionStates.insert(motionState); - addObject(shapeInfo, shape, motionState); - } else if (entity->isMoving()) { - EntityMotionState* motionState = new EntityMotionState(entity); - entity->setPhysicsInfo(static_cast<void*>(motionState)); - _entityMotionStates.insert(motionState); + if (entity->isReadyToComputeShape()) { + ShapeInfo shapeInfo; + entity->computeShapeInfo(shapeInfo); + btCollisionShape* shape = _shapeManager.getShape(shapeInfo); + if (shape) { + EntityMotionState* motionState = new EntityMotionState(entity); + entity->setPhysicsInfo(static_cast<void*>(motionState)); + _entityMotionStates.insert(motionState); + addObject(shapeInfo, shape, motionState); + } else if (entity->isMoving()) { + EntityMotionState* motionState = new EntityMotionState(entity); + entity->setPhysicsInfo(static_cast<void*>(motionState)); + _entityMotionStates.insert(motionState); - motionState->setKinematic(true, _numSubsteps); - _nonPhysicalKinematicObjects.insert(motionState); - // We failed to add the entity to the simulation. Probably because we couldn't create a shape for it. - //qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine"; + motionState->setKinematic(true, _numSubsteps); + _nonPhysicalKinematicObjects.insert(motionState); + // We failed to add the entity to the simulation. Probably because we couldn't create a shape for it. + //qDebug() << "failed to add entity " << entity->getEntityItemID() << " to physics engine"; + } } } - return; } void PhysicsEngine::removeEntityInternal(EntityItem* entity) { diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index a8c9edf2f8..cb637c60b9 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -88,8 +88,6 @@ public: void setAvatarData(AvatarData *avatarData); - // virtual void reconfigureEntity(EntityItem* entity); - private: /// \param motionState pointer to Object's MotionState void removeObjectFromBullet(ObjectMotionState* motionState); From dccedeadff030cd721caae413bca87804141b33e Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Tue, 24 Mar 2015 16:59:12 -0700 Subject: [PATCH 084/177] diff minimization --- .../src/RenderableModelEntityItem.cpp | 8 -------- .../entities-renderer/src/RenderableModelEntityItem.h | 2 -- libraries/entities/src/EntityItem.h | 11 +---------- 3 files changed, 1 insertion(+), 20 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index aab9786762..43dbb95b6d 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -286,14 +286,6 @@ const QString& RenderableModelEntityItem::getCollisionModelURL() const { return _collisionModelURL; } -void RenderableModelEntityItem::updateDimensions(const glm::vec3& value) { - if (glm::distance(_dimensions, value) > MIN_DIMENSIONS_DELTA) { - _dimensions = value; - _dirtyFlags |= (EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS); - } - _model->setScaleToFit(true, _dimensions); -} - bool RenderableModelEntityItem::isReadyToComputeShape() { if (!_model) { diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.h b/libraries/entities-renderer/src/RenderableModelEntityItem.h index 90535954b4..9146a04cf8 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.h +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.h @@ -56,8 +56,6 @@ public: virtual bool hasCollisionModel() const; virtual const QString& getCollisionModelURL() const; - virtual void updateDimensions(const glm::vec3& value); - bool isReadyToComputeShape(); void computeShapeInfo(ShapeInfo& info); ShapeType getShapeType() const; diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 49e450c45e..88287f8965 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -40,15 +40,6 @@ class EntityTreeElementExtraEncodeData; #define debugTreeVector(V) V << "[" << V << " in meters ]" -extern const float MIN_POSITION_DELTA; -extern const float MIN_DIMENSIONS_DELTA; -extern const float MIN_ALIGNMENT_DOT; -extern const float MIN_VELOCITY_DELTA; -extern const float MIN_DAMPING_DELTA; -extern const float MIN_GRAVITY_DELTA; -extern const float MIN_SPIN_DELTA; - - /// EntityItem class this is the base class for all entity types. It handles the basic properties and functionality available /// to all other entity types. In particular: postion, size, rotation, age, lifetime, velocity, gravity. You can not instantiate /// one directly, instead you must only construct one of it's derived classes with additional features. @@ -279,7 +270,7 @@ public: void updatePositionInDomainUnits(const glm::vec3& value); void updatePosition(const glm::vec3& value); void updateDimensionsInDomainUnits(const glm::vec3& value); - virtual void updateDimensions(const glm::vec3& value); + void updateDimensions(const glm::vec3& value); void updateRotation(const glm::quat& rotation); void updateDensity(float value); void updateMass(float value); From 44eca08fa488bf653dd06dd10f51ea798323385e Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 24 Mar 2015 17:38:35 -0700 Subject: [PATCH 085/177] PhysicsEngine doesn't need AvatarData MyAvatar now owns its CharacterController fix for bug of phantom collision obj when avatar's physics are disabled --- interface/src/Application.cpp | 7 +- interface/src/avatar/MyAvatar.cpp | 14 +- interface/src/avatar/MyAvatar.h | 11 + libraries/avatars/src/AvatarData.h | 13 - libraries/physics/src/CharacterController.cpp | 229 +++++++++++------- libraries/physics/src/CharacterController.h | 16 +- libraries/physics/src/PhysicsEngine.cpp | 43 +--- libraries/physics/src/PhysicsEngine.h | 4 +- 8 files changed, 197 insertions(+), 140 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 4ff41e1b6f..418407282c 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -1903,8 +1903,6 @@ void Application::init() { _physicsEngine.init(&_entityEditSender); - _physicsEngine.setAvatarData(_myAvatar); - auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>(); connect(&_physicsEngine, &EntitySimulation::entityCollisionWithEntity, @@ -2191,6 +2189,7 @@ void Application::update(float deltaTime) { { PerformanceTimer perfTimer("physics"); + _myAvatar->preSimulation(); _physicsEngine.stepSimulation(); } @@ -4207,7 +4206,7 @@ void Application::checkSkeleton() { _myAvatar->setSkeletonModelURL(DEFAULT_BODY_MODEL_URL); _myAvatar->sendIdentityPacket(); } else { - _myAvatar->updateLocalAABox(); - _physicsEngine.setAvatarData(_myAvatar); + _myAvatar->updateCharacterController(); + _physicsEngine.setCharacterController(_myAvatar->getCharacterController()); } } diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index ab4989a651..e0de24247e 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -82,6 +82,8 @@ MyAvatar::MyAvatar() : _scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME), _motionBehaviors(AVATAR_MOTION_DEFAULTS), + _characterController(this), + _enablePhysics(false), _lookAtTargetAvatar(), _shouldRender(true), _billboardValid(false), @@ -954,15 +956,15 @@ glm::vec3 MyAvatar::getSkeletonPosition() const { return Avatar::getPosition(); } -void MyAvatar::updateLocalAABox() { +void MyAvatar::updateCharacterController() { + // compute localAABox const CapsuleShape& capsule = _skeletonModel.getBoundingShape(); float radius = capsule.getRadius(); float height = 2.0f * (capsule.getHalfHeight() + radius); - glm::vec3 offset = _skeletonModel.getBoundingShapeOffset(); glm::vec3 corner(-radius, -0.5f * height, -radius); - corner += offset; + corner += _skeletonModel.getBoundingShapeOffset(); glm::vec3 scale(2.0f * radius, height, 2.0f * radius); - _localAABox.setBox(corner, scale); + _characterController.setLocalBoundingBox(corner, scale); } QString MyAvatar::getScriptedMotorFrame() const { @@ -1580,6 +1582,10 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { return palm->getPosition(); } +void MyAvatar::preSimulation() { + _characterController.setEnabled(_enablePhysics); +} + void MyAvatar::clearDriveKeys() { for (int i = 0; i < MAX_DRIVE_KEYS; ++i) { _driveKeys[i] = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 08c0228f1e..1b2b2f5e46 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -13,6 +13,7 @@ #define hifi_MyAvatar_h #include <SettingHandle.h> +#include <CharacterController.h> #include "Avatar.h" @@ -122,6 +123,8 @@ public: virtual glm::vec3 getSkeletonPosition() const; void updateLocalAABox(); + CharacterController* getCharacterController() { return &_characterController; } + void updateCharacterController(); void clearJointAnimationPriorities(); @@ -145,6 +148,11 @@ public: const RecorderPointer getRecorder() const { return _recorder; } const PlayerPointer getPlayer() const { return _player; } + + void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; } + bool isPhysicsEnabled() { return _enablePhysics; } + void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; } + void preSimulation(); public slots: void increaseSize(); @@ -202,6 +210,9 @@ private: int _scriptedMotorFrame; quint32 _motionBehaviors; + bool _enablePhysics; + CharacterController _characterController; + QWeakPointer<AvatarData> _lookAtTargetAvatar; glm::vec3 _targetAvatarPosition; bool _shouldRender; diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index 28123124a0..a2feb98798 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -300,16 +300,6 @@ public: const AABox& getLocalAABox() const { return _localAABox; } const Referential* getReferential() const { return _referential; } - void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; } - bool isPhysicsEnabled() { return _enablePhysics; } - void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; } - - void lockForRead() { _lock.lockForRead(); } - bool tryLockForRead() { return _lock.tryLockForRead(); } - void lockForWrite() { _lock.lockForWrite(); } - bool tryLockForWrite() { return _lock.tryLockForWrite(); } - void unlock() { _lock.unlock(); } - void setVelocity(const glm::vec3 velocity) { _velocity = velocity; } Q_INVOKABLE glm::vec3 getVelocity() const { return _velocity; } @@ -409,9 +399,6 @@ private: // privatize the copy constructor and assignment operator so they cannot be called AvatarData(const AvatarData&); AvatarData& operator= (const AvatarData&); - - QReadWriteLock _lock; - bool _enablePhysics = false; }; Q_DECLARE_METATYPE(AvatarData*) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index d0b083fc01..be10cd1f54 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -21,6 +21,12 @@ subject to the following restrictions: #include "BulletUtil.h" #include "CharacterController.h" +const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0; +const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1; +//const uint32_t PENDING_FLAG_ENABLE = 1U << 0; +//const uint32_t PENDING_FLAG_DISABLE = 1U << 1; +const uint32_t PENDING_FLAG_UPDATE_SHAPE = 1U << 2; +const uint32_t PENDING_FLAG_JUMP = 1U << 4; // static helper method static btVector3 getNormalizedVector(const btVector3& v) { @@ -223,11 +229,10 @@ CharacterController::CharacterController(AvatarData* avatarData) { _avatarData = avatarData; // cache the "PhysicsEnabled" state of _avatarData - _avatarData->lockForRead(); - _enabled = _avatarData->isPhysicsEnabled(); - _avatarData->unlock(); + _enabled = false; - createShapeAndGhost(); + _ghostObject = NULL; + _convexShape = NULL; _addedMargin = 0.02f; _walkDirection.setValue(0.0f,0.0f,0.0f); @@ -242,6 +247,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { _wasJumping = false; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; + _pendingFlags = 0; } CharacterController::~CharacterController() { @@ -349,7 +355,7 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl return penetration; } -void CharacterController::stepUp( btCollisionWorld* world) { +void CharacterController::stepUp(btCollisionWorld* world) { // phase 1: up // compute start and end @@ -416,7 +422,7 @@ void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& } } -void CharacterController::stepForward( btCollisionWorld* collisionWorld, const btVector3& movement) { +void CharacterController::stepForward(btCollisionWorld* collisionWorld, const btVector3& movement) { // phase 2: forward _targetPosition = _currentPosition + movement; @@ -472,7 +478,7 @@ void CharacterController::stepForward( btCollisionWorld* collisionWorld, const b _convexShape->setMargin(margin); } -void CharacterController::stepDown( btCollisionWorld* collisionWorld, btScalar dt) { +void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt) { // phase 3: down // // The "stepDown" phase first makes a normal sweep down that cancels the lift from the "stepUp" phase. @@ -558,7 +564,7 @@ void CharacterController::setVelocityForTimeInterval(const btVector3& velocity, _velocityTimeInterval += timeInterval; } -void CharacterController::reset( btCollisionWorld* collisionWorld ) { +void CharacterController::reset(btCollisionWorld* collisionWorld) { _verticalVelocity = 0.0; _verticalOffset = 0.0; _wasOnGround = false; @@ -583,7 +589,7 @@ void CharacterController::warp(const btVector3& origin) { } -void CharacterController::preStep( btCollisionWorld* collisionWorld) { +void CharacterController::preStep(btCollisionWorld* collisionWorld) { if (!_enabled) { return; } @@ -603,7 +609,7 @@ void CharacterController::preStep( btCollisionWorld* collisionWorld) { _targetPosition = _currentPosition; } -void CharacterController::playerStep( btCollisionWorld* collisionWorld, btScalar dt) { +void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar dt) { if (!_enabled || (!_useWalkDirection && _velocityTimeInterval <= 0.0)) { return; // no motion } @@ -710,106 +716,163 @@ void CharacterController::setUpInterpolate(bool value) { // (interpolate = true, and now default behavior) or happily penetrate objects above the avatar. } +/* // protected void CharacterController::createShapeAndGhost() { // get new dimensions from avatar - _avatarData->lockForRead(); - AABox box = _avatarData->getLocalAABox(); - - // create new ghost - _ghostObject = new btPairCachingGhostObject(); - _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), - glmToBullet(_avatarData->getPosition()))); - _avatarData->unlock(); - - const glm::vec3& diagonal = box.getScale(); - _radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); - _halfHeight = 0.5f * diagonal.y - _radius; + float x = _boxScale.x; + float z = _boxScale.z; + _radius = 0.5f * sqrtf(0.5f * (x * x + z * z)); + _halfHeight = 0.5f * _boxScale.y - _radius; float MIN_HALF_HEIGHT = 0.1f; if (_halfHeight < MIN_HALF_HEIGHT) { _halfHeight = MIN_HALF_HEIGHT; } - glm::vec3 offset = box.getCorner() + 0.5f * diagonal; - _shapeLocalOffset = offset; + // NOTE: _shapeLocalOffset is already computed - // stepHeight affects the heights of ledges that the character can ascend - // however the actual ledge height is some function of _stepHeight - // due to character shape and this CharacterController algorithm - // (the function is approximately 2*_stepHeight) - _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; - - // create new shape - _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); - _ghostObject->setCollisionShape(_convexShape); - _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + if (_radius > 0.0f) { + // create new ghost + _ghostObject = new btPairCachingGhostObject(); + _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), + glmToBullet(_avatarData->getPosition()))); + // stepHeight affects the heights of ledges that the character can ascend + // however the actual ledge height is some function of _stepHeight + // due to character shape and this CharacterController algorithm + // (the function is approximately 2*_stepHeight) + _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; + + // create new shape + _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); + _ghostObject->setCollisionShape(_convexShape); + _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + } else { + // TODO: handle this failure case + } + _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; } +*/ -bool CharacterController::needsShapeUpdate() { - // get new dimensions from avatar - _avatarData->lockForRead(); - AABox box = _avatarData->getLocalAABox(); - _avatarData->unlock(); +void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) { + _boxScale = scale; - const glm::vec3& diagonal = box.getScale(); - float radius = 0.5f * sqrtf(0.5f * (diagonal.x * diagonal.x + diagonal.z * diagonal.z)); - float halfHeight = 0.5f * diagonal.y - radius; + float x = _boxScale.x; + float z = _boxScale.z; + float radius = 0.5f * sqrtf(0.5f * (x * x + z * z)); + float halfHeight = 0.5f * _boxScale.y - radius; float MIN_HALF_HEIGHT = 0.1f; if (halfHeight < MIN_HALF_HEIGHT) { halfHeight = MIN_HALF_HEIGHT; } - glm::vec3 offset = box.getCorner() + 0.5f * diagonal; - // compare dimensions (and offset) + // compare dimensions float radiusDelta = glm::abs(radius - _radius); float heightDelta = glm::abs(halfHeight - _halfHeight); if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) { // shape hasn't changed --> nothing to do - float offsetDelta = glm::distance(offset, _shapeLocalOffset); - if (offsetDelta > FLT_EPSILON) { - // if only the offset changes then we can update it --> no need to rebuild shape - _shapeLocalOffset = offset; - } - return false; + } else { + // we need to: remove, update, add + _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION + | PENDING_FLAG_UPDATE_SHAPE + | PENDING_FLAG_ADD_TO_SIMULATION; + } + + // it's ok to change offset immediately -- there are no thread safety issues here + _shapeLocalOffset = corner + 0.5f * _boxScale; +} + +bool CharacterController::needsAddition() const { + return (bool)(_pendingFlags & PENDING_FLAG_ADD_TO_SIMULATION); +} + +bool CharacterController::needsRemoval() const { + return (bool)(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION); +} + +void CharacterController::setEnabled(bool enabled) { + if (enabled != _enabled) { + if (enabled) { + _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; + } else { + _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; + } + _enabled = enabled; + } +} + +void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { + if (_dynamicsWorld != world) { + if (_dynamicsWorld) { + _dynamicsWorld->removeCollisionObject(getGhostObject()); + _dynamicsWorld->removeAction(this); + } + _dynamicsWorld = world; + if (_dynamicsWorld) { + _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; + _dynamicsWorld->addCollisionObject(getGhostObject(), + btBroadphaseProxy::CharacterFilter, + btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); + _dynamicsWorld->addAction(this); + reset(_dynamicsWorld); + } else { + _pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION; + } + } else { + _pendingFlags &= ~ (PENDING_FLAG_REMOVE_FROM_SIMULATION | PENDING_FLAG_ADD_TO_SIMULATION); } - return true; } void CharacterController::updateShape() { - // DANGER: make sure this CharacterController and its GhostShape have been removed from - // the PhysicsEngine before calling this. - - // delete shape and GhostObject - delete _ghostObject; - _ghostObject = NULL; - delete _convexShape; - _convexShape = NULL; - - createShapeAndGhost(); + if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { + assert(!(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION)); + _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; + // make sure there is NO pending removal from simulation at this point + // (don't want to delete _ghostObject out from under the simulation) + // delete shape and GhostObject + delete _ghostObject; + _ghostObject = NULL; + delete _convexShape; + _convexShape = NULL; + + // compute new dimensions from avatar's bounding box + float x = _boxScale.x; + float z = _boxScale.z; + _radius = 0.5f * sqrtf(0.5f * (x * x + z * z)); + _halfHeight = 0.5f * _boxScale.y - _radius; + float MIN_HALF_HEIGHT = 0.1f; + if (_halfHeight < MIN_HALF_HEIGHT) { + _halfHeight = MIN_HALF_HEIGHT; + } + // NOTE: _shapeLocalOffset is already computed + + if (_radius > 0.0f) { + // create new ghost + _ghostObject = new btPairCachingGhostObject(); + _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), + glmToBullet(_avatarData->getPosition()))); + // stepHeight affects the heights of ledges that the character can ascend + // however the actual ledge height is some function of _stepHeight + // due to character shape and this CharacterController algorithm + // (the function is approximately 2*_stepHeight) + _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; + + // create new shape + _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); + _ghostObject->setCollisionShape(_convexShape); + _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); + } else { + // TODO: handle this failure case + } + } } void CharacterController::preSimulation(btScalar timeStep) { - bool wasEnabled = _enabled; + if (_enabled && _dynamicsWorld) { + glm::quat rotation = _avatarData->getOrientation(); + glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset; + // TODO: harvest jump event here + btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity()); - // lock avatarData, get everything we need from it ASAP, then unlock - _avatarData->lockForRead(); - _enabled = _avatarData->isPhysicsEnabled(); - glm::quat rotation = _avatarData->getOrientation(); - glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset; - // TODO: Andrew to implement: harvest jump event here - btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity()); - - _avatarData->unlock(); - - if (wasEnabled != _enabled) { - if (_enabled) { - // TODO: Andrew to implement: add collision shape back into world - } else { - // TODO: Andrew to implement: remove collision shape from world, - // otherwise things will continue to collide with it - } - } - - if (_enabled) { _ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); setVelocityForTimeInterval(walkVelocity, timeStep); } @@ -817,13 +880,11 @@ void CharacterController::preSimulation(btScalar timeStep) { void CharacterController::postSimulation() { if (_enabled) { - _avatarData->lockForWrite(); const btTransform& avatarTransform = _ghostObject->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); glm::vec3 offset = rotation * _shapeLocalOffset; _avatarData->setOrientation(rotation); _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); - _avatarData->unlock(); } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index b6109eb0ff..9803d0d6ee 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -37,13 +37,13 @@ class btPairCachingGhostObject; ///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations. ///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user. + ATTRIBUTE_ALIGNED16(class) CharacterController : public btCharacterControllerInterface { protected: AvatarData* _avatarData = NULL; btPairCachingGhostObject* _ghostObject; - glm::vec3 _shapeLocalOffset; btConvexShape* _convexShape;//is also in _ghostObject, but it needs to be convex, so we store it here to avoid upcast btScalar _radius; @@ -83,6 +83,12 @@ protected: bool _wasJumping; bool _useWalkDirection; btScalar _velocityTimeInterval; + uint32_t _pendingFlags; + + glm::vec3 _shapeLocalOffset; + glm::vec3 _boxScale; // used to compute capsule shape + + btDynamicsWorld* _dynamicsWorld = NULL; btVector3 computeReflectionDirection(const btVector3& direction, const btVector3& normal); btVector3 parallelComponent(const btVector3& direction, const btVector3& normal); @@ -152,7 +158,13 @@ public: bool onGround() const; void setUpInterpolate(bool value); - bool needsShapeUpdate(); + bool needsRemoval() const; + bool needsAddition() const; + void setEnabled(bool enabled); + void setDynamicsWorld(btDynamicsWorld* world); + + void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); + bool needsShapeUpdate() const; void updateShape(); void preSimulation(btScalar timeStep); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 447a3ab6f1..bcde3318ad 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -280,12 +280,12 @@ void PhysicsEngine::init(EntityEditPacketSender* packetSender) { void PhysicsEngine::stepSimulation() { lock(); // NOTE: the grand order of operations is: - // (1) relay incoming changes + // (1) pull incoming changes // (2) step simulation // (3) synchronize outgoing motion states // (4) send outgoing packets - // This is step (1). + // This is step (1) pull incoming changes relayIncomingChangesToSimulation(); const int MAX_NUM_SUBSTEPS = 4; @@ -296,10 +296,17 @@ void PhysicsEngine::stepSimulation() { // TODO: move character->preSimulation() into relayIncomingChanges if (_characterController) { + if (_characterController->needsRemoval()) { + _characterController->setDynamicsWorld(NULL); + } + _characterController->updateShape(); + if (_characterController->needsAddition()) { + _characterController->setDynamicsWorld(_dynamicsWorld); + } _characterController->preSimulation(timeStep); } - // This is step (2). + // This is step (2) step simulation int numSubsteps = _dynamicsWorld->stepSimulation(timeStep, MAX_NUM_SUBSTEPS, PHYSICS_ENGINE_FIXED_SUBSTEP); _numSubsteps += (uint32_t)numSubsteps; stepNonPhysicalKinematics(usecTimestampNow()); @@ -600,34 +607,10 @@ bool PhysicsEngine::updateObjectHard(btRigidBody* body, ObjectMotionState* motio return true; } -void PhysicsEngine::setAvatarData(AvatarData *avatarData) { - if (_characterController) { - bool needsShapeUpdate = _characterController->needsShapeUpdate(); - if (needsShapeUpdate) { - lock(); - // remove old info - _dynamicsWorld->removeCollisionObject(_characterController->getGhostObject()); - _dynamicsWorld->removeAction(_characterController); - // update shape - _characterController->updateShape(); - // insert new info - _dynamicsWorld->addCollisionObject(_characterController->getGhostObject(), - btBroadphaseProxy::CharacterFilter, - btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); - _dynamicsWorld->addAction(_characterController); - _characterController->reset(_dynamicsWorld); - unlock(); - } - } else { - // initialize _characterController - assert(avatarData); // don't pass NULL argument +void PhysicsEngine::setCharacterController(CharacterController* character) { + if (!_characterController) { lock(); - _characterController = new CharacterController(avatarData); - _dynamicsWorld->addCollisionObject(_characterController->getGhostObject(), - btBroadphaseProxy::CharacterFilter, - btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); - _dynamicsWorld->addAction(_characterController); - _characterController->reset(_dynamicsWorld); + _characterController = character; unlock(); } } diff --git a/libraries/physics/src/PhysicsEngine.h b/libraries/physics/src/PhysicsEngine.h index cb637c60b9..0661b47d3a 100644 --- a/libraries/physics/src/PhysicsEngine.h +++ b/libraries/physics/src/PhysicsEngine.h @@ -17,9 +17,7 @@ #include <QSet> #include <btBulletDynamicsCommon.h> #include <BulletCollision/CollisionDispatch/btGhostObject.h> -//#include <BulletCollision/CollisionShapes/btCapsuleShape.h> -#include <AvatarData.h> #include <EntityItem.h> #include <EntitySimulation.h> @@ -86,7 +84,7 @@ public: /// process queue of changed from external sources void relayIncomingChangesToSimulation(); - void setAvatarData(AvatarData *avatarData); + void setCharacterController(CharacterController* character); private: /// \param motionState pointer to Object's MotionState From d49762097686af6b9400383367d8c66e6df77430 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 24 Mar 2015 23:05:46 -0700 Subject: [PATCH 086/177] avatar can jump with E key when walking --- interface/src/avatar/MyAvatar.cpp | 3 +- interface/src/avatar/MyAvatar.h | 3 +- libraries/physics/src/CharacterController.cpp | 139 ++++-------------- libraries/physics/src/CharacterController.h | 17 +-- 4 files changed, 39 insertions(+), 123 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index e0de24247e..2f42544f28 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -70,7 +70,6 @@ MyAvatar::MyAvatar() : Avatar(), _turningKeyPressTime(0.0f), _gravity(0.0f, 0.0f, 0.0f), - _shouldJump(false), _wasPushing(false), _isPushing(false), _isBraking(false), @@ -82,8 +81,8 @@ MyAvatar::MyAvatar() : _scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME), _motionBehaviors(AVATAR_MOTION_DEFAULTS), - _characterController(this), _enablePhysics(false), + _characterController(this), _lookAtTargetAvatar(), _shouldRender(true), _billboardValid(false), diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 1b2b2f5e46..a37d1c6a30 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -89,7 +89,7 @@ public: void clearDriveKeys(); void setDriveKeys(int key, float val) { _driveKeys[key] = val; }; bool getDriveKeys(int key) { return _driveKeys[key] != 0.0f; }; - void jump() { _shouldJump = true; }; + void jump() { _characterController.jump(); } bool isMyAvatar() { return true; } @@ -194,7 +194,6 @@ private: float _turningKeyPressTime; glm::vec3 _gravity; - bool _shouldJump; float _driveKeys[MAX_DRIVE_KEYS]; bool _wasPushing; bool _isPushing; diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index be10cd1f54..fa02f81e34 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -23,10 +23,8 @@ subject to the following restrictions: const uint32_t PENDING_FLAG_ADD_TO_SIMULATION = 1U << 0; const uint32_t PENDING_FLAG_REMOVE_FROM_SIMULATION = 1U << 1; -//const uint32_t PENDING_FLAG_ENABLE = 1U << 0; -//const uint32_t PENDING_FLAG_DISABLE = 1U << 1; const uint32_t PENDING_FLAG_UPDATE_SHAPE = 1U << 2; -const uint32_t PENDING_FLAG_JUMP = 1U << 4; +const uint32_t PENDING_FLAG_JUMP = 1U << 3; // static helper method static btVector3 getNormalizedVector(const btVector3& v) { @@ -41,34 +39,6 @@ static btVector3 getNormalizedVector(const btVector3& v) { return n; } -///@todo Interact with dynamic objects, -///Ride kinematicly animated platforms properly -///More realistic (or maybe just a config option) falling -/// -> Should integrate falling velocity manually and use that in stepDown() -///Support jumping -///Support ducking - -/* This callback is unused, but we're keeping it around just in case we figure out how to use it. -class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback -{ -public: -btKinematicClosestNotMeRayResultCallback(btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) -{ -_me = me; -} - -virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult, bool normalInWorldSpace) -{ -if (rayResult.m_collisionObject == _me) -return 1.0; - -return ClosestRayResultCallback::addSingleResult(rayResult, normalInWorldSpace); -} -protected: -btCollisionObject* _me; -}; -*/ - class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: btKinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot) @@ -236,13 +206,12 @@ CharacterController::CharacterController(AvatarData* avatarData) { _addedMargin = 0.02f; _walkDirection.setValue(0.0f,0.0f,0.0f); - _useWalkDirection = true; // use walk direction by default, legacy behavior _velocityTimeInterval = 0.0f; _verticalVelocity = 0.0f; _verticalOffset = 0.0f; _gravity = 9.8f; _maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s. - _jumpSpeed = 10.0f; // ? + _jumpSpeed = 7.0f; _wasOnGround = false; _wasJumping = false; setMaxSlope(btRadians(45.0f)); @@ -485,14 +454,9 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt // If it hits a ledge then it stops otherwise it makes another sweep down in search of a floor within // reach of the character's feet. - btScalar downSpeed = (_verticalVelocity < 0.0f) ? -_verticalVelocity : 0.0f; - if (downSpeed > 0.0f && downSpeed > _maxFallSpeed && (_wasOnGround || !_wasJumping)) { - downSpeed = _maxFallSpeed; - } - // first sweep for ledge btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); - btVector3 step = up * (-(_lastStepUp + downSpeed * dt)); + btVector3 step = (_verticalVelocity * dt - _lastStepUp) * up; StepDownConvexResultCallback callback(_ghostObject, up, @@ -517,7 +481,7 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _verticalVelocity = 0.0f; _verticalOffset = 0.0f; _wasJumping = false; - } else { + } else if (!_wasJumping) { // sweep again for floor within downStep threshold StepDownConvexResultCallback callback2 (_ghostObject, up, @@ -548,17 +512,19 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _currentPosition = oldPosition - _lastStepUp * up; _lastStepUp = 0.0f; } + } else { + // we're jumping, and didn't hit anything, so our target position is where we would have fallen to + _currentPosition = _targetPosition; } } void CharacterController::setWalkDirection(const btVector3& walkDirection) { - _useWalkDirection = true; - _walkDirection = walkDirection; - _normalizedDirection = getNormalizedVector(_walkDirection); + // This must be implemented to satisfy base-class interface but does nothing. + // Use setVelocityForTimeInterval() instead. + assert(false); } void CharacterController::setVelocityForTimeInterval(const btVector3& velocity, btScalar timeInterval) { - _useWalkDirection = false; _walkDirection = velocity; _normalizedDirection = getNormalizedVector(_walkDirection); _velocityTimeInterval += timeInterval; @@ -610,7 +576,7 @@ void CharacterController::preStep(btCollisionWorld* collisionWorld) { } void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar dt) { - if (!_enabled || (!_useWalkDirection && _velocityTimeInterval <= 0.0)) { + if (!_enabled) { return; // no motion } @@ -634,17 +600,15 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // (3) step the character down looking for new ledges, the original floor, or a floor one step below where we started stepUp(collisionWorld); - if (_useWalkDirection) { - stepForward(collisionWorld, _walkDirection); - } else { - // compute substep and decrement total interval - btScalar dtMoving = (dt < _velocityTimeInterval) ? dt : _velocityTimeInterval; - _velocityTimeInterval -= dt; - // stepForward substep - btVector3 move = _walkDirection * dtMoving; - stepForward(collisionWorld, move); - } + // compute substep and decrement total interval + btScalar dtMoving = (dt < _velocityTimeInterval) ? dt : _velocityTimeInterval; + _velocityTimeInterval -= dt; + + // stepForward substep + btVector3 move = _walkDirection * dtMoving; + stepForward(collisionWorld, move); + stepDown(collisionWorld, dt); xform.setOrigin(_currentPosition); @@ -668,22 +632,7 @@ bool CharacterController::canJump() const { } void CharacterController::jump() { - if (!canJump()) { - return; - } - - _verticalVelocity = _jumpSpeed; - _wasJumping = true; - -#if 0 - currently no jumping. - btTransform xform; - _rigidBody->getMotionState()->getWorldTransform(xform); - btVector3 up = xform.getBasis()[1]; - up.normalize(); - btScalar magnitude = (btScalar(1.0)/_rigidBody->getInvMass()) * btScalar(8.0); - _rigidBody->applyCentralImpulse (up * magnitude); -#endif + _pendingFlags |= PENDING_FLAG_JUMP; } void CharacterController::setGravity(btScalar gravity) { @@ -704,7 +653,7 @@ btScalar CharacterController::getMaxSlope() const { } bool CharacterController::onGround() const { - return _enabled && _verticalVelocity == 0.0 && _verticalOffset == 0.0; + return _enabled && _verticalVelocity == 0.0f && _verticalOffset == 0.0f; } void CharacterController::debugDraw(btIDebugDraw* debugDrawer) { @@ -716,42 +665,6 @@ void CharacterController::setUpInterpolate(bool value) { // (interpolate = true, and now default behavior) or happily penetrate objects above the avatar. } -/* -// protected -void CharacterController::createShapeAndGhost() { - // get new dimensions from avatar - float x = _boxScale.x; - float z = _boxScale.z; - _radius = 0.5f * sqrtf(0.5f * (x * x + z * z)); - _halfHeight = 0.5f * _boxScale.y - _radius; - float MIN_HALF_HEIGHT = 0.1f; - if (_halfHeight < MIN_HALF_HEIGHT) { - _halfHeight = MIN_HALF_HEIGHT; - } - // NOTE: _shapeLocalOffset is already computed - - if (_radius > 0.0f) { - // create new ghost - _ghostObject = new btPairCachingGhostObject(); - _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), - glmToBullet(_avatarData->getPosition()))); - // stepHeight affects the heights of ledges that the character can ascend - // however the actual ledge height is some function of _stepHeight - // due to character shape and this CharacterController algorithm - // (the function is approximately 2*_stepHeight) - _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; - - // create new shape - _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); - _ghostObject->setCollisionShape(_convexShape); - _ghostObject->setCollisionFlags(btCollisionObject::CF_CHARACTER_OBJECT); - } else { - // TODO: handle this failure case - } - _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; -} -*/ - void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale) { _boxScale = scale; @@ -808,7 +721,7 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { } _dynamicsWorld = world; if (_dynamicsWorld) { - _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; + _pendingFlags &= ~ (PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_JUMP); _dynamicsWorld->addCollisionObject(getGhostObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); @@ -870,11 +783,17 @@ void CharacterController::preSimulation(btScalar timeStep) { if (_enabled && _dynamicsWorld) { glm::quat rotation = _avatarData->getOrientation(); glm::vec3 position = _avatarData->getPosition() + rotation * _shapeLocalOffset; - // TODO: harvest jump event here btVector3 walkVelocity = glmToBullet(_avatarData->getVelocity()); _ghostObject->setWorldTransform(btTransform(glmToBullet(rotation), glmToBullet(position))); setVelocityForTimeInterval(walkVelocity, timeStep); + if (_pendingFlags & PENDING_FLAG_JUMP) { + _pendingFlags &= ~ PENDING_FLAG_JUMP; + if (canJump()) { + _verticalVelocity = _jumpSpeed; + _wasJumping = true; + } + } } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 9803d0d6ee..598bc866d5 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -81,7 +81,6 @@ protected: bool _enabled; bool _wasOnGround; bool _wasJumping; - bool _useWalkDirection; btScalar _velocityTimeInterval; uint32_t _pendingFlags; @@ -132,18 +131,19 @@ public: virtual void setVelocityForTimeInterval(const btVector3& velocity, btScalar timeInterval); - void reset(btCollisionWorld* collisionWorld ); - void warp(const btVector3& origin); + virtual void reset(btCollisionWorld* collisionWorld ); + virtual void warp(const btVector3& origin); - void preStep(btCollisionWorld* collisionWorld); - void playerStep(btCollisionWorld* collisionWorld, btScalar dt); + virtual void preStep(btCollisionWorld* collisionWorld); + virtual void playerStep(btCollisionWorld* collisionWorld, btScalar dt); + + virtual bool canJump() const; + virtual void jump(); + virtual bool onGround() const; void setMaxFallSpeed(btScalar speed); void setJumpSpeed(btScalar jumpSpeed); void setMaxJumpHeight(btScalar maxJumpHeight); - bool canJump() const; - - void jump(); void setGravity(btScalar gravity); btScalar getGravity() const; @@ -155,7 +155,6 @@ public: btPairCachingGhostObject* getGhostObject(); - bool onGround() const; void setUpInterpolate(bool value); bool needsRemoval() const; From 430158c1095ed8c191d3d731bf083ffdbd8d269f Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Tue, 24 Mar 2015 23:35:09 -0700 Subject: [PATCH 087/177] updateShapeIfNecessary() is a more correct name --- libraries/physics/src/CharacterController.cpp | 2 +- libraries/physics/src/CharacterController.h | 2 +- libraries/physics/src/PhysicsEngine.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index fa02f81e34..c26ffa3339 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -735,7 +735,7 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { } } -void CharacterController::updateShape() { +void CharacterController::updateShapeIfNecessary() { if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { assert(!(_pendingFlags & PENDING_FLAG_REMOVE_FROM_SIMULATION)); _pendingFlags &= ~ PENDING_FLAG_UPDATE_SHAPE; diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 598bc866d5..740940ce53 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -164,7 +164,7 @@ public: void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); bool needsShapeUpdate() const; - void updateShape(); + void updateShapeIfNecessary(); void preSimulation(btScalar timeStep); void postSimulation(); diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index bcde3318ad..9ca718e19a 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -299,7 +299,7 @@ void PhysicsEngine::stepSimulation() { if (_characterController->needsRemoval()) { _characterController->setDynamicsWorld(NULL); } - _characterController->updateShape(); + _characterController->updateShapeIfNecessary(); if (_characterController->needsAddition()) { _characterController->setDynamicsWorld(_dynamicsWorld); } From 719dae61a9a8d015a12f2685439b38bc6951f7e2 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Wed, 25 Mar 2015 06:51:00 -0700 Subject: [PATCH 088/177] when a compound shape is deleted, delete the children, as well --- libraries/physics/src/ShapeInfoUtil.h | 2 ++ libraries/physics/src/ShapeManager.cpp | 12 ++++++++++++ 2 files changed, 14 insertions(+) diff --git a/libraries/physics/src/ShapeInfoUtil.h b/libraries/physics/src/ShapeInfoUtil.h index fb59f30c69..9585161440 100644 --- a/libraries/physics/src/ShapeInfoUtil.h +++ b/libraries/physics/src/ShapeInfoUtil.h @@ -20,6 +20,8 @@ // translates between ShapeInfo and btShape namespace ShapeInfoUtil { + + // XXX is collectInfoFromShape no longer strictly needed? void collectInfoFromShape(const btCollisionShape* shape, ShapeInfo& info); btCollisionShape* createShapeFromInfo(const ShapeInfo& info); diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 513fbfa7a5..9b3b2f6d35 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -100,6 +100,18 @@ void ShapeManager::collectGarbage() { DoubleHashKey& key = _pendingGarbage[i]; ShapeReference* shapeRef = _shapeMap.find(key); if (shapeRef && shapeRef->refCount == 0) { + // if the shape we're about to delete is compound, delete the children first. + auto shapeType = ShapeInfoUtil::fromBulletShapeType(shapeRef->shape->getShapeType()); + if (shapeType == SHAPE_TYPE_COMPOUND) { + const btCompoundShape* compoundShape = static_cast<const btCompoundShape*>(shapeRef->shape); + const int numChildShapes = compoundShape->getNumChildShapes(); + QVector<QVector<glm::vec3>> points; + for (int i = 0; i < numChildShapes; i ++) { + const btCollisionShape* childShape = compoundShape->getChildShape(i); + delete childShape; + } + } + delete shapeRef->shape; _shapeMap.remove(key); } From 92d394404463012c6c2ef9e05d774545c4efa725 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Wed, 25 Mar 2015 15:01:22 +0100 Subject: [PATCH 089/177] Use preOp function for all common checks/updates --- examples/entityScripts/lightController.js | 70 ++++++++++++++--------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 624fc929b3..1ff41df16c 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -4,6 +4,27 @@ this.lightID = null; this.sound = null; + var DEFAULT_USER_DATA = { + creatingLight: false, + lightID: null, + lightDefaultProperties: { + type: "Light", + position: { x: 0, y: 0, z: 0 }, + dimensions: { x: 5, y: 5, z: 5 }, + isSpotlight: false, + color: { red: 255, green: 48, blue: 0 }, + diffuseColor: { red: 255, green: 255, blue: 255 }, + ambientColor: { red: 255, green: 255, blue: 255 }, + specularColor: { red: 0, green: 0, blue: 0 }, + constantAttenuation: 1, + linearAttenuation: 0, + quadraticAttenuation: 0, + intensity: 10, + exponent: 0, + cutoff: 180, // in degrees + } + }; + function copyObject(object) { return JSON.parse(JSON.stringify(object)); } @@ -30,6 +51,19 @@ Entities.editEntity(entityID, { userData: JSON.stringify(userData) }); } + // Checks whether the userData is well-formed and updates it if not + this.checkUserData = function() { + var userData = getUserData(this.entityID); + if (!userData) { + userData = DEFAULT_USER_DATA; + } else if (!userData.lightDefaultProperties) { + userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties; + } else if (typeof userData.creatingLight == 'undefined') { + userData.creatingLight = DEFAULT_USER_DATA.creatingLight; + } + updateUserData(this.entityID, userData); + } + // Download sound if needed this.maybeDownloadSound = function() { if (this.sound === null) { @@ -76,28 +110,6 @@ this.updateLightID = function() { var userData = getUserData(this.entityID); - if (!userData) { - userData = { - lightID: null, - lightDefaultProperties: { - type: "Light", - position: { x: 0, y: 0, z: 0 }, - dimensions: { x: 5, y: 5, z: 5 }, - isSpotlight: false, - color: { red: 255, green: 48, blue: 0 }, - diffuseColor: { red: 255, green: 255, blue: 255 }, - ambientColor: { red: 255, green: 255, blue: 255 }, - specularColor: { red: 0, green: 0, blue: 0 }, - constantAttenuation: 1, - linearAttenuation: 0, - quadraticAttenuation: 0, - intensity: 10, - exponent: 0, - cutoff: 180, // in degrees - } - }; - updateUserData(this.entityID, userData); - } // Find valid light if (doesEntityExistNow(this.lightID)) { @@ -168,15 +180,21 @@ updateUserData(this.entityID, userData); print("Relative properties of light entity saved."); } - - this.preload = function(entityID) { + + // This function should be called before any callback is executed + this.preOperation = function(entityID) { this.entityID = entityID; this.maybeDownloadSound(); + + this.checkUserData(); + } + + this.preload = function(entityID) { + this.preOperation(entityID); }; this.clickReleaseOnEntity = function(entityID, mouseEvent) { - this.entityID = entityID; - this.maybeDownloadSound(); + this.preOperation(entityID); if (mouseEvent.isLeftButton) { this.updateLightID(); From afb96709f19df414534ae6ec60c0e4d021a25989 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Wed, 25 Mar 2015 15:44:37 +0100 Subject: [PATCH 090/177] Only update userData when light entity is identified --- examples/entityScripts/lightController.js | 91 +++++++++++++---------- 1 file changed, 53 insertions(+), 38 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 1ff41df16c..f4ebd17715 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -1,6 +1,5 @@ (function() { this.entityID = null; - this.properties = null; this.lightID = null; this.sound = null; @@ -51,19 +50,6 @@ Entities.editEntity(entityID, { userData: JSON.stringify(userData) }); } - // Checks whether the userData is well-formed and updates it if not - this.checkUserData = function() { - var userData = getUserData(this.entityID); - if (!userData) { - userData = DEFAULT_USER_DATA; - } else if (!userData.lightDefaultProperties) { - userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties; - } else if (typeof userData.creatingLight == 'undefined') { - userData.creatingLight = DEFAULT_USER_DATA.creatingLight; - } - updateUserData(this.entityID, userData); - } - // Download sound if needed this.maybeDownloadSound = function() { if (this.sound === null) { @@ -81,17 +67,21 @@ print("Warning: Couldn't play sound."); } } - - // Toggles the associated light entity - this.toggleLight = function() { - if (this.lightID) { - var lightProperties = Entities.getEntityProperties(this.lightID); - Entities.editEntity(this.lightID, { visible: !lightProperties.visible }); - } else { - print("Warning: No light to turn on/off"); + + // Checks whether the userData is well-formed and updates it if not + this.checkUserData = function() { + var userData = getUserData(this.entityID); + if (!userData) { + userData = DEFAULT_USER_DATA; + } else if (!userData.lightDefaultProperties) { + userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties; + } else if (typeof userData.creatingLight == 'undefined') { + userData.creatingLight = DEFAULT_USER_DATA.creatingLight; } + updateUserData(this.entityID, userData); } + // Create a Light entity this.createLight = function(userData) { var lightProperties = copyObject(userData.lightDefaultProperties); if (lightProperties) { @@ -108,34 +98,48 @@ } } + // Tries to find a valid light, creates one otherwise this.updateLightID = function() { - var userData = getUserData(this.entityID); - // Find valid light if (doesEntityExistNow(this.lightID)) { - if (!didEntityExist(this.lightID)) { - // Light now has an ID, so update it in userData - this.lightID = getTrueID(this.lightID); - userData.lightID = this.lightID; - updateUserData(this.entityID, userData); - } return; } + var userData = getUserData(this.entityID); if (doesEntityExistNow(userData.lightID)) { - this.lightID = getTrueID(userData.lightID); + this.lightID = userData.lightID; return; } - // No valid light, create one - this.lightID = this.createLight(userData); - print("Created new light entity"); - - // Update user data with new ID + if (!userData.creatingLight) { + // No valid light, create one + userData.creatingLight = true; + updateUserData(this.entityID, userData); + this.lightID = this.createLight(userData); + this.maybeUpdateLightIDInUserData(); + print("Created new light entity"); + } + } + + this.maybeUpdateLightIDInUserData = function() { + this.lightID = getTrueID(this.lightID); + if (this.lightID.isKnownID) { + this.updateLightIDInUserData(); + } else { + var that = this; + Script.setTimeout(function() { that.maybeUpdateLightIDInUserData() }, 500); + } + } + + // Update user data with new lightID + this.updateLightIDInUserData = function() { + var userData = getUserData(this.entityID); userData.lightID = this.lightID; + userData.creatingLight = false; updateUserData(this.entityID, userData); } + // Moves light entity if the lamp entity moved this.maybeMoveLight = function() { var entityProperties = Entities.getEntityProperties(this.entityID); var lightProperties = Entities.getEntityProperties(this.lightID); @@ -151,8 +155,9 @@ } } + // Stores light entity relative position in the lamp metadata this.updateRelativeLightPosition = function() { - if (!doesEntityExistNow(this.entityID) || !doesEntityExistNow(this.lightID)) { + if (!doesEntityExistNow(this.lightID)) { print("Warning: ID invalid, couldn't save relative position."); return; } @@ -189,6 +194,17 @@ this.checkUserData(); } + // Toggles the associated light entity + this.toggleLight = function() { + if (this.lightID) { + var lightProperties = Entities.getEntityProperties(this.lightID); + Entities.editEntity(this.lightID, { visible: !lightProperties.visible }); + this.playSound(); + } else { + print("Warning: No light to turn on/off"); + } + } + this.preload = function(entityID) { this.preOperation(entityID); }; @@ -200,7 +216,6 @@ this.updateLightID(); this.maybeMoveLight(); this.toggleLight(); - this.playSound(); } else if (mouseEvent.isRightButton) { this.updateRelativeLightPosition(); } From 19886bd33c91f6c8a79b51aad7c21f8b834c354e Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Wed, 25 Mar 2015 16:38:27 +0100 Subject: [PATCH 091/177] Better handling of callback --- examples/entityScripts/lightController.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index f4ebd17715..5b2e2ae8b1 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -75,8 +75,6 @@ userData = DEFAULT_USER_DATA; } else if (!userData.lightDefaultProperties) { userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties; - } else if (typeof userData.creatingLight == 'undefined') { - userData.creatingLight = DEFAULT_USER_DATA.creatingLight; } updateUserData(this.entityID, userData); } @@ -122,8 +120,8 @@ } this.maybeUpdateLightIDInUserData = function() { - this.lightID = getTrueID(this.lightID); - if (this.lightID.isKnownID) { + if (getTrueID(this.lightID).isKnownID) { + this.lightID = getTrueID(this.lightID); this.updateLightIDInUserData(); } else { var that = this; From 674b2c97a28ec5d5000a6e597325d9cef152ea36 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Wed, 25 Mar 2015 08:53:33 -0700 Subject: [PATCH 092/177] added comments to zlib license --- libraries/physics/src/CharacterController.cpp | 1 + libraries/physics/src/CharacterController.h | 1 + 2 files changed, 2 insertions(+) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index c26ffa3339..277d9748cd 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -1,6 +1,7 @@ /* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com +2015.03.25 -- modified by Andrew Meadows andrew@highfidelity.io This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 740940ce53..323529b1cd 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -1,6 +1,7 @@ /* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com +2015.03.25 -- modified by Andrew Meadows andrew@highfidelity.io This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. From 715fe1096f2331d2c7fcfae55752f3a92c892091 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Wed, 25 Mar 2015 17:33:27 +0100 Subject: [PATCH 093/177] Random but persistant switch sound --- examples/entityScripts/lightController.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/entityScripts/lightController.js b/examples/entityScripts/lightController.js index 5b2e2ae8b1..e6e4998aef 100644 --- a/examples/entityScripts/lightController.js +++ b/examples/entityScripts/lightController.js @@ -2,6 +2,9 @@ this.entityID = null; this.lightID = null; this.sound = null; + this.soundURLs = ["https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_1.wav", + "https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_2.wav", + "https://hifi-public.s3.amazonaws.com/sounds/Switches%20and%20sliders/lamp_switch_3.wav"] var DEFAULT_USER_DATA = { creatingLight: false, @@ -21,7 +24,8 @@ intensity: 10, exponent: 0, cutoff: 180, // in degrees - } + }, + soundIndex: Math.floor(Math.random() * this.soundURLs.length) }; function copyObject(object) { @@ -53,7 +57,8 @@ // Download sound if needed this.maybeDownloadSound = function() { if (this.sound === null) { - this.sound = SoundCache.getSound("http://public.highfidelity.io/sounds/Footsteps/FootstepW3Left-12db.wav"); + var soundIndex = getUserData(this.entityID).soundIndex; + this.sound = SoundCache.getSound(this.soundURLs[soundIndex]); } } // Play switch sound @@ -75,6 +80,8 @@ userData = DEFAULT_USER_DATA; } else if (!userData.lightDefaultProperties) { userData.lightDefaultProperties = DEFAULT_USER_DATA.lightDefaultProperties; + } else if (!userData.soundIndex) { + userData.soundIndex = DEFAULT_USER_DATA.soundIndex; } updateUserData(this.entityID, userData); } @@ -187,9 +194,9 @@ // This function should be called before any callback is executed this.preOperation = function(entityID) { this.entityID = entityID; - this.maybeDownloadSound(); this.checkUserData(); + this.maybeDownloadSound(); } // Toggles the associated light entity From 2128f213082ccc8e49865d9a9eae069f8be72db5 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Wed, 25 Mar 2015 11:02:48 -0700 Subject: [PATCH 094/177] only set ADD bit with UPDATE_SHAPE when enabled --- libraries/physics/src/CharacterController.cpp | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 277d9748cd..88d26110a7 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -684,10 +684,13 @@ void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) { // shape hasn't changed --> nothing to do } else { - // we need to: remove, update, add + // we always need to: REMOVE when UPDATE_SHAPE, to avoid deleting shapes out from under the PhysicsEngine _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION - | PENDING_FLAG_UPDATE_SHAPE - | PENDING_FLAG_ADD_TO_SIMULATION; + | PENDING_FLAG_UPDATE_SHAPE; + // but only need to ADD back when we happen to be enabled + if (_enabled) { + _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; + } } // it's ok to change offset immediately -- there are no thread safety issues here @@ -705,8 +708,12 @@ bool CharacterController::needsRemoval() const { void CharacterController::setEnabled(bool enabled) { if (enabled != _enabled) { if (enabled) { + // Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit. + // Setting the ADD bit here works for all cases so we don't even bother checking other bits. _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; } else { + // Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case + // it was previously set by something else (e.g. an UPDATE_SHAPE event). _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; } From 2440c47648f355e6d48bf1148c31f1ea9ff7ed37 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Wed, 25 Mar 2015 11:06:19 -0700 Subject: [PATCH 095/177] remove extra whitespace --- libraries/physics/src/CharacterController.cpp | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 88d26110a7..e84df7d644 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -5,12 +5,12 @@ Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. -Permission is granted to anyone to use this software for any purpose, -including commercial applications, and to alter it and redistribute it freely, +Permission is granted to anyone to use this software for any purpose, +including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: -1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. - If you use this software in a product, an acknowledgment in the product documentation would be appreciated +1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. + If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. @@ -29,7 +29,7 @@ const uint32_t PENDING_FLAG_JUMP = 1U << 3; // static helper method static btVector3 getNormalizedVector(const btVector3& v) { - // NOTE: check the length first, then normalize + // NOTE: check the length first, then normalize // --> avoids assert when trying to normalize zero-length vectors btScalar vLength = v.length(); if (vLength < FLT_EPSILON) { @@ -87,8 +87,8 @@ protected: class StepDownConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { // special convex sweep callback for character during the stepDown() phase public: - StepDownConvexResultCallback(btCollisionObject* me, - const btVector3& up, + StepDownConvexResultCallback(btCollisionObject* me, + const btVector3& up, const btVector3& start, const btVector3& step, const btVector3& pushDirection, @@ -144,7 +144,7 @@ class StepDownConvexResultCallback : public btCollisionWorld::ClosestConvexResul btVector3 side(_radius, - (_halfHeight - _step.length() + fractionalStep.dot(_up)), 0.0f); btScalar maxAngle = side.angle(-_up); - // Ignore hits that are larger than maxAngle. Effectively what is happening here is: + // Ignore hits that are larger than maxAngle. Effectively what is happening here is: // we're ignoring hits at contacts that have non-vertical normals... if they hit higher // than the character's "feet". Ignoring the contact allows the character to slide down // for these hits. In other words, vertical walls against the character's torso will @@ -238,9 +238,9 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl btVector3 minAabb, maxAabb; _convexShape->getAabb(_ghostObject->getWorldTransform(), minAabb, maxAabb); - collisionWorld->getBroadphase()->setAabb(_ghostObject->getBroadphaseHandle(), - minAabb, - maxAabb, + collisionWorld->getBroadphase()->setAabb(_ghostObject->getBroadphaseHandle(), + minAabb, + maxAabb, collisionWorld->getDispatcher()); bool penetration = false; @@ -299,14 +299,14 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl if (collisionHeight < _lastStepUp) { // This contact is below the lastStepUp, so we ignore it for penetration resolution, - // otherwise it may prevent the character from getting close enough to find any available + // otherwise it may prevent the character from getting close enough to find any available // horizontal foothold that would allow it to climbe the ledge. In other words, we're // making the character's "feet" soft for collisions against steps, but not floors. useContact = false; - } + } } if (useContact) { - + if (dist < maxPen) { maxPen = dist; _floorNormal = normal; @@ -382,7 +382,7 @@ void CharacterController::updateTargetPositionBasedOnCollision(const btVector3& //if (tangentMag != 0.0) { if (0) { btVector3 parComponent = parallelDir * btScalar(tangentMag * movementLength); - _targetPosition += parComponent; + _targetPosition += parComponent; } if (normalMag != 0.0) { @@ -451,7 +451,7 @@ void CharacterController::stepForward(btCollisionWorld* collisionWorld, const bt void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt) { // phase 3: down // - // The "stepDown" phase first makes a normal sweep down that cancels the lift from the "stepUp" phase. + // The "stepDown" phase first makes a normal sweep down that cancels the lift from the "stepUp" phase. // If it hits a ledge then it stops otherwise it makes another sweep down in search of a floor within // reach of the character's feet. @@ -459,11 +459,11 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); btVector3 step = (_verticalVelocity * dt - _lastStepUp) * up; - StepDownConvexResultCallback callback(_ghostObject, - up, - _currentPosition, step, + StepDownConvexResultCallback callback(_ghostObject, + up, + _currentPosition, step, _walkDirection, - _maxSlopeCosine, + _maxSlopeCosine, _radius, _halfHeight); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; @@ -484,11 +484,11 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _wasJumping = false; } else if (!_wasJumping) { // sweep again for floor within downStep threshold - StepDownConvexResultCallback callback2 (_ghostObject, - up, + StepDownConvexResultCallback callback2 (_ghostObject, + up, _currentPosition, step, _walkDirection, - _maxSlopeCosine, + _maxSlopeCosine, _radius, _halfHeight); callback2.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; @@ -542,8 +542,8 @@ void CharacterController::reset(btCollisionWorld* collisionWorld) { //clear pair cache btHashedOverlappingPairCache *cache = _ghostObject->getOverlappingPairCache(); while (cache->getOverlappingPairArray().size() > 0) { - cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, - cache->getOverlappingPairArray()[0].m_pProxy1, + cache->removeOverlappingPair(cache->getOverlappingPairArray()[0].m_pProxy0, + cache->getOverlappingPairArray()[0].m_pProxy1, collisionWorld->getDispatcher()); } } @@ -712,7 +712,7 @@ void CharacterController::setEnabled(bool enabled) { // Setting the ADD bit here works for all cases so we don't even bother checking other bits. _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; } else { - // Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case + // Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case // it was previously set by something else (e.g. an UPDATE_SHAPE event). _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; @@ -754,7 +754,7 @@ void CharacterController::updateShapeIfNecessary() { _ghostObject = NULL; delete _convexShape; _convexShape = NULL; - + // compute new dimensions from avatar's bounding box float x = _boxScale.x; float z = _boxScale.z; @@ -765,18 +765,18 @@ void CharacterController::updateShapeIfNecessary() { _halfHeight = MIN_HALF_HEIGHT; } // NOTE: _shapeLocalOffset is already computed - + if (_radius > 0.0f) { // create new ghost _ghostObject = new btPairCachingGhostObject(); _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), glmToBullet(_avatarData->getPosition()))); // stepHeight affects the heights of ledges that the character can ascend - // however the actual ledge height is some function of _stepHeight - // due to character shape and this CharacterController algorithm + // however the actual ledge height is some function of _stepHeight + // due to character shape and this CharacterController algorithm // (the function is approximately 2*_stepHeight) _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; - + // create new shape _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); _ghostObject->setCollisionShape(_convexShape); @@ -807,11 +807,11 @@ void CharacterController::preSimulation(btScalar timeStep) { void CharacterController::postSimulation() { if (_enabled) { - const btTransform& avatarTransform = _ghostObject->getWorldTransform(); + const btTransform& avatarTransform = _ghostObject->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); glm::vec3 offset = rotation * _shapeLocalOffset; _avatarData->setOrientation(rotation); - _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); + _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); } } From 045dbb11a369ba3b4e7e0675e41dbc5a12f6f955 Mon Sep 17 00:00:00 2001 From: Sam Gateau <sam@highfidelity.io> Date: Wed, 25 Mar 2015 11:07:19 -0700 Subject: [PATCH 096/177] Putting the GLERRORCHECK only in debug --- libraries/gpu/src/gpu/GLBackendShared.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libraries/gpu/src/gpu/GLBackendShared.h b/libraries/gpu/src/gpu/GLBackendShared.h index 1853573522..f51e455447 100644 --- a/libraries/gpu/src/gpu/GLBackendShared.h +++ b/libraries/gpu/src/gpu/GLBackendShared.h @@ -49,7 +49,10 @@ static const GLenum _elementTypeToGLType[NUM_TYPES]= { GL_UNSIGNED_BYTE }; +#if _DEBUG #define CHECK_GL_ERROR() ::gpu::GLBackend::checkGLError() -//#define CHECK_GL_ERROR() +#else +#define CHECK_GL_ERROR() +#endif #endif From dec89ba96f1ef02e03cc456487174fa7dcb0e78e Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Wed, 25 Mar 2015 11:22:07 -0700 Subject: [PATCH 097/177] Disable duplicating locked entities --- examples/libraries/entitySelectionTool.js | 24 +++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/examples/libraries/entitySelectionTool.js b/examples/libraries/entitySelectionTool.js index c261e0d8a6..b6c536f063 100644 --- a/examples/libraries/entitySelectionTool.js +++ b/examples/libraries/entitySelectionTool.js @@ -1263,11 +1263,13 @@ SelectionDisplay = (function () { duplicatedEntityIDs = []; for (var otherEntityID in SelectionManager.savedProperties) { var properties = SelectionManager.savedProperties[otherEntityID]; - var entityID = Entities.addEntity(properties); - duplicatedEntityIDs.push({ - entityID: entityID, - properties: properties, - }); + if (!properties.locked) { + var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties, + }); + } } } else { duplicatedEntityIDs = null; @@ -1361,11 +1363,13 @@ SelectionDisplay = (function () { duplicatedEntityIDs = []; for (var otherEntityID in SelectionManager.savedProperties) { var properties = SelectionManager.savedProperties[otherEntityID]; - var entityID = Entities.addEntity(properties); - duplicatedEntityIDs.push({ - entityID: entityID, - properties: properties, - }); + if (!properties.locked) { + var entityID = Entities.addEntity(properties); + duplicatedEntityIDs.push({ + entityID: entityID, + properties: properties, + }); + } } } else { duplicatedEntityIDs = null; From 5b4b78043aa0192eb1e2af1057cb86bd8d20e6fc Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Wed, 25 Mar 2015 11:22:28 -0700 Subject: [PATCH 098/177] Remove unneeded print messages --- examples/look.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/look.js b/examples/look.js index bcdfcf9e44..6bba57e3ad 100644 --- a/examples/look.js +++ b/examples/look.js @@ -80,7 +80,6 @@ function touchBeginEvent(event) { yawFromTouch = 0; pitchFromTouch = 0; startedTouching = true; - print("TOUCH BEGIN"); } function touchEndEvent(event) { @@ -88,7 +87,6 @@ function touchEndEvent(event) { print("touchEndEvent event.x,y=" + event.x + ", " + event.y); } startedTouching = false; - print("TOUCH END"); } function touchUpdateEvent(event) { From c3c1d4a5ae3d1c4d1d7c1c65ee56657fac0f5b34 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo <leo@highfidelity.io> Date: Wed, 25 Mar 2015 12:36:37 -0600 Subject: [PATCH 099/177] Switching to .com --- interface/src/ui/LoginDialog.cpp | 2 +- interface/ui/loginDialog.ui | 4 ++-- libraries/networking/src/LimitedNodeList.cpp | 2 +- libraries/script-engine/src/XMLHttpRequestClass.cpp | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/interface/src/ui/LoginDialog.cpp b/interface/src/ui/LoginDialog.cpp index 004f863901..4e7a4a7dc9 100644 --- a/interface/src/ui/LoginDialog.cpp +++ b/interface/src/ui/LoginDialog.cpp @@ -23,7 +23,7 @@ #include "LoginDialog.h" #include "UIUtil.h" -const QString FORGOT_PASSWORD_URL = "https://metaverse.highfidelity.io/users/password/new"; +const QString FORGOT_PASSWORD_URL = "https://metaverse.highfidelity.com/users/password/new"; LoginDialog::LoginDialog(QWidget* parent) : FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP), diff --git a/interface/ui/loginDialog.ui b/interface/ui/loginDialog.ui index c986db7f50..58ff353a16 100644 --- a/interface/ui/loginDialog.ui +++ b/interface/ui/loginDialog.ui @@ -136,7 +136,7 @@ <string><style type="text/css"> a { text-decoration: none; color: #267077;} </style> -Invalid username or password. <a href="https://metaverse.highfidelity.io/password/new">Recover?</a></string> +Invalid username or password. <a href="https://metaverse.highfidelity.com/password/new">Recover?</a></string> </property> <property name="alignment"> <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set> @@ -458,7 +458,7 @@ border-radius: 4px; padding-top: 1px;</string> <string><style type="text/css"> a { text-decoration: none; color: #267077;} </style> -<a href="https://metaverse.highfidelity.io/password/new">Recover password?</a></string> +<a href="https://metaverse.highfidelity.com/password/new">Recover password?</a></string> </property> <property name="openExternalLinks"> <bool>true</bool> diff --git a/libraries/networking/src/LimitedNodeList.cpp b/libraries/networking/src/LimitedNodeList.cpp index 98e1ed0572..ebd10b67a6 100644 --- a/libraries/networking/src/LimitedNodeList.cpp +++ b/libraries/networking/src/LimitedNodeList.cpp @@ -36,7 +36,7 @@ const char SOLO_NODE_TYPES[2] = { NodeType::AudioMixer }; -const QUrl DEFAULT_NODE_AUTH_URL = QUrl("https://metaverse.highfidelity.io"); +const QUrl DEFAULT_NODE_AUTH_URL = QUrl("https://metaverse.highfidelity.com"); LimitedNodeList::LimitedNodeList(unsigned short socketListenPort, unsigned short dtlsListenPort) : linkedDataCreateCallback(NULL), diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 116548db61..8755527860 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -207,7 +207,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a notImplemented(); } } else { - if (url.toLower().left(33) == "https://metaverse.highfidelity.io/api/") { + if (url.toLower().left(33) == "https://metaverse.highfidelity.com/api/") { AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.hasValidAccessToken()) { From 89e5fef808ee7b56546620fb22306fc1251ff98a Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Wed, 25 Mar 2015 11:46:08 -0700 Subject: [PATCH 100/177] send friends_only key for discoverability --- interface/src/DiscoverabilityManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 49850e4ef6..76081b1293 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -61,6 +61,9 @@ void DiscoverabilityManager::updateLocation() { uuidStringWithoutCurlyBraces(domainHandler.getUUID())); } + const QString FRIENDS_ONLY_KEY_IN_LOCATION = "friends_only"; + locationObject.insert(FRIENDS_ONLY_KEY_IN_LOCATION, (_mode.get() == Discoverability::Friends)); + rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, From 4bf8e9f6254a6b86dcc61ea6ddd6ac8d9dd494f2 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Wed, 25 Mar 2015 12:04:04 -0700 Subject: [PATCH 101/177] change AccountManager request API, leverage in networking and DS --- domain-server/src/DomainServer.cpp | 20 +++-- libraries/networking/src/AccountManager.cpp | 74 ++++++++----------- libraries/networking/src/AccountManager.h | 38 +++++----- libraries/networking/src/AddressManager.cpp | 18 ++--- .../networking/src/UserActivityLogger.cpp | 9 +-- 5 files changed, 71 insertions(+), 88 deletions(-) diff --git a/domain-server/src/DomainServer.cpp b/domain-server/src/DomainServer.cpp index 57e133c599..0918b85a63 100644 --- a/domain-server/src/DomainServer.cpp +++ b/domain-server/src/DomainServer.cpp @@ -814,8 +814,9 @@ void DomainServer::requestUserPublicKey(const QString& username) { qDebug() << "Requesting public key for user" << username; - AccountManager::getInstance().unauthenticatedRequest(USER_PUBLIC_KEY_PATH.arg(username), - QNetworkAccessManager::GetOperation, callbackParams); + AccountManager::getInstance().sendRequest(USER_PUBLIC_KEY_PATH.arg(username), + AccountManagerAuth::None, + QNetworkAccessManager::GetOperation, callbackParams); } QUrl DomainServer::oauthRedirectURL() { @@ -1116,8 +1117,10 @@ void DomainServer::sendPendingTransactionsToServer() { transactionCallbackParams.jsonCallbackMethod = "transactionJSONCallback"; while (i != _pendingAssignmentCredits.end()) { - accountManager.authenticatedRequest("api/v1/transactions", QNetworkAccessManager::PostOperation, - transactionCallbackParams, i.value()->postJson().toJson()); + accountManager.sendRequest("api/v1/transactions", + AccountManagerAuth::Required, + QNetworkAccessManager::PostOperation, + transactionCallbackParams, i.value()->postJson().toJson()); // set this transaction to finalized so we don't add additional credits to it i.value()->setIsFinalized(true); @@ -1240,10 +1243,11 @@ void DomainServer::sendHeartbeatToDataServer(const QString& networkAddress) { QString domainUpdateJSON = QString("{\"domain\": %1 }").arg(QString(QJsonDocument(domainObject).toJson())); - AccountManager::getInstance().authenticatedRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), - QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), - domainUpdateJSON.toUtf8()); + AccountManager::getInstance().sendRequest(DOMAIN_UPDATE.arg(uuidStringWithoutCurlyBraces(domainID)), + AccountManagerAuth::Required, + QNetworkAccessManager::PutOperation, + JSONCallbackParameters(), + domainUpdateJSON.toUtf8()); } // todo: have data-web respond with ice-server hostname to use diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 2a809f2a7c..5858c0926d 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -115,7 +115,7 @@ void AccountManager::updateBalance() { callbackParameters.jsonCallbackReceiver = &_accountInfo; callbackParameters.jsonCallbackMethod = "setBalanceFromJSON"; - authenticatedRequest("/api/v1/wallets/mine", QNetworkAccessManager::GetOperation, callbackParameters); + sendRequest("/api/v1/wallets/mine", AccountManagerAuth::Required, QNetworkAccessManager::GetOperation, callbackParameters); } } @@ -159,50 +159,30 @@ void AccountManager::setAuthURL(const QUrl& authURL) { } } -void AccountManager::authenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, - const QByteArray& dataByteArray, - QHttpMultiPart* dataMultiPart, - const QVariantMap& propertyMap) { +void AccountManager::sendRequest(const QString& path, + AccountManagerAuth::Type authType, + QNetworkAccessManager::Operation operation, + const JSONCallbackParameters& callbackParams, + const QByteArray& dataByteArray, + QHttpMultiPart* dataMultiPart, + const QVariantMap& propertyMap) { - QMetaObject::invokeMethod(this, "invokedRequest", - Q_ARG(const QString&, path), - Q_ARG(bool, true), - Q_ARG(QNetworkAccessManager::Operation, operation), - Q_ARG(const JSONCallbackParameters&, callbackParams), - Q_ARG(const QByteArray&, dataByteArray), - Q_ARG(QHttpMultiPart*, dataMultiPart), - Q_ARG(QVariantMap, propertyMap)); -} - -void AccountManager::unauthenticatedRequest(const QString& path, QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, - const QByteArray& dataByteArray, - QHttpMultiPart* dataMultiPart, - const QVariantMap& propertyMap) { + if (thread() != QThread::currentThread()) { + QMetaObject::invokeMethod(this, "sendRequest", + Q_ARG(const QString&, path), + Q_ARG(AccountManagerAuth::Type, AccountManagerAuth::Required), + Q_ARG(QNetworkAccessManager::Operation, operation), + Q_ARG(const JSONCallbackParameters&, callbackParams), + Q_ARG(const QByteArray&, dataByteArray), + Q_ARG(QHttpMultiPart*, dataMultiPart), + Q_ARG(QVariantMap, propertyMap)); + } - QMetaObject::invokeMethod(this, "invokedRequest", - Q_ARG(const QString&, path), - Q_ARG(bool, false), - Q_ARG(QNetworkAccessManager::Operation, operation), - Q_ARG(const JSONCallbackParameters&, callbackParams), - Q_ARG(const QByteArray&, dataByteArray), - Q_ARG(QHttpMultiPart*, dataMultiPart), - Q_ARG(QVariantMap, propertyMap)); -} - -void AccountManager::invokedRequest(const QString& path, - bool requiresAuthentication, - QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, - const QByteArray& dataByteArray, QHttpMultiPart* dataMultiPart, - const QVariantMap& propertyMap) { - QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance(); - + QNetworkRequest networkRequest; networkRequest.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT); - + QUrl requestURL = _authURL; if (path.startsWith("/")) { @@ -211,13 +191,17 @@ void AccountManager::invokedRequest(const QString& path, requestURL.setPath("/" + path); } - if (requiresAuthentication) { + if (authType != AccountManagerAuth::None ) { if (hasValidAccessToken()) { networkRequest.setRawHeader(ACCESS_TOKEN_AUTHORIZATION_HEADER, _accountInfo.getAccessToken().authorizationHeaderValue()); } else { - qDebug() << "No valid access token present. Bailing on authenticated invoked request."; - return; + if (authType == AccountManagerAuth::Required) { + qDebug() << "No valid access token present. Bailing on invoked request to" + << path << "that requires authentication"; + return; + } + } } @@ -540,8 +524,8 @@ void AccountManager::processGeneratedKeypair(const QByteArray& publicKey, const requestMultiPart->append(keyPart); - authenticatedRequest(PUBLIC_KEY_UPDATE_PATH, QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), QByteArray(), requestMultiPart); + sendRequest(PUBLIC_KEY_UPDATE_PATH, AccountManagerAuth::Required, QNetworkAccessManager::PutOperation, + JSONCallbackParameters(), QByteArray(), requestMultiPart); // get rid of the keypair generator now that we don't need it anymore sender()->deleteLater(); diff --git a/libraries/networking/src/AccountManager.h b/libraries/networking/src/AccountManager.h index 2c9a441db1..b9c85d71e0 100644 --- a/libraries/networking/src/AccountManager.h +++ b/libraries/networking/src/AccountManager.h @@ -37,6 +37,16 @@ public: QString updateSlot; }; +namespace AccountManagerAuth { + enum Type { + None, + Required, + Optional + }; +} + +Q_DECLARE_METATYPE(AccountManagerAuth::Type); + const QByteArray ACCESS_TOKEN_AUTHORIZATION_HEADER = "Authorization"; class AccountManager : public QObject { @@ -44,19 +54,13 @@ class AccountManager : public QObject { public: static AccountManager& getInstance(bool forceReset = false); - void authenticatedRequest(const QString& path, - QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, - const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), - const QByteArray& dataByteArray = QByteArray(), - QHttpMultiPart* dataMultiPart = NULL, - const QVariantMap& propertyMap = QVariantMap()); - - void unauthenticatedRequest(const QString& path, - QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, - const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), - const QByteArray& dataByteArray = QByteArray(), - QHttpMultiPart* dataMultiPart = NULL, - const QVariantMap& propertyMap = QVariantMap()) ; + Q_INVOKABLE void sendRequest(const QString& path, + AccountManagerAuth::Type authType, + QNetworkAccessManager::Operation operation = QNetworkAccessManager::GetOperation, + const JSONCallbackParameters& callbackParams = JSONCallbackParameters(), + const QByteArray& dataByteArray = QByteArray(), + QHttpMultiPart* dataMultiPart = NULL, + const QVariantMap& propertyMap = QVariantMap()); const QUrl& getAuthURL() const { return _authURL; } void setAuthURL(const QUrl& authURL); @@ -107,14 +111,6 @@ private: void passSuccessToCallback(QNetworkReply* reply); void passErrorToCallback(QNetworkReply* reply); - Q_INVOKABLE void invokedRequest(const QString& path, - bool requiresAuthentication, - QNetworkAccessManager::Operation operation, - const JSONCallbackParameters& callbackParams, - const QByteArray& dataByteArray, - QHttpMultiPart* dataMultiPart, - const QVariantMap& propertyMap); - QUrl _authURL; QMap<QNetworkReply*, JSONCallbackParameters> _pendingCallbackMap; diff --git a/libraries/networking/src/AddressManager.cpp b/libraries/networking/src/AddressManager.cpp index 0458a5e912..3c27c4644c 100644 --- a/libraries/networking/src/AddressManager.cpp +++ b/libraries/networking/src/AddressManager.cpp @@ -294,12 +294,11 @@ void AddressManager::attemptPlaceNameLookup(const QString& lookupString, const Q requestParams.insert(OVERRIDE_PATH_KEY, overridePath); } - AccountManager::getInstance().unauthenticatedRequest(GET_PLACE.arg(placeName), - QNetworkAccessManager::GetOperation, - apiCallbackParameters(), - QByteArray(), - NULL, - requestParams); + AccountManager::getInstance().sendRequest(GET_PLACE.arg(placeName), + AccountManagerAuth::None, + QNetworkAccessManager::GetOperation, + apiCallbackParameters(), + QByteArray(), NULL, requestParams); } bool AddressManager::handleNetworkAddress(const QString& lookupString) { @@ -439,9 +438,10 @@ void AddressManager::setDomainInfo(const QString& hostname, quint16 port) { void AddressManager::goToUser(const QString& username) { QString formattedUsername = QUrl::toPercentEncoding(username); // this is a username - pull the captured name and lookup that user's location - AccountManager::getInstance().unauthenticatedRequest(GET_USER_LOCATION.arg(formattedUsername), - QNetworkAccessManager::GetOperation, - apiCallbackParameters()); + AccountManager::getInstance().sendRequest(GET_USER_LOCATION.arg(formattedUsername), + AccountManagerAuth::Optional, + QNetworkAccessManager::GetOperation, + apiCallbackParameters()); } void AddressManager::copyAddress() { diff --git a/libraries/networking/src/UserActivityLogger.cpp b/libraries/networking/src/UserActivityLogger.cpp index 64828708b2..89c0bd34bd 100644 --- a/libraries/networking/src/UserActivityLogger.cpp +++ b/libraries/networking/src/UserActivityLogger.cpp @@ -62,11 +62,10 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall params.errorCallbackMethod = "requestError"; } - accountManager.authenticatedRequest(USER_ACTIVITY_URL, - QNetworkAccessManager::PostOperation, - params, - NULL, - multipart); + accountManager.sendRequest(USER_ACTIVITY_URL, + AccountManagerAuth::Required, + QNetworkAccessManager::PostOperation, + params, NULL, multipart); } void UserActivityLogger::requestFinished(QNetworkReply& requestReply) { From 7a9c1e20abaac807136f6ef4d5aa073c32d06f91 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Wed, 25 Mar 2015 12:04:47 -0700 Subject: [PATCH 102/177] use new AccountManager API in DiscoverabilityManager --- interface/src/DiscoverabilityManager.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 76081b1293..791e5667c4 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -66,15 +66,16 @@ void DiscoverabilityManager::updateLocation() { rootObject.insert(LOCATION_KEY_IN_ROOT, locationObject); - accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::PutOperation, - JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); + accountManager.sendRequest(API_USER_LOCATION_PATH, AccountManagerAuth::Required, + QNetworkAccessManager::PutOperation, + JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); } } } void DiscoverabilityManager::removeLocation() { AccountManager& accountManager = AccountManager::getInstance(); - accountManager.authenticatedRequest(API_USER_LOCATION_PATH, QNetworkAccessManager::DeleteOperation); + accountManager.sendRequest(API_USER_LOCATION_PATH, AccountManagerAuth::Required, QNetworkAccessManager::DeleteOperation); } void DiscoverabilityManager::setDiscoverabilityMode(Discoverability::Mode discoverabilityMode) { From d1d183e190b58205d811a507bf0c10ecd06d9df6 Mon Sep 17 00:00:00 2001 From: Leonardo Murillo <leo@highfidelity.io> Date: Wed, 25 Mar 2015 13:05:10 -0600 Subject: [PATCH 103/177] More .com changes --- domain-server/resources/describe-settings.json | 4 ++-- domain-server/resources/web/js/settings.js | 6 +++--- examples/edit.js | 2 +- examples/libraries/modelUploader.js | 6 +++--- examples/lobby.js | 2 +- examples/users.js | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/domain-server/resources/describe-settings.json b/domain-server/resources/describe-settings.json index 4636c61367..0082bd84ae 100644 --- a/domain-server/resources/describe-settings.json +++ b/domain-server/resources/describe-settings.json @@ -6,7 +6,7 @@ { "name": "access_token", "label": "Access Token", - "help": "This is an access token generated on the <a href='https://metaverse.highfidelity.io/user/security' target='_blank'>My Security</a> page of your High Fidelity account.<br/>Generate a token with the 'domains' scope and paste it here.<br/>This is required to associate this domain-server with a domain in your account." + "help": "This is an access token generated on the <a href='https://metaverse.highfidelity.com/user/security' target='_blank'>My Security</a> page of your High Fidelity account.<br/>Generate a token with the 'domains' scope and paste it here.<br/>This is required to associate this domain-server with a domain in your account." }, { "name": "id", @@ -30,7 +30,7 @@ }, { "value": "disabled", - "label": "None: use the network information I have entered for this domain at metaverse.highfidelity.io" + "label": "None: use the network information I have entered for this domain at metaverse.highfidelity.com" } ] }, diff --git a/domain-server/resources/web/js/settings.js b/domain-server/resources/web/js/settings.js index f62515c863..4fac753959 100644 --- a/domain-server/resources/web/js/settings.js +++ b/domain-server/resources/web/js/settings.js @@ -652,7 +652,7 @@ function chooseFromHighFidelityDomains(clickedButton) { clickedButton.attr('disabled', 'disabled') // get a list of user domains from data-web - data_web_domains_url = "https://metaverse.highfidelity.io/api/v1/domains?access_token=" + data_web_domains_url = "https://metaverse.highfidelity.com/api/v1/domains?access_token=" $.getJSON(data_web_domains_url + Settings.initialValues.metaverse.access_token, function(data){ modal_buttons = { @@ -682,7 +682,7 @@ function chooseFromHighFidelityDomains(clickedButton) { modal_buttons["success"] = { label: 'Create new domain', callback: function() { - window.open("https://metaverse.highfidelity.io/user/domains", '_blank'); + window.open("https://metaverse.highfidelity.com/user/domains", '_blank'); } } modal_body = "<p>You do not have any domains in your High Fidelity account." + @@ -708,4 +708,4 @@ function chooseFromHighFidelityDomains(clickedButton) { title: "Access token required" }) } -} \ No newline at end of file +} diff --git a/examples/edit.js b/examples/edit.js index 72938e5ed4..70e51823b2 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -130,7 +130,7 @@ var importingSVOTextOverlay = Overlays.addOverlay("text", { visible: false, }); -var MARKETPLACE_URL = "https://metaverse.highfidelity.io/marketplace"; +var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace"; var marketplaceWindow = new WebWindow('Marketplace', MARKETPLACE_URL, 900, 700, false); marketplaceWindow.setVisible(false); diff --git a/examples/libraries/modelUploader.js b/examples/libraries/modelUploader.js index fcc96854ab..64a9e91203 100644 --- a/examples/libraries/modelUploader.js +++ b/examples/libraries/modelUploader.js @@ -21,8 +21,8 @@ modelUploader = (function () { //svoBuffer, mapping, geometry, - API_URL = "https://metaverse.highfidelity.io/api/v1/models", - MODEL_URL = "http://public.highfidelity.io/models/content", + API_URL = "https://metaverse.highfidelity.com/api/v1/models", + MODEL_URL = "http://public.highfidelity.com/models/content", NAME_FIELD = "name", SCALE_FIELD = "scale", FILENAME_FIELD = "filename", @@ -690,4 +690,4 @@ modelUploader = (function () { }; return that; -}()); \ No newline at end of file +}()); diff --git a/examples/lobby.js b/examples/lobby.js index 5d687dc07a..381107d65a 100644 --- a/examples/lobby.js +++ b/examples/lobby.js @@ -158,7 +158,7 @@ var places = {}; function changeLobbyTextures() { var req = new XMLHttpRequest(); - req.open("GET", "https://metaverse.highfidelity.io/api/v1/places?limit=21", false); + req.open("GET", "https://metaverse.highfidelity.com/api/v1/places?limit=21", false); req.send(); places = JSON.parse(req.responseText).data.places; diff --git a/examples/users.js b/examples/users.js index dec141127e..22fe89389f 100644 --- a/examples/users.js +++ b/examples/users.js @@ -34,7 +34,7 @@ var usersWindow = (function () { usersOnline, // Raw users data linesOfUsers = [], // Array of indexes pointing into usersOnline - API_URL = "https://metaverse.highfidelity.io/api/v1/users?status=online", + API_URL = "https://metaverse.highfidelity.com/api/v1/users?status=online", HTTP_GET_TIMEOUT = 60000, // ms = 1 minute usersRequest, processUsers, From ea3ec91f715542a4f7c49e49dac83051428c4587 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Wed, 25 Mar 2015 12:27:15 -0700 Subject: [PATCH 104/177] Remove inspect tool from edit.js --- examples/edit.js | 16 +--------------- 1 file changed, 1 insertion(+), 15 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 03137310b6..da0a226b93 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -76,7 +76,6 @@ var DEFAULT_DIMENSIONS = { var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS); -var MENU_INSPECT_TOOL_ENABLED = "Inspect Tool"; var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select"; var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus"; var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode"; @@ -553,18 +552,6 @@ function mousePressEvent(event) { // Event handled; do nothing. return; } - } else if (Menu.isOptionChecked(MENU_INSPECT_TOOL_ENABLED)) { - var result = findClickedEntity(event); - if (event.isRightButton) { - if (result !== null) { - var currentProperties = Entities.getEntityProperties(result.entityID); - cameraManager.enable(); - cameraManager.focus(currentProperties.position, null, Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); - cameraManager.mousePressEvent(event); - } - } else { - cameraManager.mousePressEvent(event); - } } } @@ -780,7 +767,7 @@ function setupModelMenus() { Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities", shortcutKey: "CTRL+META+I", afterItem: "Export Entities" }); Menu.addMenuItem({ menuName: "File", menuItemName: "Import Entities from URL", shortcutKey: "CTRL+META+U", afterItem: "Import Entities" }); - Menu.addMenuItem({ menuName: "View", menuItemName: MENU_AUTO_FOCUS_ON_SELECT, afterItem: MENU_INSPECT_TOOL_ENABLED, + Menu.addMenuItem({ menuName: "View", menuItemName: MENU_AUTO_FOCUS_ON_SELECT, isCheckable: true, isChecked: Settings.getValue(SETTING_AUTO_FOCUS_ON_SELECT) == "true" }); Menu.addMenuItem({ menuName: "View", menuItemName: MENU_EASE_ON_FOCUS, afterItem: MENU_AUTO_FOCUS_ON_SELECT, isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" }); @@ -811,7 +798,6 @@ function cleanupModelMenus() { Menu.removeMenuItem("File", "Import Entities"); Menu.removeMenuItem("File", "Import Entities from URL"); - Menu.removeMenuItem("View", MENU_INSPECT_TOOL_ENABLED); Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT); Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS); Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE); From 8eed2b6603ddc160502d052e259c697c139c7df0 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Wed, 25 Mar 2015 12:28:56 -0700 Subject: [PATCH 105/177] Add PopupMenu to edit.js --- examples/edit.js | 123 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/examples/edit.js b/examples/edit.js index da0a226b93..fc427a3add 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1210,4 +1210,127 @@ PropertiesTool = function(opts) { return that; }; +PopupMenu = function() { + var self = this; + + var MENU_ITEM_HEIGHT = 21; + var MENU_ITEM_SPACING = 1; + var TEXT_MARGIN = 7; + + var overlays = []; + var overlayInfo = {}; + + var upColor = { red: 0, green: 0, blue: 0 }; + var downColor = { red: 192, green: 192, blue: 192 }; + var overColor = { red: 128, green: 128, blue: 128 }; + + self.onSelectMenuItem = function() { }; + + self.addMenuItem = function(name) { + var id = Overlays.addOverlay("text", { + text: name, + backgroundAlpha: 1.0, + backgroundColor: upColor, + topMargin: TEXT_MARGIN, + leftMargin: TEXT_MARGIN, + width: 210, + height: MENU_ITEM_HEIGHT, + font: { size: 12 }, + visible: false, + }); + overlays.push(id); + overlayInfo[id] = { name: name }; + return id; + }; + + self.updateMenuItemText = function(id, newText) { + Overlays.editOverlay(id, { text: newText }); + }; + + self.setPosition = function(x, y) { + for (var key in overlayInfo) { + Overlays.editOverlay(key, { + x: x, + y: y, + }); + y += MENU_ITEM_HEIGHT + MENU_ITEM_SPACING; + } + }; + + self.onSelected = function() { }; + + var pressingOverlay = null; + var hoveringOverlay = null; + + self.mousePressEvent = function(event) { + if (event.isLeftButton) { + var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + if (overlay in overlayInfo) { + pressingOverlay = overlay; + Overlays.editOverlay(pressingOverlay, { backgroundColor: downColor }); + } else { + self.hide(); + } + return false; + } + }; + self.mouseMoveEvent = function(event) { + if (visible) { + var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + if (!pressingOverlay) { + if (hoveringOverlay != null && overlay != hoveringOverlay) { + Overlays.editOverlay(hoveringOverlay, { backgroundColor: upColor}); + hoveringOverlay = null; + } + if (overlay != hoveringOverlay && overlay in overlayInfo) { + Overlays.editOverlay(overlay, { backgroundColor: overColor }); + hoveringOverlay = overlay; + } + } + } + return false; + }; + self.mouseReleaseEvent = function(event) { + var overlay = Overlays.getOverlayAtPoint({ x: event.x, y: event.y }); + if (pressingOverlay != null) { + if (overlay == pressingOverlay) { + self.onSelectMenuItem(overlayInfo[overlay].name); + } + Overlays.editOverlay(pressingOverlay, { backgroundColor: upColor }); + pressingOverlay = null; + self.hide(); + } + }; + + var visible = false; + + self.setVisible = function(newVisible) { + if (newVisible != visible) { + visible = newVisible; + for (var key in overlayInfo) { + Overlays.editOverlay(key, { visible: newVisible }); + } + } + } + self.show = function() { + self.setVisible(true); + } + self.hide = function() { + self.setVisible(false); + } + + function cleanup() { + for (var i = 0; i < overlays.length; i++) { + Overlays.deleteOverlay(overlays[i]); + } + } + + Controller.mousePressEvent.connect(self.mousePressEvent); + Controller.mouseMoveEvent.connect(self.mouseMoveEvent); + Controller.mouseReleaseEvent.connect(self.mouseReleaseEvent); + Script.scriptEnding.connect(cleanup); + + return this; +}; + propertiesTool = PropertiesTool(); From d07acfe9aceb675e548a378812f94b52a2a97484 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Wed, 25 Mar 2015 12:29:38 -0700 Subject: [PATCH 106/177] Add right-click marketplace popup --- examples/edit.js | 177 ++++++++++++++++++++++++++++------------------- 1 file changed, 107 insertions(+), 70 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index fc427a3add..cdc3822fb2 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -543,7 +543,7 @@ function mousePressEvent(event) { mouseHasMovedSincePress = false; mouseCapturedByTool = false; - if (toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) { + if (propertyMenu.mousePressEvent(event) || toolBar.mousePressEvent(event) || progressDialog.mousePressEvent(event)) { mouseCapturedByTool = true; return; } @@ -563,6 +563,8 @@ var IDLE_MOUSE_TIMEOUT = 200; var DEFAULT_ENTITY_DRAG_DROP_DISTANCE = 2.0; function mouseMoveEvent(event) { + mouseHasMovedSincePress = true; + if (placingEntityID) { if (!placingEntityID.isKnownID) { placingEntityID = Entities.identifyEntity(placingEntityID); @@ -583,10 +585,8 @@ function mouseMoveEvent(event) { Script.clearTimeout(idleMouseTimerId); } - mouseHasMovedSincePress = true; - // allow the selectionDisplay and cameraManager to handle the event first, if it doesn't handle it, then do our own thing - if (selectionDisplay.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) { + if (selectionDisplay.mouseMoveEvent(event) || propertyMenu.mouseMoveEvent(event) || cameraManager.mouseMoveEvent(event)) { return; } @@ -631,7 +631,7 @@ function highlightEntityUnderCursor(position, accurateRay) { function mouseReleaseEvent(event) { - if (toolBar.mouseReleaseEvent(event)) { + if (propertyMenu.mouseReleaseEvent(event) || toolBar.mouseReleaseEvent(event)) { return true; } if (placingEntityID) { @@ -655,74 +655,94 @@ function mouseReleaseEvent(event) { } function mouseClickEvent(event) { - if (!event.isLeftButton || !isActive) { - return; - } - - var result = findClickedEntity(event); - if (result === null) { - if (!event.isShifted) { - selectionManager.clearSelections(); - } - return; - } - toolBar.setActive(true); - var pickRay = result.pickRay; - var foundEntity = result.entityID; - - var properties = Entities.getEntityProperties(foundEntity); - if (isLocked(properties)) { - print("Model locked " + properties.id); - } else { - var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal); - // P P - Model - // /| A - Palm - // / | d B - unit vector toward tip - // / | X - base of the perpendicular line - // A---X----->B d - distance fom axis - // x x - distance from A - // - // |X-A| = (P-A).B - // X == A + ((P-A).B)B - // d = |P-X| - - var A = pickRay.origin; - var B = Vec3.normalize(pickRay.direction); - var P = properties.position; - - var x = Vec3.dot(Vec3.subtract(P, A), B); - var X = Vec3.sum(A, Vec3.multiply(B, x)); - var d = Vec3.length(Vec3.subtract(P, X)); - var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; - - var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; - - var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) - && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); - - if (0 < x && sizeOK) { - entitySelected = true; - selectedEntityID = foundEntity; - orientation = MyAvatar.orientation; - intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); - - + print("CLICK"); + if (isActive && event.isLeftButton) { + var result = findClickedEntity(event); + if (result === null) { if (!event.isShifted) { - selectionManager.setSelections([foundEntity]); + selectionManager.clearSelections(); + } + return; + } + toolBar.setActive(true); + var pickRay = result.pickRay; + var foundEntity = result.entityID; + + var properties = Entities.getEntityProperties(foundEntity); + if (isLocked(properties)) { + print("Model locked " + properties.id); + } else { + var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; + + print("Checking properties: " + properties.id + " " + properties.isKnownID + " - Half Diagonal:" + halfDiagonal); + // P P - Model + // /| A - Palm + // / | d B - unit vector toward tip + // / | X - base of the perpendicular line + // A---X----->B d - distance fom axis + // x x - distance from A + // + // |X-A| = (P-A).B + // X == A + ((P-A).B)B + // d = |P-X| + + var A = pickRay.origin; + var B = Vec3.normalize(pickRay.direction); + var P = properties.position; + + var x = Vec3.dot(Vec3.subtract(P, A), B); + var X = Vec3.sum(A, Vec3.multiply(B, x)); + var d = Vec3.length(Vec3.subtract(P, X)); + var halfDiagonal = Vec3.length(properties.dimensions) / 2.0; + + var angularSize = 2 * Math.atan(halfDiagonal / Vec3.distance(Camera.getPosition(), properties.position)) * 180 / 3.14; + + var sizeOK = (allowLargeModels || angularSize < MAX_ANGULAR_SIZE) + && (allowSmallModels || angularSize > MIN_ANGULAR_SIZE); + + if (0 < x && sizeOK) { + entitySelected = true; + selectedEntityID = foundEntity; + orientation = MyAvatar.orientation; + intersection = rayPlaneIntersection(pickRay, P, Quat.getFront(orientation)); + + + if (!event.isShifted) { + selectionManager.setSelections([foundEntity]); + } else { + selectionManager.addEntity(foundEntity, true); + } + + print("Model selected: " + foundEntity.id); + selectionDisplay.select(selectedEntityID, event); + + if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) { + cameraManager.focus(selectionManager.worldPosition, + selectionManager.worldDimensions, + Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); + } + } + } + } else if (event.isRightButton) { + var result = findClickedEntity(event); + if (result) { + var properties = Entities.getEntityProperties(result.entityID); + var data = {}; + try { + data = JSON.parse(properties.attribution); + } catch (e) { + } + if (data.marketplaceID) { + propertyMenu.marketplaceID = data.marketplaceID; + propertyMenu.updateMenuItemText(showMenuItem, "Show in Marketplace"); } else { - selectionManager.addEntity(foundEntity, true); - } - - print("Model selected: " + foundEntity.id); - selectionDisplay.select(selectedEntityID, event); - - if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) { - cameraManager.focus(selectionManager.worldPosition, - selectionManager.worldDimensions, - Menu.isOptionChecked(MENU_EASE_ON_FOCUS)); + propertyMenu.marketplaceID = null; + propertyMenu.updateMenuItemText(showMenuItem, "No marketplace info"); } + propertyMenu.setPosition(event.x, event.y); + propertyMenu.show(); + } else { + propertyMenu.hide(); } } } @@ -1137,6 +1157,8 @@ PropertiesTool = function(opts) { if (marketplaceWindow.url != data.url) { marketplaceWindow.setURL(data.url); } + marketplaceWindow.setVisible(true); + marketplaceWindow.raise(); } else if (data.type == "action") { if (data.action == "moveSelectionToGrid") { if (selectionManager.hasSelection()) { @@ -1333,4 +1355,19 @@ PopupMenu = function() { return this; }; +var propertyMenu = PopupMenu(); + +propertyMenu.onSelectMenuItem = function(name) { + if (propertyMenu.marketplaceID) { + var url = "https://metaverse.highfidelity.io/marketplace/items/" + propertyMenu.marketplaceID; + if (marketplaceWindow.url != url) { + marketplaceWindow.setURL(url); + } + marketplaceWindow.setVisible(true); + marketplaceWindow.raise(); + } +}; + +var showMenuItem = propertyMenu.addMenuItem("Show in Marketplace"); + propertiesTool = PropertiesTool(); From b8174b164f06d49fc708ecb7c200ef305dc62d51 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Wed, 25 Mar 2015 12:29:57 -0700 Subject: [PATCH 107/177] Update marketplace popup to hide on position or orientation change --- examples/edit.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/edit.js b/examples/edit.js index cdc3822fb2..fd197349aa 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -839,11 +839,21 @@ Script.scriptEnding.connect(function() { Overlays.deleteOverlay(importingSVOTextOverlay); }); +var lastOrientation = null; +var lastPosition = null; + // Do some stuff regularly, like check for placement of various overlays Script.update.connect(function (deltaTime) { toolBar.move(); progressDialog.move(); selectionDisplay.checkMove(); + var dOrientation = Math.abs(Quat.dot(Camera.orientation, lastOrientation) - 1); + var dPosition = Vec3.distance(Camera.position, lastPosition); + if (dOrientation > 0.001 || dPosition > 0.001) { + propertyMenu.hide(); + lastOrientation = Camera.orientation; + lastPosition = Camera.position; + } }); function insideBox(center, dimensions, point) { From b5b1c5a90b10ebcb10bb6a519b70c1efcec93099 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Wed, 25 Mar 2015 12:30:42 -0700 Subject: [PATCH 108/177] Remove extraneous print --- examples/edit.js | 1 - 1 file changed, 1 deletion(-) diff --git a/examples/edit.js b/examples/edit.js index fd197349aa..80415ab418 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -655,7 +655,6 @@ function mouseReleaseEvent(event) { } function mouseClickEvent(event) { - print("CLICK"); if (isActive && event.isLeftButton) { var result = findClickedEntity(event); if (result === null) { From ec2b11640ce7606e004cc6909d85b6a9bd3cd390 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Wed, 25 Mar 2015 12:51:13 -0700 Subject: [PATCH 109/177] more tweaks to LOD logic --- interface/src/LODManager.cpp | 101 ++++++++++++++++++++++++----------- interface/src/LODManager.h | 39 +++++++++----- 2 files changed, 95 insertions(+), 45 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 8b942dcfe1..751bea8c23 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -40,26 +40,38 @@ float LODManager::getLODIncreaseFPS() { void LODManager::autoAdjustLOD(float currentFPS) { + // NOTE: our first ~100 samples at app startup are completely all over the place, and we don't // really want to count them in our average, so we will ignore the real frame rates and stuff // our moving average with simulated good data const int IGNORE_THESE_SAMPLES = 100; - const float ASSUMED_FPS = 60.0f; - if (_fpsAverage.getSampleCount() < IGNORE_THESE_SAMPLES) { + //const float ASSUMED_FPS = 60.0f; + if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) { currentFPS = ASSUMED_FPS; + _lastUpShift = _lastDownShift = usecTimestampNow(); } - _fpsAverage.updateAverage(currentFPS); - _fastFPSAverage.updateAverage(currentFPS); + _fpsAverageStartWindow.updateAverage(currentFPS); + _fpsAverageDownWindow.updateAverage(currentFPS); + _fpsAverageUpWindow.updateAverage(currentFPS); quint64 now = usecTimestampNow(); bool changed = false; bool octreeChanged = false; - quint64 elapsed = now - _lastAdjust; + quint64 elapsedSinceDownShift = now - _lastDownShift; + quint64 elapsedSinceUpShift = now - _lastUpShift; if (_automaticLODAdjust) { - // LOD Downward adjustment - if (elapsed > ADJUST_LOD_DOWN_DELAY && _fpsAverage.getAverage() < getLODDecreaseFPS()) { + + // LOD Downward adjustment + // If our last adjust was an upshift, then we don't want to consider any downshifts until we've delayed at least + // our START_DELAY_WINDOW_IN_SECS + bool doDownShift = _lastAdjustWasUpShift + ? (elapsedSinceUpShift > START_SHIFT_ELPASED && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()) + : (elapsedSinceDownShift > DOWN_SHIFT_ELPASED && _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS()); + + + if (doDownShift) { // Octree items... stepwise adjustment if (_octreeSizeScale > ADJUST_LOD_MIN_SIZE_SCALE) { @@ -70,37 +82,58 @@ void LODManager::autoAdjustLOD(float currentFPS) { octreeChanged = changed = true; } - if (changed) { - _lastAdjust = now; - qDebug() << "adjusting LOD down... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() - << "_octreeSizeScale=" << _octreeSizeScale; + if (changed) { + if (_lastAdjustWasUpShift) { + qDebug() << "adjusting LOD DOWN after initial delay..." + << "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was " + << _fpsAverageStartWindow.getAverage() + << "minimum is:" << getLODDecreaseFPS() + << "elapsedSinceUpShift:" << elapsedSinceUpShift + << " NEW _octreeSizeScale=" << _octreeSizeScale; + } else { + qDebug() << "adjusting LOD DOWN..." + << "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was " + << _fpsAverageDownWindow.getAverage() + << "minimum is:" << getLODDecreaseFPS() + << "elapsedSinceDownShift:" << elapsedSinceDownShift + << " NEW _octreeSizeScale=" << _octreeSizeScale; + } + + _lastDownShift = now; + _lastAdjustWasUpShift = false; emit LODDecreased(); } - } + } else { - // LOD Upward adjustment - if (elapsed > ADJUST_LOD_UP_DELAY && _fpsAverage.getAverage() > getLODIncreaseFPS()) { + // LOD Upward adjustment + if (elapsedSinceUpShift > UP_SHIFT_ELPASED && _fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) { - // Octee items... stepwise adjustment - if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { - if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; - } else { - _octreeSizeScale *= ADJUST_LOD_UP_BY; + // Octee items... stepwise adjustment + if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { + if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; + } else { + _octreeSizeScale *= ADJUST_LOD_UP_BY; + } + if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; + } + octreeChanged = changed = true; } - if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; - } - octreeChanged = changed = true; - } - if (changed) { - _lastAdjust = now; - qDebug() << "adjusting LOD up... average fps for last approximately 5 seconds=" << _fpsAverage.getAverage() - << "_octreeSizeScale=" << _octreeSizeScale; + if (changed) { + qDebug() << "adjusting LOD UP... average fps for last "<< UP_SHIFT_WINDOW_IN_SECS <<"seconds was " + << _fpsAverageUpWindow.getAverage() + << "upshift point is:" << getLODIncreaseFPS() + << "elapsedSinceUpShift:" << elapsedSinceUpShift + << " NEW _octreeSizeScale=" << _octreeSizeScale; - emit LODIncreased(); + _lastUpShift = now; + _lastAdjustWasUpShift = true; + + emit LODIncreased(); + } } } @@ -116,9 +149,13 @@ void LODManager::autoAdjustLOD(float currentFPS) { } void LODManager::resetLODAdjust() { - _fpsAverage.reset(); - _fastFPSAverage.reset(); + + // TODO: Do we need this??? + /* + _fpsAverageDownWindow.reset(); + _fpsAverageUpWindow.reset(); _lastAdjust = usecTimestampNow(); + */ } QString LODManager::getLODFeedbackText() { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index c14f17ca61..3f9d2046c1 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -19,10 +19,22 @@ const float DEFAULT_DESKTOP_LOD_DOWN_FPS = 30.0; const float DEFAULT_HMD_LOD_DOWN_FPS = 60.0; -const float INCREASE_LOD_GAP = 5.0f; +const float MAX_LIKELY_DESKTOP_FPS = 59.0; // this is essentially, V-synch - 1 fps +const float MAX_LIKELY_HMD_FPS = 74.0; // this is essentially, V-synch - 1 fps +const float INCREASE_LOD_GAP = 15.0f; -const quint64 ADJUST_LOD_DOWN_DELAY = 1000 * 1000 * 0.5; // Consider adjusting LOD down after half a second -const quint64 ADJUST_LOD_UP_DELAY = ADJUST_LOD_DOWN_DELAY * 2; +const float START_DELAY_WINDOW_IN_SECS = 3.0f; // wait at least this long after steady state/last upshift to consider downshifts +const float DOWN_SHIFT_WINDOW_IN_SECS = 0.5f; +const float UP_SHIFT_WINDOW_IN_SECS = 2.5f; + +const int ASSUMED_FPS = 60; +const quint64 START_SHIFT_ELPASED = USECS_PER_SECOND * START_DELAY_WINDOW_IN_SECS; +const quint64 DOWN_SHIFT_ELPASED = USECS_PER_SECOND * DOWN_SHIFT_WINDOW_IN_SECS; // Consider adjusting LOD down after half a second +const quint64 UP_SHIFT_ELPASED = USECS_PER_SECOND * UP_SHIFT_WINDOW_IN_SECS; + +const int START_DELAY_SAMPLES_OF_FRAMES = ASSUMED_FPS * START_DELAY_WINDOW_IN_SECS; +const int DOWN_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * DOWN_SHIFT_WINDOW_IN_SECS; +const int UP_SHIFT_SAMPLES_OF_FRAMES = ASSUMED_FPS * UP_SHIFT_WINDOW_IN_SECS; const float ADJUST_LOD_DOWN_BY = 0.9f; const float ADJUST_LOD_UP_BY = 1.1f; @@ -37,9 +49,6 @@ const float ADJUST_LOD_MAX_SIZE_SCALE = DEFAULT_OCTREE_SIZE_SCALE; // do. But both are still culled using the same angular size logic. const float AVATAR_TO_ENTITY_RATIO = 2.0f; -const int ONE_SECOND_OF_FRAMES = 60; -const int FIVE_SECONDS_OF_FRAMES = 5 * ONE_SECOND_OF_FRAMES; - class LODManager : public QObject, public Dependency { Q_OBJECT @@ -51,11 +60,11 @@ public: Q_INVOKABLE void setDesktopLODDecreaseFPS(float value) { _desktopLODDecreaseFPS = value; } Q_INVOKABLE float getDesktopLODDecreaseFPS() const { return _desktopLODDecreaseFPS; } - Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return _desktopLODDecreaseFPS + INCREASE_LOD_GAP; } + Q_INVOKABLE float getDesktopLODIncreaseFPS() const { return glm::min(_desktopLODDecreaseFPS + INCREASE_LOD_GAP, MAX_LIKELY_DESKTOP_FPS); } Q_INVOKABLE void setHMDLODDecreaseFPS(float value) { _hmdLODDecreaseFPS = value; } Q_INVOKABLE float getHMDLODDecreaseFPS() const { return _hmdLODDecreaseFPS; } - Q_INVOKABLE float getHMDLODIncreaseFPS() const { return _hmdLODDecreaseFPS + INCREASE_LOD_GAP; } + Q_INVOKABLE float getHMDLODIncreaseFPS() const { return glm::min(_hmdLODDecreaseFPS + INCREASE_LOD_GAP, MAX_LIKELY_HMD_FPS); } Q_INVOKABLE float getAvatarLODDistanceMultiplier() const { return _avatarLODDistanceMultiplier; } @@ -68,8 +77,8 @@ public: Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } Q_INVOKABLE void resetLODAdjust(); - Q_INVOKABLE float getFPSAverage() const { return _fpsAverage.getAverage(); } - Q_INVOKABLE float getFastFPSAverage() const { return _fastFPSAverage.getAverage(); } + //Q_INVOKABLE float getFPSAverage() const { return _fpsAverage.getAverage(); } + //Q_INVOKABLE float getFastFPSAverage() const { return _fastFPSAverage.getAverage(); } Q_INVOKABLE float getLODDecreaseFPS(); Q_INVOKABLE float getLODIncreaseFPS(); @@ -96,9 +105,13 @@ private: float _octreeSizeScale = DEFAULT_OCTREE_SIZE_SCALE; int _boundaryLevelAdjust = 0; - quint64 _lastAdjust = 0; - SimpleMovingAverage _fpsAverage = FIVE_SECONDS_OF_FRAMES; - SimpleMovingAverage _fastFPSAverage = ONE_SECOND_OF_FRAMES; + quint64 _lastDownShift = 0; + quint64 _lastUpShift = 0; + bool _lastAdjustWasUpShift = true; // start out as if we've just upshifted + + SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES; + SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES; + SimpleMovingAverage _fpsAverageUpWindow = UP_SHIFT_SAMPLES_OF_FRAMES; bool _shouldRenderTableNeedsRebuilding = true; QMap<float, float> _shouldRenderTable; From 429a258df031ff8ba1d4a68db9965217ca9f6652 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Wed, 25 Mar 2015 14:38:27 -0700 Subject: [PATCH 110/177] enable hover when far above floor --- libraries/physics/src/CharacterController.cpp | 65 ++++++++++++++++--- libraries/physics/src/CharacterController.h | 2 + 2 files changed, 58 insertions(+), 9 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index e84df7d644..84dcf25212 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -40,6 +40,24 @@ static btVector3 getNormalizedVector(const btVector3& v) { return n; } +class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { +public: + btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : + btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) { + m_me = me; + } + + virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { + if (rayResult.m_collisionObject == m_me) { + return 1.0; + } + return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace); + } +protected: + btCollisionObject* m_me; +}; + + class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: btKinematicClosestNotMeConvexResultCallback(btCollisionObject* me, const btVector3& up, btScalar minSlopeDot) @@ -215,6 +233,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { _jumpSpeed = 7.0f; _wasOnGround = false; _wasJumping = false; + _isHovering = true; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; _pendingFlags = 0; @@ -325,6 +344,27 @@ bool CharacterController::recoverFromPenetration(btCollisionWorld* collisionWorl return penetration; } +void CharacterController::scanDown(btCollisionWorld* world) { + // we test with downward raycast and if we don't find floor close enough then turn on "hover" + btKinematicClosestNotMeRayResultCallback callback(_ghostObject); + callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; + callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; + + btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); + btVector3 start = _currentPosition; + const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight; // closest possible floor for disabling hover + const btScalar MIN_HOVER_HEIGHT = 2.0f + _halfHeight; // distance to floor for enabling hover + btVector3 end = start - MAX_SCAN_HEIGHT * up; + + world->rayTest(start, end, callback); + bool wasHovering = _isHovering; + if (!callback.hasHit()) { + _isHovering = true; + } else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) { + _isHovering = false; + } +} + void CharacterController::stepUp(btCollisionWorld* world) { // phase 1: up @@ -495,7 +535,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; _currentPosition = _targetPosition; - btVector3 oldPosition = _currentPosition; step = (- _stepHeight) * up; _targetPosition = _currentPosition + step; @@ -510,7 +549,7 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _wasJumping = false; } else { // nothing to step down on, so remove the stepUp effect - _currentPosition = oldPosition - _lastStepUp * up; + //_currentPosition = oldPosition; _lastStepUp = 0.0f; } } else { @@ -581,14 +620,19 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar return; // no motion } - _wasOnGround = onGround(); - // Update fall velocity. - _verticalVelocity -= _gravity * dt; - if (_verticalVelocity > _jumpSpeed) { - _verticalVelocity = _jumpSpeed; - } else if (_verticalVelocity < -_maxFallSpeed) { - _verticalVelocity = -_maxFallSpeed; + if (_isHovering) { + _wasOnGround = false; + const btScalar HOVER_RELAXATION_TIMESCALE = 1.0f; + _verticalVelocity *= (1.0f - dt / HOVER_RELAXATION_TIMESCALE); + } else { + _wasOnGround = onGround(); + _verticalVelocity -= _gravity * dt; + if (_verticalVelocity > _jumpSpeed) { + _verticalVelocity = _jumpSpeed; + } else if (_verticalVelocity < -_maxFallSpeed) { + _verticalVelocity = -_maxFallSpeed; + } } _verticalOffset = _verticalVelocity * dt; @@ -600,6 +644,8 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // (2) step the character forward // (3) step the character down looking for new ledges, the original floor, or a floor one step below where we started + scanDown(collisionWorld); + stepUp(collisionWorld); // compute substep and decrement total interval @@ -711,6 +757,7 @@ void CharacterController::setEnabled(bool enabled) { // Don't bother clearing REMOVE bit since it might be paired with an UPDATE_SHAPE bit. // Setting the ADD bit here works for all cases so we don't even bother checking other bits. _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; + _isHovering = true; } else { // Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case // it was previously set by something else (e.g. an UPDATE_SHAPE event). diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 323529b1cd..f604e60c31 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -82,6 +82,7 @@ protected: bool _enabled; bool _wasOnGround; bool _wasJumping; + bool _isHovering; btScalar _velocityTimeInterval; uint32_t _pendingFlags; @@ -95,6 +96,7 @@ protected: btVector3 perpindicularComponent(const btVector3& direction, const btVector3& normal); bool recoverFromPenetration(btCollisionWorld* collisionWorld); + void scanDown(btCollisionWorld* collisionWorld); void stepUp(btCollisionWorld* collisionWorld); void updateTargetPositionBasedOnCollision(const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0)); void stepForward(btCollisionWorld* collisionWorld, const btVector3& walkMove); From dd9290bd5900ac5383cba268be3470545ec45a5c Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Wed, 25 Mar 2015 15:21:28 -0700 Subject: [PATCH 111/177] clear points for non-hull shapes --- libraries/shared/src/ShapeInfo.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libraries/shared/src/ShapeInfo.cpp b/libraries/shared/src/ShapeInfo.cpp index 73dd945f73..5fe1fc230d 100644 --- a/libraries/shared/src/ShapeInfo.cpp +++ b/libraries/shared/src/ShapeInfo.cpp @@ -23,6 +23,7 @@ void ShapeInfo::clear() { void ShapeInfo::setParams(ShapeType type, const glm::vec3& halfExtents, QString url) { _type = type; + _points.clear(); switch(type) { case SHAPE_TYPE_NONE: _halfExtents = glm::vec3(0.0f); @@ -56,6 +57,7 @@ void ShapeInfo::setBox(const glm::vec3& halfExtents) { _url = ""; _type = SHAPE_TYPE_BOX; _halfExtents = halfExtents; + _points.clear(); _doubleHashKey.clear(); } @@ -63,6 +65,7 @@ void ShapeInfo::setSphere(float radius) { _url = ""; _type = SHAPE_TYPE_SPHERE; _halfExtents = glm::vec3(radius, radius, radius); + _points.clear(); _doubleHashKey.clear(); } @@ -70,6 +73,7 @@ void ShapeInfo::setEllipsoid(const glm::vec3& halfExtents) { _url = ""; _type = SHAPE_TYPE_ELLIPSOID; _halfExtents = halfExtents; + _points.clear(); _doubleHashKey.clear(); } @@ -87,6 +91,7 @@ void ShapeInfo::setCapsuleY(float radius, float halfHeight) { _url = ""; _type = SHAPE_TYPE_CAPSULE_Y; _halfExtents = glm::vec3(radius, halfHeight, radius); + _points.clear(); _doubleHashKey.clear(); } From a3a54e8d7d8fe8059234699efe9202ed7f26361d Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Wed, 25 Mar 2015 15:21:36 -0700 Subject: [PATCH 112/177] style --- libraries/entities/src/ModelEntityItem.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index f135f617f4..55d809e70e 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -281,8 +281,7 @@ void ModelEntityItem::updateShapeType(ShapeType type) { } } -void ModelEntityItem::setCollisionModelURL(const QString& url) -{ +void ModelEntityItem::setCollisionModelURL(const QString& url) { if (_collisionModelURL != url) { _collisionModelURL = url; _dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS; From 923951143c062c15edbeec5f31c29e605d20d8da Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Wed, 25 Mar 2015 15:21:53 -0700 Subject: [PATCH 113/177] comment out line that's killing cmake for me --- tools/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5c7c306a62..ba2938aaa6 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -8,5 +8,5 @@ set_target_properties(scribe PROPERTIES FOLDER "Tools") find_package(VHACD) if(VHACD_FOUND) add_subdirectory(vhacd) -set_target_properties(vhacd PROPERTIES FOLDER "Tools") +# set_target_properties(vhacd PROPERTIES FOLDER "Tools") endif() From ef0281ab436e74ddf3de0c3e3c0b493daee49cbd Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Wed, 25 Mar 2015 15:30:03 -0700 Subject: [PATCH 114/177] use the new placename entry as entry point --- libraries/networking/src/AddressManager.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AddressManager.h b/libraries/networking/src/AddressManager.h index bfc3ace657..a2522afcbc 100644 --- a/libraries/networking/src/AddressManager.h +++ b/libraries/networking/src/AddressManager.h @@ -23,7 +23,7 @@ #include "AccountManager.h" const QString HIFI_URL_SCHEME = "hifi"; -const QString DEFAULT_HIFI_ADDRESS = "hifi://sandbox"; +const QString DEFAULT_HIFI_ADDRESS = "hifi://entry"; typedef const glm::vec3& (*PositionGetter)(); typedef glm::quat (*OrientationGetter)(); From 68e730af454938854d4220c92de521c53b399a18 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Wed, 25 Mar 2015 15:48:50 -0700 Subject: [PATCH 115/177] handle throttle render case and clean up code logic to be more obvious --- interface/src/LODManager.cpp | 46 ++++++++++++++++++++---------------- interface/src/LODManager.h | 2 +- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index 751bea8c23..e1a82372d2 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -50,6 +50,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { currentFPS = ASSUMED_FPS; _lastUpShift = _lastDownShift = usecTimestampNow(); } + _fpsAverageStartWindow.updateAverage(currentFPS); _fpsAverageDownWindow.updateAverage(currentFPS); _fpsAverageUpWindow.updateAverage(currentFPS); @@ -64,12 +65,17 @@ void LODManager::autoAdjustLOD(float currentFPS) { if (_automaticLODAdjust) { // LOD Downward adjustment - // If our last adjust was an upshift, then we don't want to consider any downshifts until we've delayed at least - // our START_DELAY_WINDOW_IN_SECS - bool doDownShift = _lastAdjustWasUpShift - ? (elapsedSinceUpShift > START_SHIFT_ELPASED && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()) - : (elapsedSinceDownShift > DOWN_SHIFT_ELPASED && _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS()); + // If we've been downshifting, we watch a shorter downshift window so that we will quickly move toward our + // target frame rate. But if we haven't just done a downshift (either because our last shift was an upshift, + // or because we've just started out) then we look at a much longer window to consider whether or not to start + // downshifting. + bool doDownShift = false; + if (_isDownshifting) { + doDownShift = (elapsedSinceDownShift > DOWN_SHIFT_ELPASED && _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS()); + } else { + doDownShift = (elapsedSinceUpShift > START_SHIFT_ELPASED && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()); + } if (doDownShift) { @@ -83,24 +89,26 @@ void LODManager::autoAdjustLOD(float currentFPS) { } if (changed) { - if (_lastAdjustWasUpShift) { - qDebug() << "adjusting LOD DOWN after initial delay..." - << "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was " - << _fpsAverageStartWindow.getAverage() - << "minimum is:" << getLODDecreaseFPS() - << "elapsedSinceUpShift:" << elapsedSinceUpShift - << " NEW _octreeSizeScale=" << _octreeSizeScale; - } else { + if (_isDownshifting) { + // subsequent downshift qDebug() << "adjusting LOD DOWN..." << "average fps for last "<< DOWN_SHIFT_WINDOW_IN_SECS <<"seconds was " << _fpsAverageDownWindow.getAverage() << "minimum is:" << getLODDecreaseFPS() << "elapsedSinceDownShift:" << elapsedSinceDownShift << " NEW _octreeSizeScale=" << _octreeSizeScale; + } else { + // first downshift + qDebug() << "adjusting LOD DOWN after initial delay..." + << "average fps for last "<< START_DELAY_WINDOW_IN_SECS <<"seconds was " + << _fpsAverageStartWindow.getAverage() + << "minimum is:" << getLODDecreaseFPS() + << "elapsedSinceUpShift:" << elapsedSinceUpShift + << " NEW _octreeSizeScale=" << _octreeSizeScale; } _lastDownShift = now; - _lastAdjustWasUpShift = false; + _isDownshifting = true; emit LODDecreased(); } @@ -130,7 +138,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { << " NEW _octreeSizeScale=" << _octreeSizeScale; _lastUpShift = now; - _lastAdjustWasUpShift = true; + _isDownshifting = false; emit LODIncreased(); } @@ -149,13 +157,11 @@ void LODManager::autoAdjustLOD(float currentFPS) { } void LODManager::resetLODAdjust() { - - // TODO: Do we need this??? - /* + _fpsAverageStartWindow.reset(); _fpsAverageDownWindow.reset(); _fpsAverageUpWindow.reset(); - _lastAdjust = usecTimestampNow(); - */ + _lastUpShift = _lastDownShift = usecTimestampNow(); + _isDownshifting = false; } QString LODManager::getLODFeedbackText() { diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 3f9d2046c1..d3765c164a 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -107,7 +107,7 @@ private: quint64 _lastDownShift = 0; quint64 _lastUpShift = 0; - bool _lastAdjustWasUpShift = true; // start out as if we've just upshifted + bool _isDownshifting = false; // start out as if we're not downshifting SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES; SimpleMovingAverage _fpsAverageDownWindow = DOWN_SHIFT_SAMPLES_OF_FRAMES; From f46067b634b7530ba7f84dc24d4e8469c79ab515 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Wed, 25 Mar 2015 16:30:33 -0700 Subject: [PATCH 116/177] better tracking of being done with downshifting --- interface/src/LODManager.cpp | 51 +++++++++++++++++++++++------------- interface/src/LODManager.h | 1 + 2 files changed, 34 insertions(+), 18 deletions(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index e1a82372d2..d12fe9147a 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -48,7 +48,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { //const float ASSUMED_FPS = 60.0f; if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) { currentFPS = ASSUMED_FPS; - _lastUpShift = _lastDownShift = usecTimestampNow(); + _lastStable = _lastUpShift = _lastDownShift = usecTimestampNow(); } _fpsAverageStartWindow.updateAverage(currentFPS); @@ -58,9 +58,11 @@ void LODManager::autoAdjustLOD(float currentFPS) { quint64 now = usecTimestampNow(); bool changed = false; - bool octreeChanged = false; quint64 elapsedSinceDownShift = now - _lastDownShift; quint64 elapsedSinceUpShift = now - _lastUpShift; + + quint64 lastStableOrUpshift = glm::max(_lastUpShift, _lastStable); + quint64 elapsedSinceStableOrUpShift = now - lastStableOrUpshift; if (_automaticLODAdjust) { @@ -72,9 +74,19 @@ void LODManager::autoAdjustLOD(float currentFPS) { bool doDownShift = false; if (_isDownshifting) { - doDownShift = (elapsedSinceDownShift > DOWN_SHIFT_ELPASED && _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS()); + // only consider things if our DOWN_SHIFT time has elapsed... + if (elapsedSinceDownShift > DOWN_SHIFT_ELPASED) { + doDownShift = _fpsAverageDownWindow.getAverage() < getLODDecreaseFPS(); + + if (!doDownShift) { + qDebug() << "---- WE APPEAR TO BE DONE DOWN SHIFTING -----"; + _isDownshifting = false; + _lastStable = now; + } + } } else { - doDownShift = (elapsedSinceUpShift > START_SHIFT_ELPASED && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()); + doDownShift = (elapsedSinceStableOrUpShift > START_SHIFT_ELPASED + && _fpsAverageStartWindow.getAverage() < getLODDecreaseFPS()); } if (doDownShift) { @@ -85,7 +97,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; } - octreeChanged = changed = true; + changed = true; } if (changed) { @@ -109,25 +121,28 @@ void LODManager::autoAdjustLOD(float currentFPS) { _lastDownShift = now; _isDownshifting = true; - + emit LODDecreased(); } } else { // LOD Upward adjustment - if (elapsedSinceUpShift > UP_SHIFT_ELPASED && _fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) { + if (elapsedSinceUpShift > UP_SHIFT_ELPASED) { + + if (_fpsAverageUpWindow.getAverage() > getLODIncreaseFPS()) { - // Octee items... stepwise adjustment - if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { - if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; - } else { - _octreeSizeScale *= ADJUST_LOD_UP_BY; + // Octee items... stepwise adjustment + if (_octreeSizeScale < ADJUST_LOD_MAX_SIZE_SCALE) { + if (_octreeSizeScale < ADJUST_LOD_MIN_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MIN_SIZE_SCALE; + } else { + _octreeSizeScale *= ADJUST_LOD_UP_BY; + } + if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { + _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; + } + changed = true; } - if (_octreeSizeScale > ADJUST_LOD_MAX_SIZE_SCALE) { - _octreeSizeScale = ADJUST_LOD_MAX_SIZE_SCALE; - } - octreeChanged = changed = true; } if (changed) { @@ -139,7 +154,7 @@ void LODManager::autoAdjustLOD(float currentFPS) { _lastUpShift = now; _isDownshifting = false; - + emit LODIncreased(); } } diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index d3765c164a..4003d09344 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -107,6 +107,7 @@ private: quint64 _lastDownShift = 0; quint64 _lastUpShift = 0; + quint64 _lastStable = 0; bool _isDownshifting = false; // start out as if we're not downshifting SimpleMovingAverage _fpsAverageStartWindow = START_DELAY_SAMPLES_OF_FRAMES; From 19feeacc51e7db68ac03399be13bb845b9c2829d Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Wed, 25 Mar 2015 16:38:57 -0700 Subject: [PATCH 117/177] dead code --- interface/src/LODManager.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/LODManager.cpp b/interface/src/LODManager.cpp index d12fe9147a..cb4913df72 100644 --- a/interface/src/LODManager.cpp +++ b/interface/src/LODManager.cpp @@ -45,7 +45,6 @@ void LODManager::autoAdjustLOD(float currentFPS) { // really want to count them in our average, so we will ignore the real frame rates and stuff // our moving average with simulated good data const int IGNORE_THESE_SAMPLES = 100; - //const float ASSUMED_FPS = 60.0f; if (_fpsAverageUpWindow.getSampleCount() < IGNORE_THESE_SAMPLES) { currentFPS = ASSUMED_FPS; _lastStable = _lastUpShift = _lastDownShift = usecTimestampNow(); From c031ce15a7908d32496803332b52f8657e3ab47a Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Wed, 25 Mar 2015 16:45:51 -0700 Subject: [PATCH 118/177] dead code --- interface/src/LODManager.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/interface/src/LODManager.h b/interface/src/LODManager.h index 4003d09344..77f156531a 100644 --- a/interface/src/LODManager.h +++ b/interface/src/LODManager.h @@ -76,10 +76,6 @@ public: Q_INVOKABLE void setBoundaryLevelAdjust(int boundaryLevelAdjust); Q_INVOKABLE int getBoundaryLevelAdjust() const { return _boundaryLevelAdjust; } - Q_INVOKABLE void resetLODAdjust(); - //Q_INVOKABLE float getFPSAverage() const { return _fpsAverage.getAverage(); } - //Q_INVOKABLE float getFastFPSAverage() const { return _fastFPSAverage.getAverage(); } - Q_INVOKABLE float getLODDecreaseFPS(); Q_INVOKABLE float getLODIncreaseFPS(); @@ -88,6 +84,7 @@ public: void loadSettings(); void saveSettings(); + void resetLODAdjust(); signals: void LODIncreased(); From 716e9bfe4fdfaf15c2e86aee33a2d0e28daae264 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Thu, 26 Mar 2015 15:40:48 +0100 Subject: [PATCH 119/177] Hint order for FST files --- interface/src/ModelPackager.cpp | 2 + interface/src/ModelPackager.h | 2 - interface/src/ModelPropertiesDialog.cpp | 1 + interface/src/ModelPropertiesDialog.h | 13 --- libraries/fbx/src/FBXReader.cpp | 68 -------------- libraries/fbx/src/FBXReader.h | 6 -- libraries/fbx/src/FSTReader.cpp | 96 ++++++++++++++++++++ libraries/fbx/src/FSTReader.h | 36 ++++++++ libraries/render-utils/src/GeometryCache.cpp | 1 + 9 files changed, 136 insertions(+), 89 deletions(-) create mode 100644 libraries/fbx/src/FSTReader.cpp create mode 100644 libraries/fbx/src/FSTReader.h diff --git a/interface/src/ModelPackager.cpp b/interface/src/ModelPackager.cpp index 49d4ae566f..f552d67a98 100644 --- a/interface/src/ModelPackager.cpp +++ b/interface/src/ModelPackager.cpp @@ -14,6 +14,8 @@ #include <QMessageBox> #include <QTemporaryDir> +#include <FSTReader.h> + #include "ModelSelector.h" #include "ModelPropertiesDialog.h" diff --git a/interface/src/ModelPackager.h b/interface/src/ModelPackager.h index c62388f196..2c90395e56 100644 --- a/interface/src/ModelPackager.h +++ b/interface/src/ModelPackager.h @@ -15,8 +15,6 @@ #include <QFileInfo> #include <QVariantHash> -#include <FBXReader.h> - #include "ui/ModelsBrowser.h" class ModelPackager : public QObject { diff --git a/interface/src/ModelPropertiesDialog.cpp b/interface/src/ModelPropertiesDialog.cpp index de98407a2a..81fe9ce7fd 100644 --- a/interface/src/ModelPropertiesDialog.cpp +++ b/interface/src/ModelPropertiesDialog.cpp @@ -19,6 +19,7 @@ #include <QMessageBox> #include <QPushButton> +#include <FSTReader.h> #include <GLMHelpers.h> #include "ModelPropertiesDialog.h" diff --git a/interface/src/ModelPropertiesDialog.h b/interface/src/ModelPropertiesDialog.h index 65c5be6c21..5af4d173f1 100644 --- a/interface/src/ModelPropertiesDialog.h +++ b/interface/src/ModelPropertiesDialog.h @@ -23,19 +23,6 @@ class QComboBox; class QCheckBox; class QVBoxLayout; -static const QString NAME_FIELD = "name"; -static const QString FILENAME_FIELD = "filename"; -static const QString TEXDIR_FIELD = "texdir"; -static const QString LOD_FIELD = "lod"; -static const QString JOINT_INDEX_FIELD = "jointIndex"; -static const QString SCALE_FIELD = "scale"; -static const QString TRANSLATION_X_FIELD = "tx"; -static const QString TRANSLATION_Y_FIELD = "ty"; -static const QString TRANSLATION_Z_FIELD = "tz"; -static const QString JOINT_FIELD = "joint"; -static const QString FREE_JOINT_FIELD = "freeJoint"; -static const QString BLENDSHAPE_FIELD = "bs"; - /// A dialog that allows customization of various model properties. class ModelPropertiesDialog : public QDialog { Q_OBJECT diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index a2c217c97d..1cd3bba73a 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -458,41 +458,6 @@ FBXNode parseFBX(QIODevice* device) { return top; } -QVariantHash parseMapping(QIODevice* device) { - QVariantHash properties; - - QByteArray line; - while (!(line = device->readLine()).isEmpty()) { - if ((line = line.trimmed()).startsWith('#')) { - continue; // comment - } - QList<QByteArray> sections = line.split('='); - if (sections.size() < 2) { - continue; - } - QByteArray name = sections.at(0).trimmed(); - if (sections.size() == 2) { - properties.insertMulti(name, sections.at(1).trimmed()); - - } else if (sections.size() == 3) { - QVariantHash heading = properties.value(name).toHash(); - heading.insertMulti(sections.at(1).trimmed(), sections.at(2).trimmed()); - properties.insert(name, heading); - - } else if (sections.size() >= 4) { - QVariantHash heading = properties.value(name).toHash(); - QVariantList contents; - for (int i = 2; i < sections.size(); i++) { - contents.append(sections.at(i).trimmed()); - } - heading.insertMulti(sections.at(1).trimmed(), contents); - properties.insert(name, heading); - } - } - - return properties; -} - QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) { QVector<glm::vec3> values; for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 3 * 3); it != end; ) { @@ -2473,39 +2438,6 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping, return geometry; } -QVariantHash readMapping(const QByteArray& data) { - QBuffer buffer(const_cast<QByteArray*>(&data)); - buffer.open(QIODevice::ReadOnly); - return parseMapping(&buffer); -} - -QByteArray writeMapping(const QVariantHash& mapping) { - QBuffer buffer; - buffer.open(QIODevice::WriteOnly); - for (QVariantHash::const_iterator first = mapping.constBegin(); first != mapping.constEnd(); first++) { - QByteArray key = first.key().toUtf8() + " = "; - QVariantHash hashValue = first.value().toHash(); - if (hashValue.isEmpty()) { - buffer.write(key + first.value().toByteArray() + "\n"); - continue; - } - for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) { - QByteArray extendedKey = key + second.key().toUtf8(); - QVariantList listValue = second.value().toList(); - if (listValue.isEmpty()) { - buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n"); - continue; - } - buffer.write(extendedKey); - for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) { - buffer.write(" = " + third->toByteArray()); - } - buffer.write("\n"); - } - } - return buffer.data(); -} - FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps, float lightmapLevel) { QBuffer buffer(const_cast<QByteArray*>(&model)); buffer.open(QIODevice::ReadOnly); diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index ecce607575..6cb6b19c05 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -261,12 +261,6 @@ public: Q_DECLARE_METATYPE(FBXGeometry) -/// Reads an FST mapping from the supplied data. -QVariantHash readMapping(const QByteArray& data); - -/// Writes an FST mapping to a byte array. -QByteArray writeMapping(const QVariantHash& mapping); - /// Reads FBX geometry from the supplied model and mapping data. /// \exception QString if an error occurs in parsing FBXGeometry readFBX(const QByteArray& model, const QVariantHash& mapping, bool loadLightmaps = true, float lightmapLevel = 1.0f); diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp new file mode 100644 index 0000000000..397de2bd2a --- /dev/null +++ b/libraries/fbx/src/FSTReader.cpp @@ -0,0 +1,96 @@ +// +// FSTReader.cpp +// +// +// Created by Clement on 3/26/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#include "FSTReader.h" + +QVariantHash parseMapping(QIODevice* device) { + QVariantHash properties; + + QByteArray line; + while (!(line = device->readLine()).isEmpty()) { + if ((line = line.trimmed()).startsWith('#')) { + continue; // comment + } + QList<QByteArray> sections = line.split('='); + if (sections.size() < 2) { + continue; + } + QByteArray name = sections.at(0).trimmed(); + if (sections.size() == 2) { + properties.insertMulti(name, sections.at(1).trimmed()); + + } else if (sections.size() == 3) { + QVariantHash heading = properties.value(name).toHash(); + heading.insertMulti(sections.at(1).trimmed(), sections.at(2).trimmed()); + properties.insert(name, heading); + + } else if (sections.size() >= 4) { + QVariantHash heading = properties.value(name).toHash(); + QVariantList contents; + for (int i = 2; i < sections.size(); i++) { + contents.append(sections.at(i).trimmed()); + } + heading.insertMulti(sections.at(1).trimmed(), contents); + properties.insert(name, heading); + } + } + + return properties; +} + +QVariantHash readMapping(const QByteArray& data) { + QBuffer buffer(const_cast<QByteArray*>(&data)); + buffer.open(QIODevice::ReadOnly); + return parseMapping(&buffer); +} + +QByteArray writeMapping(const QVariantHash& mapping) { + static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << SCALE_FIELD << FILENAME_FIELD + << TEXDIR_FIELD << JOINT_FIELD << FREE_JOINT_FIELD + << BLENDSHAPE_FIELD << JOINT_INDEX_FIELD; + QBuffer buffer; + auto writeVariant = [&buffer](QVariantHash::const_iterator& it) { + QByteArray key = it.key().toUtf8() + " = "; + QVariantHash hashValue = it.value().toHash(); + if (hashValue.isEmpty()) { + buffer.write(key + it.value().toByteArray() + "\n"); + return; + } + for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) { + QByteArray extendedKey = key + second.key().toUtf8(); + QVariantList listValue = second.value().toList(); + if (listValue.isEmpty()) { + buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n"); + continue; + } + buffer.write(extendedKey); + for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) { + buffer.write(" = " + third->toByteArray()); + } + buffer.write("\n"); + } + }; + buffer.open(QIODevice::WriteOnly); + + for (auto key : PREFERED_ORDER) { + auto it = mapping.find(key); + if (it != mapping.constEnd()) { + writeVariant(it); + } + } + + for (auto it = mapping.constBegin(); it != mapping.constEnd(); it++) { + if (!PREFERED_ORDER.contains(it.key())) { + writeVariant(it); + } + } + return buffer.data(); +} \ No newline at end of file diff --git a/libraries/fbx/src/FSTReader.h b/libraries/fbx/src/FSTReader.h new file mode 100644 index 0000000000..59559dea74 --- /dev/null +++ b/libraries/fbx/src/FSTReader.h @@ -0,0 +1,36 @@ +// +// FSTReader.h +// +// +// Created by Clement on 3/26/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#ifndef hifi_FSTReader_h +#define hifi_FSTReader_h + +#include <QVariantHash> + +static const QString NAME_FIELD = "name"; +static const QString FILENAME_FIELD = "filename"; +static const QString TEXDIR_FIELD = "texdir"; +static const QString LOD_FIELD = "lod"; +static const QString JOINT_INDEX_FIELD = "jointIndex"; +static const QString SCALE_FIELD = "scale"; +static const QString TRANSLATION_X_FIELD = "tx"; +static const QString TRANSLATION_Y_FIELD = "ty"; +static const QString TRANSLATION_Z_FIELD = "tz"; +static const QString JOINT_FIELD = "joint"; +static const QString FREE_JOINT_FIELD = "freeJoint"; +static const QString BLENDSHAPE_FIELD = "bs"; + +/// Reads an FST mapping from the supplied data. +QVariantHash readMapping(const QByteArray& data); + +/// Writes an FST mapping to a byte array. +QByteArray writeMapping(const QVariantHash& mapping); + +#endif // hifi_FSTReader_h \ No newline at end of file diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 29f76291ea..e60409e36f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -21,6 +21,7 @@ #include <gpu/Batch.h> #include <gpu/GLBackend.h> +#include <FSTReader.h> #include <SharedUtil.h> #include "TextureCache.h" From c26b499671091e638ed7f01788c6269af94a9862 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Thu, 26 Mar 2015 15:58:18 +0100 Subject: [PATCH 120/177] Add forgotten include --- libraries/fbx/src/FSTReader.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index 397de2bd2a..4f882d4bd8 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include <QBuffer> + #include "FSTReader.h" QVariantHash parseMapping(QIODevice* device) { From 7c4ea855a838c2668fc0fffbaa1b297f5752b097 Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Wed, 25 Mar 2015 14:50:25 -0700 Subject: [PATCH 121/177] Limit height of users window per screen space available --- examples/users.js | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/examples/users.js b/examples/users.js index 22fe89389f..18404340c5 100644 --- a/examples/users.js +++ b/examples/users.js @@ -54,6 +54,8 @@ var usersWindow = (function () { isVisible = true, viewportHeight, + isMirrorDisplay = false, + isFullscreenMirror = false, HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/", RADIO_BUTTON_SVG = HIFI_PUBLIC_BUCKET + "images/radio-button.svg", @@ -62,10 +64,21 @@ var usersWindow = (function () { radioButtonDiameter; function calculateWindowHeight() { + var AUDIO_METER_HEIGHT = 52, + MIRROR_HEIGHT = 220, + maxWindowHeight; + // Reserve 5 lines for window heading plus visibility heading and controls // Subtract windowLineSpacing for both end of user list and end of controls windowHeight = (linesOfUsers.length > 0 ? linesOfUsers.length + 5 : 5) * windowLineHeight - 2 * windowLineSpacing + VISIBILITY_SPACER_2D + 2 * WINDOW_MARGIN_2D; + + // Limit to height of window minus VU meter and mirror if displayed + maxWindowHeight = viewportHeight - AUDIO_METER_HEIGHT; + if (isMirrorDisplay && !isFullscreenMirror) { + maxWindowHeight -= MIRROR_HEIGHT; + } + windowHeight = Math.min(windowHeight, maxWindowHeight); } function updateOverlayPositions() { @@ -295,10 +308,20 @@ var usersWindow = (function () { } function onScriptUpdate() { - var oldViewportHeight = viewportHeight; + var oldViewportHeight = viewportHeight, + oldIsMirrorDisplay = isMirrorDisplay, + oldIsFullscreenMirror = isFullscreenMirror, + MIRROR_MENU_ITEM = "Mirror", + FULLSCREEN_MIRROR_MENU_ITEM = "Fullscreen Mirror"; viewportHeight = Controller.getViewportDimensions().y; - if (viewportHeight !== oldViewportHeight) { + isMirrorDisplay = Menu.isOptionChecked(MIRROR_MENU_ITEM); + isFullscreenMirror = Menu.isOptionChecked(FULLSCREEN_MIRROR_MENU_ITEM); + + if (viewportHeight !== oldViewportHeight + || isMirrorDisplay !== oldIsMirrorDisplay + || isFullscreenMirror !== oldIsFullscreenMirror) { + calculateWindowHeight(); updateOverlayPositions(); } } From 8e66f5998a9e555f5495871b706d29351b707823 Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Wed, 25 Mar 2015 16:29:57 -0700 Subject: [PATCH 122/177] Add scrollbar background and bar --- examples/users.js | 54 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 51 insertions(+), 3 deletions(-) diff --git a/examples/users.js b/examples/users.js index 18404340c5..3efe2ff19a 100644 --- a/examples/users.js +++ b/examples/users.js @@ -11,7 +11,7 @@ var usersWindow = (function () { - var WINDOW_WIDTH_2D = 150, + var WINDOW_WIDTH_2D = 160, WINDOW_MARGIN_2D = 12, WINDOW_FONT_2D = { size: 12 }, WINDOW_FOREGROUND_COLOR_2D = { red: 240, green: 240, blue: 240 }, @@ -22,6 +22,13 @@ var usersWindow = (function () { WINDOW_BACKGROUND_ALPHA_2D = 0.7, windowPane2D, windowHeading2D, + SCROLLBAR_BACKGROUND_WIDTH_2D = 12, + SCROLLBAR_BACKGROUND_COLOR_2D = { red: 80, green: 80, blue: 80 }, + SCROLLBAR_BACKGROUND_ALPHA_2D = 0.8, + scrollbarBackground2D, + SCROLLBAR_BAR_COLOR_2D = { red: 180, green: 180, blue: 180 }, + SCROLLBAR_BAR_ALPHA_2D = 0.8, + scrollbarBar2D, VISIBILITY_SPACER_2D = 12, // Space between list of users and visibility controls visibilityHeading2D, VISIBILITY_RADIO_SPACE = 16, @@ -91,6 +98,12 @@ var usersWindow = (function () { Overlays.editOverlay(windowHeading2D, { y: viewportHeight - windowHeight + WINDOW_MARGIN_2D }); + Overlays.editOverlay(scrollbarBackground2D, { + y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight + }); + Overlays.editOverlay(scrollbarBar2D, { + y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight + 1 + }); Overlays.editOverlay(visibilityHeading2D, { y: viewportHeight - 4 * windowLineHeight + windowLineSpacing - WINDOW_MARGIN_2D }); @@ -135,7 +148,7 @@ var usersWindow = (function () { } textWidth = Overlays.textSize(windowPane2D, userText).width; - maxTextWidth = WINDOW_WIDTH_2D - 2 * WINDOW_MARGIN_2D; + maxTextWidth = WINDOW_WIDTH_2D - SCROLLBAR_BACKGROUND_WIDTH_2D - 2 * WINDOW_MARGIN_2D; if (textWidth > maxTextWidth) { // Trim and append "..." to fit window width maxTextWidth = maxTextWidth - Overlays.textSize(windowPane2D, "...").width; @@ -168,6 +181,15 @@ var usersWindow = (function () { text: linesOfUsers.length > 0 ? "Users online" : "No users online" }); + Overlays.editOverlay(scrollbarBackground2D, { + y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight, + height: linesOfUsers.length * windowLineHeight - windowLineSpacing / 2 + }); + Overlays.editOverlay(scrollbarBar2D, { + y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight + 1, + height: linesOfUsers.length * windowLineHeight / 3 // TODO + }); + updateOverlayPositions(); } @@ -239,6 +261,8 @@ var usersWindow = (function () { Overlays.editOverlay(windowPane2D, { visible: isVisible }); Overlays.editOverlay(windowHeading2D, { visible: isVisible }); + Overlays.editOverlay(scrollbarBackground2D, { visible: isVisible }); + Overlays.editOverlay(scrollbarBar2D, { visible: isVisible }); Overlays.editOverlay(visibilityHeading2D, { visible: isVisible }); for (i = 0; i < visibilityControls2D.length; i += 1) { Overlays.editOverlay(visibilityControls2D[i].radioOverlay, { visible: isVisible }); @@ -372,6 +396,28 @@ var usersWindow = (function () { visible: isVisible }); + scrollbarBackground2D = Overlays.addOverlay("text", { + x: WINDOW_WIDTH_2D - 0.5 * WINDOW_MARGIN_2D - SCROLLBAR_BACKGROUND_WIDTH_2D, + y: viewportHeight, + width: SCROLLBAR_BACKGROUND_WIDTH_2D, + height: windowTextHeight, + backgroundColor: SCROLLBAR_BACKGROUND_COLOR_2D, + backgroundAlpha: SCROLLBAR_BACKGROUND_ALPHA_2D, + text: "", + visible: isVisible + }); + + scrollbarBar2D = Overlays.addOverlay("text", { + x: WINDOW_WIDTH_2D - 0.5 * WINDOW_MARGIN_2D - SCROLLBAR_BACKGROUND_WIDTH_2D + 1, + y: viewportHeight, + width: SCROLLBAR_BACKGROUND_WIDTH_2D - 2, + height: windowTextHeight, + backgroundColor: SCROLLBAR_BAR_COLOR_2D, + backgroundAlpha: SCROLLBAR_BAR_ALPHA_2D, + text: "", + visible: isVisible + }); + visibilityHeading2D = Overlays.addOverlay("text", { x: WINDOW_MARGIN_2D, y: viewportHeight, @@ -413,7 +459,7 @@ var usersWindow = (function () { textOverlay: Overlays.addOverlay("text", { x: WINDOW_MARGIN_2D, y: viewportHeight, - width: WINDOW_WIDTH_2D - 2 * WINDOW_MARGIN_2D, + width: WINDOW_WIDTH_2D - SCROLLBAR_BACKGROUND_WIDTH_2D - 2 * WINDOW_MARGIN_2D, height: windowTextHeight, topMargin: 0, leftMargin: VISIBILITY_RADIO_SPACE, @@ -479,6 +525,8 @@ var usersWindow = (function () { Script.clearTimeout(usersTimer); Overlays.deleteOverlay(windowPane2D); Overlays.deleteOverlay(windowHeading2D); + Overlays.deleteOverlay(scrollbarBackground2D); + Overlays.deleteOverlay(scrollbarBar2D); Overlays.deleteOverlay(visibilityHeading2D); for (i = 0; i <= visibilityControls2D.length; i += 1) { Overlays.deleteOverlay(visibilityControls2D[i].textOverlay); From 567375368e7f02c23b9613a786a30e9340916ee9 Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Wed, 25 Mar 2015 17:44:14 -0700 Subject: [PATCH 123/177] Show first N users that can fit --- examples/users.js | 90 +++++++++++++++++++++++++++++------------------ 1 file changed, 56 insertions(+), 34 deletions(-) diff --git a/examples/users.js b/examples/users.js index 3efe2ff19a..2eef3e3816 100644 --- a/examples/users.js +++ b/examples/users.js @@ -40,6 +40,7 @@ var usersWindow = (function () { usersOnline, // Raw users data linesOfUsers = [], // Array of indexes pointing into usersOnline + numUsersToDisplay = 0, API_URL = "https://metaverse.highfidelity.com/api/v1/users?status=online", HTTP_GET_TIMEOUT = 60000, // ms = 1 minute @@ -73,19 +74,23 @@ var usersWindow = (function () { function calculateWindowHeight() { var AUDIO_METER_HEIGHT = 52, MIRROR_HEIGHT = 220, + nonUsersHeight, maxWindowHeight; // Reserve 5 lines for window heading plus visibility heading and controls // Subtract windowLineSpacing for both end of user list and end of controls - windowHeight = (linesOfUsers.length > 0 ? linesOfUsers.length + 5 : 5) * windowLineHeight - - 2 * windowLineSpacing + VISIBILITY_SPACER_2D + 2 * WINDOW_MARGIN_2D; + nonUsersHeight = 5 * windowLineHeight - 2 * windowLineSpacing + VISIBILITY_SPACER_2D + 2 * WINDOW_MARGIN_2D; - // Limit to height of window minus VU meter and mirror if displayed + // Limit window to height of viewport minus VU meter and mirror if displayed + windowHeight = linesOfUsers.length * windowLineHeight + nonUsersHeight; maxWindowHeight = viewportHeight - AUDIO_METER_HEIGHT; if (isMirrorDisplay && !isFullscreenMirror) { maxWindowHeight -= MIRROR_HEIGHT; } windowHeight = Math.min(windowHeight, maxWindowHeight); + + // Corresponding number of users to actually display + numUsersToDisplay = Math.round((windowHeight - nonUsersHeight) / windowLineHeight); } function updateOverlayPositions() { @@ -130,46 +135,39 @@ var usersWindow = (function () { function updateUsersDisplay() { var displayText = "", - myUsername, user, userText, textWidth, maxTextWidth, + ellipsisWidth, + reducedTextWidth, i; - myUsername = GlobalServices.username; - linesOfUsers = []; - for (i = 0; i < usersOnline.length; i += 1) { - user = usersOnline[i]; - if (user.username !== myUsername && user.online) { - userText = user.username; - if (user.location.root) { - userText += " @ " + user.location.root.name; - } - textWidth = Overlays.textSize(windowPane2D, userText).width; + maxTextWidth = WINDOW_WIDTH_2D - SCROLLBAR_BACKGROUND_WIDTH_2D - 2 * WINDOW_MARGIN_2D; + ellipsisWidth = Overlays.textSize(windowPane2D, "...").width; + reducedTextWidth = maxTextWidth - ellipsisWidth; - maxTextWidth = WINDOW_WIDTH_2D - SCROLLBAR_BACKGROUND_WIDTH_2D - 2 * WINDOW_MARGIN_2D; - if (textWidth > maxTextWidth) { - // Trim and append "..." to fit window width - maxTextWidth = maxTextWidth - Overlays.textSize(windowPane2D, "...").width; - while (textWidth > maxTextWidth) { - userText = userText.slice(0, -1); - textWidth = Overlays.textSize(windowPane2D, userText).width; - } - userText += "..."; + for (i = 0; i < numUsersToDisplay; i += 1) { + user = usersOnline[linesOfUsers[i]]; + userText = user.text; + print(userText); + textWidth = user.textWidth; + + if (textWidth > maxTextWidth) { + // Trim and append "..." to fit window width + maxTextWidth = maxTextWidth - Overlays.textSize(windowPane2D, "...").width; + while (textWidth > reducedTextWidth) { + userText = userText.slice(0, -1); textWidth = Overlays.textSize(windowPane2D, userText).width; } - - usersOnline[i].textWidth = textWidth; - linesOfUsers.push(i); - displayText += "\n" + userText; + userText += "..."; } + + displayText += "\n" + userText; } displayText = displayText.slice(1); // Remove leading "\n". - calculateWindowHeight(); - Overlays.editOverlay(windowPane2D, { y: viewportHeight - windowHeight, height: windowHeight, @@ -183,11 +181,11 @@ var usersWindow = (function () { Overlays.editOverlay(scrollbarBackground2D, { y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight, - height: linesOfUsers.length * windowLineHeight - windowLineSpacing / 2 + height: numUsersToDisplay * windowLineHeight - windowLineSpacing / 2 }); Overlays.editOverlay(scrollbarBar2D, { y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight + 1, - height: linesOfUsers.length * windowLineHeight / 3 // TODO + height: numUsersToDisplay * windowLineHeight / 3 // TODO }); updateOverlayPositions(); @@ -203,7 +201,11 @@ var usersWindow = (function () { } processUsers = function () { - var response; + var response, + myUsername, + user, + userText, + i; if (usersRequest.readyState === usersRequest.DONE) { if (usersRequest.status === 200) { @@ -220,7 +222,26 @@ var usersWindow = (function () { } usersOnline = response.data.users; + myUsername = GlobalServices.username; + linesOfUsers = []; + for (i = 0; i < usersOnline.length; i += 1) { + user = usersOnline[i]; + if (user.username !== myUsername && user.online) { + userText = user.username; + if (user.location.root) { + userText += " @ " + user.location.root.name; + } + + usersOnline[i].text = userText; + usersOnline[i].textWidth = Overlays.textSize(windowPane2D, userText).width; + + linesOfUsers.push(i); + } + } + + calculateWindowHeight(); updateUsersDisplay(); + } else { print("Error: Request for users status returned " + usersRequest.status + " " + usersRequest.statusText); usersTimer = Script.setTimeout(pollUsers, HTTP_GET_TIMEOUT); // Try again after a longer delay. @@ -346,6 +367,7 @@ var usersWindow = (function () { || isMirrorDisplay !== oldIsMirrorDisplay || isFullscreenMirror !== oldIsFullscreenMirror) { calculateWindowHeight(); + updateUsersDisplay(); updateOverlayPositions(); } } @@ -361,10 +383,10 @@ var usersWindow = (function () { radioButtonDiameter = RADIO_BUTTON_DISPLAY_SCALE * windowTextHeight; Overlays.deleteOverlay(textSizeOverlay); - calculateWindowHeight(); - viewportHeight = Controller.getViewportDimensions().y; + calculateWindowHeight(); + windowPane2D = Overlays.addOverlay("text", { x: 0, y: viewportHeight, // Start up off-screen From ba1a7c67610d443d7a700c586ac1c12b9acff61f Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Wed, 25 Mar 2015 18:35:51 -0700 Subject: [PATCH 124/177] Show/hide scrollbar depending on whether needed or not --- examples/users.js | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/examples/users.js b/examples/users.js index 2eef3e3816..2d35315ae3 100644 --- a/examples/users.js +++ b/examples/users.js @@ -65,6 +65,8 @@ var usersWindow = (function () { isMirrorDisplay = false, isFullscreenMirror = false, + isUsingScrollbars = false, + HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/", RADIO_BUTTON_SVG = HIFI_PUBLIC_BUCKET + "images/radio-button.svg", RADIO_BUTTON_SVG_DIAMETER = 14, @@ -91,6 +93,7 @@ var usersWindow = (function () { // Corresponding number of users to actually display numUsersToDisplay = Math.round((windowHeight - nonUsersHeight) / windowLineHeight); + isUsingScrollbars = numUsersToDisplay < linesOfUsers.length; } function updateOverlayPositions() { @@ -143,14 +146,13 @@ var usersWindow = (function () { reducedTextWidth, i; - maxTextWidth = WINDOW_WIDTH_2D - SCROLLBAR_BACKGROUND_WIDTH_2D - 2 * WINDOW_MARGIN_2D; + maxTextWidth = WINDOW_WIDTH_2D - (isUsingScrollbars ? SCROLLBAR_BACKGROUND_WIDTH_2D : 0) - 2 * WINDOW_MARGIN_2D; ellipsisWidth = Overlays.textSize(windowPane2D, "...").width; reducedTextWidth = maxTextWidth - ellipsisWidth; for (i = 0; i < numUsersToDisplay; i += 1) { user = usersOnline[linesOfUsers[i]]; userText = user.text; - print(userText); textWidth = user.textWidth; if (textWidth > maxTextWidth) { @@ -181,11 +183,13 @@ var usersWindow = (function () { Overlays.editOverlay(scrollbarBackground2D, { y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight, - height: numUsersToDisplay * windowLineHeight - windowLineSpacing / 2 + height: numUsersToDisplay * windowLineHeight - windowLineSpacing / 2, + visible: isUsingScrollbars }); Overlays.editOverlay(scrollbarBar2D, { y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight + 1, - height: numUsersToDisplay * windowLineHeight / 3 // TODO + height: numUsersToDisplay * windowLineHeight / 3, // TODO + visible: isUsingScrollbars }); updateOverlayPositions(); @@ -282,8 +286,8 @@ var usersWindow = (function () { Overlays.editOverlay(windowPane2D, { visible: isVisible }); Overlays.editOverlay(windowHeading2D, { visible: isVisible }); - Overlays.editOverlay(scrollbarBackground2D, { visible: isVisible }); - Overlays.editOverlay(scrollbarBar2D, { visible: isVisible }); + Overlays.editOverlay(scrollbarBackground2D, { visible: isVisible && isUsingScrollbars }); + Overlays.editOverlay(scrollbarBar2D, { visible: isVisible && isUsingScrollbars }); Overlays.editOverlay(visibilityHeading2D, { visible: isVisible }); for (i = 0; i < visibilityControls2D.length; i += 1) { Overlays.editOverlay(visibilityControls2D[i].radioOverlay, { visible: isVisible }); @@ -426,7 +430,7 @@ var usersWindow = (function () { backgroundColor: SCROLLBAR_BACKGROUND_COLOR_2D, backgroundAlpha: SCROLLBAR_BACKGROUND_ALPHA_2D, text: "", - visible: isVisible + visible: isVisible && isUsingScrollbars }); scrollbarBar2D = Overlays.addOverlay("text", { @@ -437,7 +441,7 @@ var usersWindow = (function () { backgroundColor: SCROLLBAR_BAR_COLOR_2D, backgroundAlpha: SCROLLBAR_BAR_ALPHA_2D, text: "", - visible: isVisible + visible: isVisible && isUsingScrollbars }); visibilityHeading2D = Overlays.addOverlay("text", { From 98c88aab046d0def09ba1c7c13ced34c2177f41a Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Wed, 25 Mar 2015 19:13:33 -0700 Subject: [PATCH 125/177] Handle no users able to be displayed, insufficient screen height --- examples/users.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/users.js b/examples/users.js index 2d35315ae3..ef0aa9f48d 100644 --- a/examples/users.js +++ b/examples/users.js @@ -89,11 +89,11 @@ var usersWindow = (function () { if (isMirrorDisplay && !isFullscreenMirror) { maxWindowHeight -= MIRROR_HEIGHT; } - windowHeight = Math.min(windowHeight, maxWindowHeight); + windowHeight = Math.max(Math.min(windowHeight, maxWindowHeight), nonUsersHeight); // Corresponding number of users to actually display - numUsersToDisplay = Math.round((windowHeight - nonUsersHeight) / windowLineHeight); - isUsingScrollbars = numUsersToDisplay < linesOfUsers.length; + numUsersToDisplay = Math.max(Math.round((windowHeight - nonUsersHeight) / windowLineHeight), 0); + isUsingScrollbars = 0 < numUsersToDisplay && numUsersToDisplay < linesOfUsers.length; } function updateOverlayPositions() { From 1e1a2770653f9f8465741f374efef2fc5e361990 Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Wed, 25 Mar 2015 19:25:35 -0700 Subject: [PATCH 126/177] Scrollbar bar height varies with percentage of users displayed --- examples/users.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/examples/users.js b/examples/users.js index ef0aa9f48d..46ec38112d 100644 --- a/examples/users.js +++ b/examples/users.js @@ -26,9 +26,12 @@ var usersWindow = (function () { SCROLLBAR_BACKGROUND_COLOR_2D = { red: 80, green: 80, blue: 80 }, SCROLLBAR_BACKGROUND_ALPHA_2D = 0.8, scrollbarBackground2D, + SCROLLBAR_BAR_MIN_HEIGHT = 5, SCROLLBAR_BAR_COLOR_2D = { red: 180, green: 180, blue: 180 }, SCROLLBAR_BAR_ALPHA_2D = 0.8, scrollbarBar2D, + scrollbarBackgroundHeight, + scrollbarBarHeight, VISIBILITY_SPACER_2D = 12, // Space between list of users and visibility controls visibilityHeading2D, VISIBILITY_RADIO_SPACE = 16, @@ -181,14 +184,16 @@ var usersWindow = (function () { text: linesOfUsers.length > 0 ? "Users online" : "No users online" }); + scrollbarBackgroundHeight = numUsersToDisplay * windowLineHeight - windowLineSpacing / 2; Overlays.editOverlay(scrollbarBackground2D, { y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight, - height: numUsersToDisplay * windowLineHeight - windowLineSpacing / 2, + height: scrollbarBackgroundHeight, visible: isUsingScrollbars }); + scrollbarBarHeight = Math.max(numUsersToDisplay / linesOfUsers.length * scrollbarBackgroundHeight, SCROLLBAR_BAR_MIN_HEIGHT); Overlays.editOverlay(scrollbarBar2D, { y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight + 1, - height: numUsersToDisplay * windowLineHeight / 3, // TODO + height: scrollbarBarHeight, visible: isUsingScrollbars }); From 14e92eecad08504998b5dd272abd9f480c793561 Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Thu, 26 Mar 2015 10:54:20 -0700 Subject: [PATCH 127/177] Click and drag scrollbar --- examples/users.js | 63 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 11 deletions(-) diff --git a/examples/users.js b/examples/users.js index 46ec38112d..f4daaed078 100644 --- a/examples/users.js +++ b/examples/users.js @@ -69,6 +69,11 @@ var usersWindow = (function () { isFullscreenMirror = false, isUsingScrollbars = false, + isMovingScrollbar = false, + scrollbarBackgroundPosition = {}, + scrollbarBarPosition = {}, + scrollbarBarClickedAt, // 0.0 .. 1.0 + scrollbarValue = 0.0, // 0.0 .. 1.0 HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/", RADIO_BUTTON_SVG = HIFI_PUBLIC_BUCKET + "images/radio-button.svg", @@ -109,11 +114,15 @@ var usersWindow = (function () { Overlays.editOverlay(windowHeading2D, { y: viewportHeight - windowHeight + WINDOW_MARGIN_2D }); + + scrollbarBackgroundPosition.y = viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight; Overlays.editOverlay(scrollbarBackground2D, { - y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight + y: scrollbarBackgroundPosition.y }); + scrollbarBarPosition.y = scrollbarBackgroundPosition.y + 1 + + scrollbarValue * (scrollbarBackgroundHeight - scrollbarBarHeight - 2); Overlays.editOverlay(scrollbarBar2D, { - y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight + 1 + y: scrollbarBarPosition.y }); Overlays.editOverlay(visibilityHeading2D, { y: viewportHeight - 4 * windowLineHeight + windowLineSpacing - WINDOW_MARGIN_2D @@ -174,25 +183,22 @@ var usersWindow = (function () { displayText = displayText.slice(1); // Remove leading "\n". Overlays.editOverlay(windowPane2D, { - y: viewportHeight - windowHeight, height: windowHeight, text: displayText }); Overlays.editOverlay(windowHeading2D, { - y: viewportHeight - windowHeight + WINDOW_MARGIN_2D, text: linesOfUsers.length > 0 ? "Users online" : "No users online" }); scrollbarBackgroundHeight = numUsersToDisplay * windowLineHeight - windowLineSpacing / 2; Overlays.editOverlay(scrollbarBackground2D, { - y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight, height: scrollbarBackgroundHeight, visible: isUsingScrollbars }); - scrollbarBarHeight = Math.max(numUsersToDisplay / linesOfUsers.length * scrollbarBackgroundHeight, SCROLLBAR_BAR_MIN_HEIGHT); + scrollbarBarHeight = Math.max(numUsersToDisplay / linesOfUsers.length * scrollbarBackgroundHeight, + SCROLLBAR_BAR_MIN_HEIGHT); Overlays.editOverlay(scrollbarBar2D, { - y: viewportHeight - windowHeight + WINDOW_MARGIN_2D + windowTextHeight + 1, height: scrollbarBarHeight, visible: isUsingScrollbars }); @@ -359,6 +365,31 @@ var usersWindow = (function () { } updateVisibilityControls(); } + + if (clickedOverlay === scrollbarBar2D) { + scrollbarBarClickedAt = (event.y - scrollbarBarPosition.y) / scrollbarBarHeight; + isMovingScrollbar = true; + } + } + + function onMouseMoveEvent(event) { + if (isMovingScrollbar) { + if (scrollbarBackgroundPosition.x - WINDOW_MARGIN_2D <= event.x + && event.x <= scrollbarBackgroundPosition.x + SCROLLBAR_BACKGROUND_WIDTH_2D + WINDOW_MARGIN_2D + && scrollbarBackgroundPosition.y - WINDOW_MARGIN_2D <= event.y + && event.y <= scrollbarBackgroundPosition.y + scrollbarBackgroundHeight + WINDOW_MARGIN_2D) { + scrollbarValue = (event.y - scrollbarBarClickedAt * scrollbarBarHeight - scrollbarBackgroundPosition.y) + / (scrollbarBackgroundHeight - scrollbarBarHeight - 2); + scrollbarValue = Math.min(Math.max(scrollbarValue, 0.0), 1.0); + updateOverlayPositions(); + } else { + isMovingScrollbar = false; + } + } + } + + function onMouseReleaseEvent() { + isMovingScrollbar = false; } function onScriptUpdate() { @@ -427,9 +458,13 @@ var usersWindow = (function () { visible: isVisible }); - scrollbarBackground2D = Overlays.addOverlay("text", { + scrollbarBackgroundPosition = { x: WINDOW_WIDTH_2D - 0.5 * WINDOW_MARGIN_2D - SCROLLBAR_BACKGROUND_WIDTH_2D, - y: viewportHeight, + y: viewportHeight + }; + scrollbarBackground2D = Overlays.addOverlay("text", { + x: scrollbarBackgroundPosition.x, + y: scrollbarBackgroundPosition.y, width: SCROLLBAR_BACKGROUND_WIDTH_2D, height: windowTextHeight, backgroundColor: SCROLLBAR_BACKGROUND_COLOR_2D, @@ -438,9 +473,13 @@ var usersWindow = (function () { visible: isVisible && isUsingScrollbars }); - scrollbarBar2D = Overlays.addOverlay("text", { + scrollbarBarPosition = { x: WINDOW_WIDTH_2D - 0.5 * WINDOW_MARGIN_2D - SCROLLBAR_BACKGROUND_WIDTH_2D + 1, - y: viewportHeight, + y: viewportHeight + }; + scrollbarBar2D = Overlays.addOverlay("text", { + x: scrollbarBarPosition.x, + y: scrollbarBarPosition.y, width: SCROLLBAR_BACKGROUND_WIDTH_2D - 2, height: windowTextHeight, backgroundColor: SCROLLBAR_BAR_COLOR_2D, @@ -529,6 +568,8 @@ var usersWindow = (function () { updateVisibilityControls(); Controller.mousePressEvent.connect(onMousePressEvent); + Controller.mouseMoveEvent.connect(onMouseMoveEvent); + Controller.mouseReleaseEvent.connect(onMouseReleaseEvent); Menu.addMenuItem({ menuName: MENU_NAME, From c7fe7aa15773dc3f405913f808693046c43cf2db Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Thu, 26 Mar 2015 11:21:56 -0700 Subject: [PATCH 128/177] Update users displayed per scrollbar position --- examples/users.js | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/examples/users.js b/examples/users.js index f4daaed078..ed1703c329 100644 --- a/examples/users.js +++ b/examples/users.js @@ -44,6 +44,7 @@ var usersWindow = (function () { usersOnline, // Raw users data linesOfUsers = [], // Array of indexes pointing into usersOnline numUsersToDisplay = 0, + firstUserToDisplay = 0, API_URL = "https://metaverse.highfidelity.com/api/v1/users?status=online", HTTP_GET_TIMEOUT = 60000, // ms = 1 minute @@ -102,6 +103,12 @@ var usersWindow = (function () { // Corresponding number of users to actually display numUsersToDisplay = Math.max(Math.round((windowHeight - nonUsersHeight) / windowLineHeight), 0); isUsingScrollbars = 0 < numUsersToDisplay && numUsersToDisplay < linesOfUsers.length; + if (isUsingScrollbars) { + firstUserToDisplay = Math.floor(scrollbarValue * (linesOfUsers.length - numUsersToDisplay)); + } else { + firstUserToDisplay = 0; + scrollbarValue = 0.0; + } } function updateOverlayPositions() { @@ -163,7 +170,7 @@ var usersWindow = (function () { reducedTextWidth = maxTextWidth - ellipsisWidth; for (i = 0; i < numUsersToDisplay; i += 1) { - user = usersOnline[linesOfUsers[i]]; + user = usersOnline[linesOfUsers[firstUserToDisplay + i]]; userText = user.text; textWidth = user.textWidth; @@ -320,6 +327,7 @@ var usersWindow = (function () { minY, maxY, lineClicked, + userClicked, i, visibilityChanged; @@ -334,7 +342,7 @@ var usersWindow = (function () { overlayX = event.x - WINDOW_MARGIN_2D; overlayY = event.y - viewportHeight + windowHeight - WINDOW_MARGIN_2D - windowLineHeight; - numLinesBefore = Math.floor(overlayY / windowLineHeight); + numLinesBefore = Math.round(overlayY / windowLineHeight); minY = numLinesBefore * windowLineHeight; maxY = minY + windowTextHeight; @@ -343,10 +351,12 @@ var usersWindow = (function () { lineClicked = numLinesBefore; } - if (0 <= lineClicked && lineClicked < linesOfUsers.length - && 0 <= overlayX && overlayX <= usersOnline[linesOfUsers[lineClicked]].textWidth) { - //print("Go to " + usersOnline[linesOfUsers[lineClicked]].username); - location.goToUser(usersOnline[linesOfUsers[lineClicked]].username); + userClicked = firstUserToDisplay + lineClicked; + + if (0 <= userClicked && userClicked < linesOfUsers.length + && 0 <= overlayX && overlayX <= usersOnline[linesOfUsers[userClicked]].textWidth) { + //print("Go to " + usersOnline[linesOfUsers[userClicked]].username); + location.goToUser(usersOnline[linesOfUsers[userClicked]].username); } } @@ -381,7 +391,9 @@ var usersWindow = (function () { scrollbarValue = (event.y - scrollbarBarClickedAt * scrollbarBarHeight - scrollbarBackgroundPosition.y) / (scrollbarBackgroundHeight - scrollbarBarHeight - 2); scrollbarValue = Math.min(Math.max(scrollbarValue, 0.0), 1.0); + firstUserToDisplay = Math.floor(scrollbarValue * (linesOfUsers.length - numUsersToDisplay)); updateOverlayPositions(); + updateUsersDisplay(); } else { isMovingScrollbar = false; } From 876f3e8a2351c2b5bdd92f09d393f9f4f7ae6a9b Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Thu, 26 Mar 2015 11:50:17 -0700 Subject: [PATCH 129/177] Scroll when click above or below bar --- examples/users.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/examples/users.js b/examples/users.js index ed1703c329..59263e0607 100644 --- a/examples/users.js +++ b/examples/users.js @@ -329,7 +329,8 @@ var usersWindow = (function () { lineClicked, userClicked, i, - visibilityChanged; + visibilityChanged, + delta; if (!isVisible) { return; @@ -380,6 +381,20 @@ var usersWindow = (function () { scrollbarBarClickedAt = (event.y - scrollbarBarPosition.y) / scrollbarBarHeight; isMovingScrollbar = true; } + + if (clickedOverlay === scrollbarBackground2D) { + delta = scrollbarBarHeight / (scrollbarBackgroundHeight - scrollbarBarHeight); + + if (event.y < scrollbarBarPosition.y) { + scrollbarValue = Math.max(scrollbarValue - delta, 0.0); + } else { + scrollbarValue = Math.min(scrollbarValue + delta, 1.0); + } + + firstUserToDisplay = Math.floor(scrollbarValue * (linesOfUsers.length - numUsersToDisplay)); + updateOverlayPositions(); + updateUsersDisplay(); + } } function onMouseMoveEvent(event) { From ef9d66514632575bc03824f8f3bc52780dc2a52b Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Thu, 26 Mar 2015 12:17:20 -0700 Subject: [PATCH 130/177] Highlight scrollbar when it is being moved --- examples/users.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/examples/users.js b/examples/users.js index 59263e0607..ebd59886aa 100644 --- a/examples/users.js +++ b/examples/users.js @@ -29,6 +29,7 @@ var usersWindow = (function () { SCROLLBAR_BAR_MIN_HEIGHT = 5, SCROLLBAR_BAR_COLOR_2D = { red: 180, green: 180, blue: 180 }, SCROLLBAR_BAR_ALPHA_2D = 0.8, + SCROLLBAR_BAR_SELECTED_ALPHA_2D = 0.9, scrollbarBar2D, scrollbarBackgroundHeight, scrollbarBarHeight, @@ -379,6 +380,9 @@ var usersWindow = (function () { if (clickedOverlay === scrollbarBar2D) { scrollbarBarClickedAt = (event.y - scrollbarBarPosition.y) / scrollbarBarHeight; + Overlays.editOverlay(scrollbarBar2D, { + backgroundAlpha: SCROLLBAR_BAR_SELECTED_ALPHA_2D + }); isMovingScrollbar = true; } @@ -410,12 +414,18 @@ var usersWindow = (function () { updateOverlayPositions(); updateUsersDisplay(); } else { + Overlays.editOverlay(scrollbarBar2D, { + backgroundAlpha: SCROLLBAR_BAR_ALPHA_2D + }); isMovingScrollbar = false; } } } function onMouseReleaseEvent() { + Overlays.editOverlay(scrollbarBar2D, { + backgroundAlpha: SCROLLBAR_BAR_ALPHA_2D + }); isMovingScrollbar = false; } From 858dbeb674445c9f1530bec5f84dd5482ea932f7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Thu, 26 Mar 2015 13:23:15 -0700 Subject: [PATCH 131/177] remove one line of cruft --- libraries/physics/src/CharacterController.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 84dcf25212..fb2457083a 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -357,7 +357,6 @@ void CharacterController::scanDown(btCollisionWorld* world) { btVector3 end = start - MAX_SCAN_HEIGHT * up; world->rayTest(start, end, callback); - bool wasHovering = _isHovering; if (!callback.hasHit()) { _isHovering = true; } else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) { From eea4c565472aab5692f871a41c14f160c46f1bc0 Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 26 Mar 2015 14:03:25 -0700 Subject: [PATCH 132/177] use TBB release libraries for apple external project --- cmake/externals/tbb/CMakeLists.txt | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/cmake/externals/tbb/CMakeLists.txt b/cmake/externals/tbb/CMakeLists.txt index 54a73dafb8..ad46196b95 100644 --- a/cmake/externals/tbb/CMakeLists.txt +++ b/cmake/externals/tbb/CMakeLists.txt @@ -95,9 +95,15 @@ elseif (UNIX) endif () if (DEFINED _TBB_LIB_DIR) - set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbb_debug.${_LIB_EXT} CACHE FILEPATH "TBB debug library location") + if (NOT APPLE) + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbb_debug.${_LIB_EXT} CACHE FILEPATH "TBB debug library location") + set(${EXTERNAL_NAME_UPPER}_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbbmalloc_debug.${_LIB_EXT} CACHE FILEPATH "TBB malloc debug library location") + else () + set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "TBB debug library location") + set(${EXTERNAL_NAME_UPPER}_MALLOC_LIBRARY_DEBUG "" CACHE FILEPATH "TBB malloc debug library location") + endif () + set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbb.${_LIB_EXT} CACHE FILEPATH "TBB release library location") - set(${EXTERNAL_NAME_UPPER}_MALLOC_LIBRARY_DEBUG ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbbmalloc_debug.${_LIB_EXT} CACHE FILEPATH "TBB malloc debug library location") set(${EXTERNAL_NAME_UPPER}_MALLOC_LIBRARY_RELEASE ${_TBB_LIB_DIR}/${_LIB_PREFIX}tbbmalloc.${_LIB_EXT} CACHE FILEPATH "TBB malloc release library location") endif () From 0ef4022e9400abbdb3b06d49b01937259007c8b7 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Thu, 26 Mar 2015 15:14:46 -0700 Subject: [PATCH 133/177] tweak gravity and step heights of controller --- libraries/physics/src/CharacterController.cpp | 25 ++++++++----------- libraries/physics/src/CharacterController.h | 3 ++- 2 files changed, 13 insertions(+), 15 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 84dcf25212..f243deffaa 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -228,9 +228,9 @@ CharacterController::CharacterController(AvatarData* avatarData) { _velocityTimeInterval = 0.0f; _verticalVelocity = 0.0f; _verticalOffset = 0.0f; - _gravity = 9.8f; + _gravity = 5.0f; // slower than Earth's _maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s. - _jumpSpeed = 7.0f; + _jumpSpeed = 5.0f; _wasOnGround = false; _wasJumping = false; _isHovering = true; @@ -352,8 +352,8 @@ void CharacterController::scanDown(btCollisionWorld* world) { btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); btVector3 start = _currentPosition; - const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight; // closest possible floor for disabling hover - const btScalar MIN_HOVER_HEIGHT = 2.0f + _halfHeight; // distance to floor for enabling hover + const btScalar MAX_SCAN_HEIGHT = 20.0f + _halfHeight + _radius; // closest possible floor for disabling hover + const btScalar MIN_HOVER_HEIGHT = 3.0f + _halfHeight + _radius; // distance to floor for enabling hover btVector3 end = start - MAX_SCAN_HEIGHT * up; world->rayTest(start, end, callback); @@ -374,7 +374,7 @@ void CharacterController::stepUp(btCollisionWorld* world) { btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); start.setOrigin(_currentPosition + up * (_convexShape->getMargin() + _addedMargin)); - _targetPosition = _currentPosition + up * _stepHeight; + _targetPosition = _currentPosition + up * _stepUpHeight; end.setIdentity(); end.setOrigin(_targetPosition); @@ -392,15 +392,15 @@ void CharacterController::stepUp(btCollisionWorld* world) { // Only modify the position if the hit was a slope and not a wall or ceiling. if (callback.m_hitNormalWorld.dot(up) > 0.0f) { - _lastStepUp = _stepHeight * callback.m_closestHitFraction; + _lastStepUp = _stepUpHeight * callback.m_closestHitFraction; _currentPosition.setInterpolate3(_currentPosition, _targetPosition, callback.m_closestHitFraction); } else { - _lastStepUp = _stepHeight; + _lastStepUp = _stepUpHeight; _currentPosition = _targetPosition; } } else { _currentPosition = _targetPosition; - _lastStepUp = _stepHeight; + _lastStepUp = _stepUpHeight; } } @@ -524,6 +524,7 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _wasJumping = false; } else if (!_wasJumping) { // sweep again for floor within downStep threshold + step = -_stepDownHeight * up; StepDownConvexResultCallback callback2 (_ghostObject, up, _currentPosition, step, @@ -535,7 +536,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt callback2.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; _currentPosition = _targetPosition; - step = (- _stepHeight) * up; _targetPosition = _currentPosition + step; start.setOrigin(_currentPosition); @@ -549,7 +549,6 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _wasJumping = false; } else { // nothing to step down on, so remove the stepUp effect - //_currentPosition = oldPosition; _lastStepUp = 0.0f; } } else { @@ -819,10 +818,8 @@ void CharacterController::updateShapeIfNecessary() { _ghostObject->setWorldTransform(btTransform(glmToBullet(_avatarData->getOrientation()), glmToBullet(_avatarData->getPosition()))); // stepHeight affects the heights of ledges that the character can ascend - // however the actual ledge height is some function of _stepHeight - // due to character shape and this CharacterController algorithm - // (the function is approximately 2*_stepHeight) - _stepHeight = 0.1f * (_radius + _halfHeight) + 0.1f; + _stepUpHeight = _radius + 0.25f * _halfHeight + 0.1f; + _stepDownHeight = _radius; // create new shape _convexShape = new btCapsuleShape(_radius, 2.0f * _halfHeight); diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index f604e60c31..b31c4855ea 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -59,7 +59,8 @@ protected: btScalar _maxSlopeCosine; // Cosine equivalent of _maxSlopeRadians (calculated once when set, for optimization) btScalar _gravity; - btScalar _stepHeight; // height of stepUp prior to stepForward + btScalar _stepUpHeight; // height of stepUp prior to stepForward + btScalar _stepDownHeight; // height of stepDown btScalar _addedMargin;//@todo: remove this and fix the code From 8a951e0dd3fc8bba4dc08c078c53743a31226dfb Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Thu, 26 Mar 2015 15:16:57 -0700 Subject: [PATCH 134/177] minor cleanup --- libraries/physics/src/CharacterController.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index f243deffaa..34c2f51b03 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -43,18 +43,18 @@ static btVector3 getNormalizedVector(const btVector3& v) { class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { public: btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : - btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) { - m_me = me; + btCollisionWorld::ClosestRayResultCallback(btVector3(0.0f, 0.0f, 0.0f), btVector3(0.0f, 0.0f, 0.0f)) { + _me = me; } virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { - if (rayResult.m_collisionObject == m_me) { - return 1.0; + if (rayResult.m_collisionObject == _me) { + return 1.0f; } return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace); } protected: - btCollisionObject* m_me; + btCollisionObject* _me; }; @@ -357,7 +357,6 @@ void CharacterController::scanDown(btCollisionWorld* world) { btVector3 end = start - MAX_SCAN_HEIGHT * up; world->rayTest(start, end, callback); - bool wasHovering = _isHovering; if (!callback.hasHit()) { _isHovering = true; } else if (_isHovering && callback.m_closestHitFraction * MAX_SCAN_HEIGHT < MIN_HOVER_HEIGHT) { From 8e7ead2ead37b13dec7db60ae5aea42894cf1370 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Thu, 26 Mar 2015 16:05:31 -0700 Subject: [PATCH 135/177] fix locking issue in enter/leave entity scripts --- examples/entityScripts/portal.js | 9 +++++++-- .../entities-renderer/src/EntityTreeRenderer.cpp | 12 +++++++----- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/examples/entityScripts/portal.js b/examples/entityScripts/portal.js index 5dd7849c38..4e2ec6ddaf 100644 --- a/examples/entityScripts/portal.js +++ b/examples/entityScripts/portal.js @@ -9,15 +9,20 @@ this.preload = function(entityID) { teleport = SoundCache.getSound("http://s3.amazonaws.com/hifi-public/birarda/teleport.raw"); - + var properties = Entities.getEntityProperties(entityID); - portalDestination = properties.userData; animationURL = properties.modelURL; print("The portal destination is " + portalDestination); } this.enterEntity = function(entityID) { + + var properties = Entities.getEntityProperties(entityID); // in case the userData/portalURL has changed + portalDestination = properties.userData; + + print("enterEntity() .... The portal destination is " + portalDestination); + if (portalDestination.length > 0) { print("Teleporting to hifi://" + portalDestination); Window.location = "hifi://" + portalDestination; diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index b005f67f5e..3faa06fc53 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -277,7 +277,6 @@ void EntityTreeRenderer::update() { void EntityTreeRenderer::checkEnterLeaveEntities() { if (_tree && !_shuttingDown) { - _tree->lockForWrite(); // so that our scripts can do edits if they want glm::vec3 avatarPosition = _viewState->getAvatarPosition(); if (avatarPosition != _lastAvatarPosition) { @@ -286,6 +285,7 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { QVector<EntityItemID> entitiesContainingAvatar; // find the entities near us + _tree->lockForRead(); // don't let someone else change our tree while we search static_cast<EntityTree*>(_tree)->findEntities(avatarPosition, radius, foundEntities); // create a list of entities that actually contain the avatar's position @@ -294,6 +294,11 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { entitiesContainingAvatar << entity->getEntityItemID(); } } + _tree->unlock(); + + // Note: at this point we don't need to worry about the tree being locked, because we only deal with + // EntityItemIDs from here. The loadEntityScript() method is robust against attempting to load scripts + // for entity IDs that no longer exist. // for all of our previous containing entities, if they are no longer containing then send them a leave event foreach(const EntityItemID& entityID, _currentEntitiesInside) { @@ -322,14 +327,12 @@ void EntityTreeRenderer::checkEnterLeaveEntities() { _currentEntitiesInside = entitiesContainingAvatar; _lastAvatarPosition = avatarPosition; } - _tree->unlock(); } } void EntityTreeRenderer::leaveAllEntities() { if (_tree && !_shuttingDown) { - _tree->lockForWrite(); // so that our scripts can do edits if they want - + // for all of our previous containing entities, if they are no longer containing then send them a leave event foreach(const EntityItemID& entityID, _currentEntitiesInside) { emit leaveEntity(entityID); @@ -344,7 +347,6 @@ void EntityTreeRenderer::leaveAllEntities() { // make sure our "last avatar position" is something other than our current position, so that on our // first chance, we'll check for enter/leave entity events. _lastAvatarPosition = _viewState->getAvatarPosition() + glm::vec3((float)TREE_SCALE); - _tree->unlock(); } } void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::RenderSide renderSide) { From 28e2e65da99fd9006f174ef74b4af04d4ef603ba Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Thu, 26 Mar 2015 16:23:36 -0700 Subject: [PATCH 136/177] Fix marketplace showing for all edit properties buttons --- examples/edit.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/edit.js b/examples/edit.js index 8088b7cd74..52e565f3f9 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -1162,7 +1162,7 @@ PropertiesTool = function(opts) { } pushCommandForSelections(); selectionManager._update(); - } else if (data.type = "showMarketplace") { + } else if (data.type == "showMarketplace") { if (marketplaceWindow.url != data.url) { marketplaceWindow.setURL(data.url); } From 6cff99f9d6253749fae2b25a87734f55c0d9b141 Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Thu, 26 Mar 2015 16:36:46 -0700 Subject: [PATCH 137/177] menu and display tweaks --- interface/src/Application.cpp | 10 +++------- interface/src/Menu.cpp | 14 +++++++------- interface/src/Menu.h | 6 +----- interface/src/devices/TV3DManager.cpp | 9 ++------- interface/src/ui/ApplicationOverlay.cpp | 13 +------------ interface/src/ui/ApplicationOverlay.h | 2 +- 6 files changed, 15 insertions(+), 39 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc8fa08c4e..8cd36b501f 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -789,7 +789,7 @@ void Application::paintGL() { DependencyManager::get<GlowEffect>()->render(); - if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { + { PerformanceTimer perfTimer("renderOverlay"); _applicationOverlay.renderOverlay(true); _applicationOverlay.displayOverlayTexture(); @@ -1127,13 +1127,10 @@ void Application::keyPressEvent(QKeyEvent* event) { Menu::getInstance()->triggerOption(MenuOption::FullscreenMirror); } break; - case Qt::Key_Slash: - Menu::getInstance()->triggerOption(MenuOption::UserInterface); - break; case Qt::Key_P: Menu::getInstance()->triggerOption(MenuOption::FirstPerson); break; - case Qt::Key_Percent: + case Qt::Key_Slash: Menu::getInstance()->triggerOption(MenuOption::Stats); break; case Qt::Key_Plus: @@ -3019,8 +3016,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs _nodeBoundsDisplay.draw(); // Render the world box - if (theCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats) && - Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { + if (theCamera.getMode() != CAMERA_MODE_MIRROR && Menu::getInstance()->isOptionChecked(MenuOption::Stats)) { PerformanceTimer perfTimer("worldBox"); renderWorldBox(); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 8d3c01320f..2ec5c12ca0 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -230,7 +230,6 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false, qApp, SLOT(cameraMenuChanged())); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::UserInterface, Qt::Key_Slash, true); addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools, Qt::META | Qt::Key_H, false, @@ -259,14 +258,13 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false); - addDisabledActionAndSeparator(viewMenu, "Stats"); - addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Percent); + addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash); addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, qApp, SLOT(toggleLogDialog())); addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0, dialogsManager.data(), SLOT(bandwidthDetails())); addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0, dialogsManager.data(), SLOT(octreeStatsDetails())); - addActionToQMenuAndActionHash(viewMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp())); + QMenu* developerMenu = addMenu("Developer"); @@ -538,10 +536,12 @@ Menu::Menu() { statsRenderer.data(), SLOT(toggleShowInjectedStreams())); -#ifndef Q_OS_MAC QMenu* helpMenu = addMenu("Help"); - QAction* helpAction = helpMenu->addAction(MenuOption::AboutApp); - connect(helpAction, SIGNAL(triggered()), qApp, SLOT(aboutApp())); + addActionToQMenuAndActionHash(helpMenu, MenuOption::EditEntitiesHelp, 0, qApp, SLOT(showEditEntitiesHelp())); + +#ifndef Q_OS_MAC + QAction* aboutAction = helpMenu->addAction(MenuOption::AboutApp); + connect(aboutAction, SIGNAL(triggered()), qApp, SLOT(aboutApp())); #endif } diff --git a/interface/src/Menu.h b/interface/src/Menu.h index 60fe5d4cd2..b3d2d548df 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -184,12 +184,10 @@ namespace MenuOption { const QString Mirror = "Mirror"; const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; - const QString NewVoxelCullingMode = "New Voxel Culling Mode"; const QString NoFaceTracking = "None"; const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity"; - const QString OctreeStats = "Voxel and Entity Statistics"; + const QString OctreeStats = "Entity Statistics"; const QString OffAxisProjection = "Off-Axis Projection"; - const QString OldVoxelCullingMode = "Old Voxel Culling Mode"; const QString OnlyDisplayTopTen = "Only Display Top Ten"; const QString Pair = "Pair"; const QString PipelineWarnings = "Log Render Pipeline Warnings"; @@ -233,7 +231,6 @@ namespace MenuOption { const QString ScriptEditor = "Script Editor..."; const QString ScriptedMotorControl = "Enable Scripted Motor Control"; const QString ShowBordersEntityNodes = "Show Entity Nodes"; - const QString ShowBordersVoxelNodes = "Show Voxel Nodes"; const QString ShowIKConstraints = "Show IK Constraints"; const QString SimpleShadows = "Simple"; const QString SixenseEnabled = "Enable Hydra Support"; @@ -251,7 +248,6 @@ namespace MenuOption { const QString TransmitterDrive = "Transmitter Drive"; const QString TurnWithHead = "Turn using Head"; const QString PackageModel = "Package Model"; - const QString UserInterface = "User Interface"; const QString Visage = "Visage"; const QString Wireframe = "Wireframe"; } diff --git a/interface/src/devices/TV3DManager.cpp b/interface/src/devices/TV3DManager.cpp index b5f57301f1..f082c6de47 100644 --- a/interface/src/devices/TV3DManager.cpp +++ b/interface/src/devices/TV3DManager.cpp @@ -104,7 +104,6 @@ void TV3DManager::display(Camera& whichCamera) { // We only need to render the overlays to a texture once, then we just render the texture as a quad // PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay() applicationOverlay.renderOverlay(true); - const bool displayOverlays = Menu::getInstance()->isOptionChecked(MenuOption::UserInterface); DependencyManager::get<GlowEffect>()->prepare(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -135,9 +134,7 @@ void TV3DManager::display(Camera& whichCamera) { eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0)); Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO); - if (displayOverlays) { - applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); - } + applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); _activeEye = NULL; } glPopMatrix(); @@ -166,9 +163,7 @@ void TV3DManager::display(Camera& whichCamera) { eyeCamera.setEyeOffsetPosition(glm::vec3(-_activeEye->modelTranslation,0,0)); Application::getInstance()->displaySide(eyeCamera, false, RenderArgs::MONO); - if (displayOverlays) { - applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); - } + applicationOverlay.displayOverlayTexture3DTV(whichCamera, _aspect, fov); _activeEye = NULL; } glPopMatrix(); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 0c5941366f..d9adaf02e6 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -176,18 +176,7 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) { _textureAspectRatio = (float)glCanvas->getDeviceWidth() / (float)glCanvas->getDeviceHeight(); //Handle fading and deactivation/activation of UI - if (Menu::getInstance()->isOptionChecked(MenuOption::UserInterface)) { - _alpha += FADE_SPEED; - if (_alpha > 1.0f) { - _alpha = 1.0f; - } - } else { - _alpha -= FADE_SPEED; - if (_alpha <= 0.0f) { - _alpha = 0.0f; - } - } - + // Render 2D overlay glMatrixMode(GL_PROJECTION); glDisable(GL_DEPTH_TEST); diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 64161e4a31..58b79adcda 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -114,7 +114,7 @@ private: quint64 _lastMouseMove; bool _magnifier; - float _alpha; + float _alpha = 1.0f; float _oculusUIRadius; float _trailingAudioLoudness; From ba82436d951da6accd32186465341077acc0beff Mon Sep 17 00:00:00 2001 From: Stephen Birarda <commit@birarda.com> Date: Thu, 26 Mar 2015 16:50:40 -0700 Subject: [PATCH 138/177] add user heartbeat if they choose not to send location --- interface/src/DiscoverabilityManager.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/interface/src/DiscoverabilityManager.cpp b/interface/src/DiscoverabilityManager.cpp index 791e5667c4..13697ff8be 100644 --- a/interface/src/DiscoverabilityManager.cpp +++ b/interface/src/DiscoverabilityManager.cpp @@ -30,8 +30,9 @@ DiscoverabilityManager::DiscoverabilityManager() : const QString API_USER_LOCATION_PATH = "/api/v1/user/location"; void DiscoverabilityManager::updateLocation() { + AccountManager& accountManager = AccountManager::getInstance(); + if (_mode.get() != Discoverability::None) { - AccountManager& accountManager = AccountManager::getInstance(); auto addressManager = DependencyManager::get<AddressManager>(); DomainHandler& domainHandler = DependencyManager::get<NodeList>()->getDomainHandler(); @@ -70,6 +71,10 @@ void DiscoverabilityManager::updateLocation() { QNetworkAccessManager::PutOperation, JSONCallbackParameters(), QJsonDocument(rootObject).toJson()); } + } else { + // we still send a heartbeat to the metaverse server for stats collection + const QString API_USER_HEARTBEAT_PATH = "/api/v1/user/heartbeat"; + accountManager.sendRequest(API_USER_HEARTBEAT_PATH, AccountManagerAuth::Required, QNetworkAccessManager::PutOperation); } } From 43b30c7ffab6f19e29b29d9d9c2771039f8ad104 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Thu, 26 Mar 2015 18:35:31 -0700 Subject: [PATCH 139/177] quiet compiler --- assignment-client/src/avatars/AvatarMixer.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 176fd51eea..39ae9a85ad 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -149,7 +149,8 @@ void AvatarMixer::broadcastAvatarData() { // about a given otherNode to this node // FIXME does this mean we should sort the othernodes by distance before iterating // over them? - float outputBandwidth = node->getOutboundBandwidth(); + // float outputBandwidth = + node->getOutboundBandwidth(); // this is an AGENT we have received head data from // send back a packet with other active node data to this node From 7da87d6e156bd93802261d8941e9c1ec7126671b Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Thu, 26 Mar 2015 18:37:55 -0700 Subject: [PATCH 140/177] set up a way to request ResourceCache downloads from a non-networking thread. --- interface/src/Application.cpp | 12 ++++- interface/src/Application.h | 2 + libraries/networking/src/ResourceCache.cpp | 49 ++++++++++++-------- libraries/networking/src/ResourceCache.h | 12 ++++- libraries/render-utils/src/GeometryCache.cpp | 4 +- libraries/render-utils/src/GeometryCache.h | 3 +- libraries/render-utils/src/Model.cpp | 16 ++++++- libraries/render-utils/src/Model.h | 4 +- 8 files changed, 73 insertions(+), 29 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index dc8fa08c4e..a69fc3659d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -344,6 +344,13 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) : // put the NodeList and datagram processing on the node thread nodeList->moveToThread(nodeThread); + // geometry background downloads need to happen on the Datagram Processor Thread. The idle loop will + // emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background + // downloads. + QSharedPointer<GeometryCache> geometryCacheP = DependencyManager::get<GeometryCache>(); + ResourceCache *geometryCache = geometryCacheP.data(); + connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets); + // connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal connect(&nodeList->getNodeSocket(), &QUdpSocket::readyRead, _datagramProcessor, &DatagramProcessor::processDatagrams); @@ -1569,6 +1576,9 @@ void Application::idle() { idleTimer->start(2); } } + + // check for any requested background downloads. + emit checkBackgroundDownloads(); } void Application::setFullscreen(bool fullscreen) { @@ -3140,7 +3150,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); - bool eyeRelativeCamera = false; + // bool eyeRelativeCamera = false; if (billboard) { _mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees _mirrorCamera.setPosition(_myAvatar->getPosition() + diff --git a/interface/src/Application.h b/interface/src/Application.h index 7764f297d3..54dbf60f3f 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -333,6 +333,8 @@ signals: void svoImportRequested(const QString& url); + void checkBackgroundDownloads(); + public slots: void domainChanged(const QString& domainHostname); void updateWindowTitle(); diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index b574eb1aeb..f6dfb94903 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -18,6 +18,7 @@ #include <QTimer> #include <SharedUtil.h> +#include <assert.h> #include "NetworkAccessManager.h" #include "ResourceCache.h" @@ -48,32 +49,42 @@ void ResourceCache::refresh(const QUrl& url) { } } +void ResourceCache::getResourceAsynchronously(const QUrl& url) { + qDebug() << "ResourceCache::getResourceAsynchronously" << url.toString(); + _resourcesToBeGottenLock.lockForWrite(); + _resourcesToBeGotten.enqueue(QUrl(url)); + _resourcesToBeGottenLock.unlock(); +} + +void ResourceCache::checkAsynchronousGets() { + assert(QThread::currentThread() == thread()); + _resourcesToBeGottenLock.lockForRead(); + if (_resourcesToBeGotten.isEmpty()) { + _resourcesToBeGottenLock.unlock(); + return; + } + QUrl url = _resourcesToBeGotten.dequeue(); + _resourcesToBeGottenLock.unlock(); + getResource(url); +} + QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl& fallback, - bool delayLoad, void* extra, bool block) { + bool delayLoad, void* extra) { + QSharedPointer<Resource> resource = _resources.value(url); + if (!resource.isNull()) { + return resource; + } + if (QThread::currentThread() != thread()) { - // This will re-call this method in the main thread. If block is true and the main thread - // is waiting on a lock, we'll deadlock here. - if (block) { - QSharedPointer<Resource> result; - QMetaObject::invokeMethod(this, "getResource", Qt::BlockingQueuedConnection, - Q_RETURN_ARG(QSharedPointer<Resource>, result), Q_ARG(const QUrl&, url), - Q_ARG(const QUrl&, fallback), Q_ARG(bool, delayLoad), Q_ARG(void*, extra)); - return result; - } else { - // Queue the re-invocation of this method, but if the main thread is blocked, don't wait. The - // return value may be NULL -- it's expected that this will be called again later, in order - // to receive the actual Resource. - QMetaObject::invokeMethod(this, "getResource", Qt::QueuedConnection, - Q_ARG(const QUrl&, url), - Q_ARG(const QUrl&, fallback), Q_ARG(bool, delayLoad), Q_ARG(void*, extra)); - return _resources.value(url); - } + assert(delayLoad); + getResourceAsynchronously(url); + return QSharedPointer<Resource>(); } if (!url.isValid() && !url.isEmpty() && fallback.isValid()) { return getResource(fallback, QUrl(), delayLoad); } - QSharedPointer<Resource> resource = _resources.value(url); + if (resource.isNull()) { resource = createResource(url, fallback.isValid() ? getResource(fallback, QUrl(), true) : QSharedPointer<Resource>(), delayLoad, extra); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index d4aa9a7fd9..c7aceb2e1a 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -21,6 +21,8 @@ #include <QSharedPointer> #include <QUrl> #include <QWeakPointer> +#include <QReadWriteLock> +#include <QQueue> #include <DependencyManager.h> @@ -79,6 +81,9 @@ public: void refresh(const QUrl& url); +public slots: + void checkAsynchronousGets(); + protected: qint64 _unusedResourcesMaxSize = DEFAULT_UNUSED_MAX_SIZE; qint64 _unusedResourcesSize = 0; @@ -89,7 +94,7 @@ protected: /// \param delayLoad if true, don't load the resource immediately; wait until load is first requested /// \param extra extra data to pass to the creator, if appropriate Q_INVOKABLE QSharedPointer<Resource> getResource(const QUrl& url, const QUrl& fallback = QUrl(), - bool delayLoad = false, void* extra = NULL, bool block = true); + bool delayLoad = false, void* extra = NULL); /// Creates a new resource. virtual QSharedPointer<Resource> createResource(const QUrl& url, @@ -109,6 +114,11 @@ private: int _lastLRUKey = 0; static int _requestLimit; + + void getResourceAsynchronously(const QUrl& url); + QReadWriteLock _resourcesToBeGottenLock; + QQueue<QUrl> _resourcesToBeGotten; + }; /// Base class for resources. diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 29f76291ea..c18dfa4d5f 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -1770,8 +1770,8 @@ void GeometryCache::renderLine(const glm::vec2& p1, const glm::vec2& p2, } -QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad, bool block) { - return getResource(url, fallback, delayLoad, NULL, block).staticCast<NetworkGeometry>(); +QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback, bool delayLoad) { + return getResource(url, fallback, delayLoad, NULL).staticCast<NetworkGeometry>(); } QSharedPointer<Resource> GeometryCache::createResource(const QUrl& url, diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index a64d041fc1..37156a6c71 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -203,8 +203,7 @@ public: /// Loads geometry from the specified URL. /// \param fallback a fallback URL to load if the desired one is unavailable /// \param delayLoad if true, don't load the geometry immediately; wait until load is first requested - QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), - bool delayLoad = false, bool block = true); + QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); protected: diff --git a/libraries/render-utils/src/Model.cpp b/libraries/render-utils/src/Model.cpp index 873f458ccf..81c9f9448c 100644 --- a/libraries/render-utils/src/Model.cpp +++ b/libraries/render-utils/src/Model.cpp @@ -325,6 +325,8 @@ void Model::init() { _skinTranslucentProgram = gpu::ShaderPointer(gpu::Shader::createProgram(skinModelVertex, modelTranslucentPixel)); makeResult = gpu::Shader::makeProgram(*_skinTranslucentProgram, slotBindings); initSkinProgram(_skinTranslucentProgram, _skinTranslucentLocations); + + (void) makeResult; // quiet compiler } } @@ -1032,12 +1034,22 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo } } -void Model::setCollisionModelURL(const QUrl& url, const QUrl& fallback, bool delayLoad) { + +const QSharedPointer<NetworkGeometry> Model::getCollisionGeometry(bool delayLoad) +{ + if (_collisionGeometry.isNull() && !_collisionUrl.isEmpty()) { + _collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(_collisionUrl, QUrl(), delayLoad); + } + + return _collisionGeometry; +} + +void Model::setCollisionModelURL(const QUrl& url) { if (_collisionUrl == url) { return; } _collisionUrl = url; - _collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, fallback, delayLoad); + _collisionGeometry = DependencyManager::get<GeometryCache>()->getGeometry(url, QUrl(), true); } bool Model::getJointPositionInWorldFrame(int jointIndex, glm::vec3& position) const { diff --git a/libraries/render-utils/src/Model.h b/libraries/render-utils/src/Model.h index 05db20b056..3b4cbdd450 100644 --- a/libraries/render-utils/src/Model.h +++ b/libraries/render-utils/src/Model.h @@ -109,7 +109,7 @@ public: const QUrl& getURL() const { return _url; } // Set the model to use for collisions - Q_INVOKABLE void setCollisionModelURL(const QUrl& url, const QUrl& fallback = QUrl(), bool delayLoad = false); + Q_INVOKABLE void setCollisionModelURL(const QUrl& url); const QUrl& getCollisionURL() const { return _collisionUrl; } /// Sets the distance parameter used for LOD computations. @@ -134,7 +134,7 @@ public: const QSharedPointer<NetworkGeometry>& getGeometry() const { return _geometry; } /// Returns a reference to the shared collision geometry. - const QSharedPointer<NetworkGeometry> getCollisionGeometry() {return _collisionGeometry; } + const QSharedPointer<NetworkGeometry> getCollisionGeometry(bool delayLoad = true); /// Returns the number of joint states in the model. int getJointStateCount() const { return _jointStates.size(); } From 821ac605f5dc8cd93cf8460f456defe05b099041 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Thu, 26 Mar 2015 19:48:52 -0700 Subject: [PATCH 141/177] smoother motion on steps faster motion when "flying" cleanup of MyAvatar::updatePosition() --- interface/src/avatar/MyAvatar.cpp | 136 +++--------------- interface/src/avatar/MyAvatar.h | 1 - libraries/physics/src/CharacterController.cpp | 55 ++++--- libraries/physics/src/CharacterController.h | 6 +- 4 files changed, 63 insertions(+), 135 deletions(-) diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 2f42544f28..aa36748f0c 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -174,11 +174,7 @@ void MyAvatar::simulate(float deltaTime) { { PerformanceTimer perfTimer("transform"); updateOrientation(deltaTime); - if (isPhysicsEnabled()) { - updatePositionWithPhysics(deltaTime); - } else { - updatePosition(deltaTime); - } + updatePosition(deltaTime); } { @@ -1258,128 +1254,38 @@ glm::vec3 MyAvatar::applyScriptedMotor(float deltaTime, const glm::vec3& localVe return localVelocity + motorEfficiency * deltaVelocity; } -const float NEARBY_FLOOR_THRESHOLD = 5.0f; - void MyAvatar::updatePosition(float deltaTime) { - - // check for floor by casting a ray straight down from avatar's position - float heightAboveFloor = FLT_MAX; - bool hasFloor = false; - const CapsuleShape& boundingShape = _skeletonModel.getBoundingShape(); - const float maxFloorDistance = boundingShape.getBoundingRadius() * NEARBY_FLOOR_THRESHOLD; - - RayIntersectionInfo intersection; - // NOTE: avatar is center of PhysicsSimulation, so rayStart is the origin for the purposes of the raycast - intersection._rayStart = glm::vec3(0.0f); - intersection._rayDirection = - _worldUpDirection; - intersection._rayLength = 4.0f * boundingShape.getBoundingRadius(); - - // velocity is initialized to the measured _velocity but will be modified by friction, external thrust, etc - glm::vec3 velocity = _velocity; - - bool pushingUp = (_driveKeys[UP] - _driveKeys[DOWN] > 0.0f) || _scriptedMotorVelocity.y > 0.0f; - if (_motionBehaviors & AVATAR_MOTION_STAND_ON_NEARBY_FLOORS) { - const float MAX_SPEED_UNDER_GRAVITY = 2.0f * _scale * MAX_WALKING_SPEED; - if (pushingUp || glm::length2(velocity) > MAX_SPEED_UNDER_GRAVITY * MAX_SPEED_UNDER_GRAVITY) { - // we're pushing up or moving quickly, so disable gravity - setLocalGravity(glm::vec3(0.0f)); - hasFloor = false; - } else { - if (heightAboveFloor > maxFloorDistance) { - // disable local gravity when floor is too far away - setLocalGravity(glm::vec3(0.0f)); - hasFloor = false; - } else { - // enable gravity - setLocalGravity(-_worldUpDirection); - } - } - } - - bool zeroDownwardVelocity = false; - bool gravityEnabled = (glm::length2(_gravity) > EPSILON); - if (gravityEnabled) { - const float SLOP = 0.002f; - if (heightAboveFloor < SLOP) { - if (heightAboveFloor < 0.0) { - // Gravity is in effect so we assume that the avatar is colliding against the world and we need - // to lift avatar out of floor, but we don't want to do it too fast (keep it smooth). - float distanceToLift = glm::min(-heightAboveFloor, MAX_WALKING_SPEED * deltaTime); - - // We don't use applyPositionDelta() for this lift distance because we don't want the avatar - // to come flying out of the floor. Instead we update position directly, and set a boolean - // that will remind us later to zero any downward component of the velocity. - _position += distanceToLift * _worldUpDirection; - } - zeroDownwardVelocity = true; - } - if (!zeroDownwardVelocity) { - velocity += (deltaTime * GRAVITY_EARTH) * _gravity; - } - } - - // rotate velocity into camera frame - glm::quat rotation = getHead()->getCameraOrientation(); - glm::vec3 localVelocity = glm::inverse(rotation) * velocity; - - // apply motors in camera frame - glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor); - newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); - - // rotate back into world-frame - velocity = rotation * newLocalVelocity; - - // apply thrust - velocity += _thrust * deltaTime; - _thrust = glm::vec3(0.0f); - - // remove downward velocity so we don't push into floor - if (zeroDownwardVelocity) { - float verticalSpeed = glm::dot(velocity, _worldUpDirection); - if (verticalSpeed < 0.0f || !pushingUp) { - velocity -= verticalSpeed * _worldUpDirection; - } - } - - // cap avatar speed - float speed = glm::length(velocity); - if (speed > MAX_AVATAR_SPEED) { - velocity *= MAX_AVATAR_SPEED / speed; - speed = MAX_AVATAR_SPEED; - } - - // update position - if (speed > MIN_AVATAR_SPEED) { - applyPositionDelta(deltaTime * velocity); - } - - // update _moving flag based on speed - const float MOVING_SPEED_THRESHOLD = 0.01f; - _moving = speed > MOVING_SPEED_THRESHOLD; - - measureMotionDerivatives(deltaTime); -} - -void MyAvatar::updatePositionWithPhysics(float deltaTime) { // rotate velocity into camera frame glm::quat rotation = getHead()->getCameraOrientation(); glm::vec3 localVelocity = glm::inverse(rotation) * _velocity; - bool hasFloor = false; - glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, hasFloor); + bool isOnGround = _characterController.onGround(); + glm::vec3 newLocalVelocity = applyKeyboardMotor(deltaTime, localVelocity, isOnGround); newLocalVelocity = applyScriptedMotor(deltaTime, newLocalVelocity); - // cap avatar speed - float speed = glm::length(newLocalVelocity); - if (speed > MAX_WALKING_SPEED) { - newLocalVelocity *= MAX_WALKING_SPEED / speed; - } - // rotate back into world-frame _velocity = rotation * newLocalVelocity; _velocity += _thrust * deltaTime; _thrust = glm::vec3(0.0f); + + // cap avatar speed + float speed = glm::length(_velocity); + if (speed > MAX_AVATAR_SPEED) { + _velocity *= MAX_AVATAR_SPEED / speed; + speed = MAX_AVATAR_SPEED; + } + + if (speed > MIN_AVATAR_SPEED && !isPhysicsEnabled()) { + // update position ourselves + applyPositionDelta(deltaTime * _velocity); + measureMotionDerivatives(deltaTime); + } // else physics will move avatar later + + // update _moving flag based on speed + const float MOVING_SPEED_THRESHOLD = 0.01f; + _moving = speed > MOVING_SPEED_THRESHOLD; + } void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) { diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index a37d1c6a30..320a3179bc 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -234,7 +234,6 @@ private: glm::vec3 applyKeyboardMotor(float deltaTime, const glm::vec3& velocity, bool walkingOnFloor); glm::vec3 applyScriptedMotor(float deltaTime, const glm::vec3& velocity); void updatePosition(float deltaTime); - void updatePositionWithPhysics(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void maybeUpdateBillboard(); void setGravity(const glm::vec3& gravity); diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 34c2f51b03..aa0d109732 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -231,8 +231,8 @@ CharacterController::CharacterController(AvatarData* avatarData) { _gravity = 5.0f; // slower than Earth's _maxFallSpeed = 55.0f; // Terminal velocity of a sky diver in m/s. _jumpSpeed = 5.0f; - _wasOnGround = false; - _wasJumping = false; + _isOnGround = false; + _isJumping = false; _isHovering = true; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; @@ -450,12 +450,12 @@ void CharacterController::stepForward(btCollisionWorld* collisionWorld, const bt btScalar margin = _convexShape->getMargin(); _convexShape->setMargin(margin + _addedMargin); - const btScalar MIN_STEP_DISTANCE = 0.0001f; + const btScalar MIN_STEP_DISTANCE_SQUARED = 1.0e-6f; btVector3 step = _targetPosition - _currentPosition; btScalar stepLength2 = step.length2(); int maxIter = 10; - while (stepLength2 > MIN_STEP_DISTANCE && maxIter-- > 0) { + while (stepLength2 > MIN_STEP_DISTANCE_SQUARED && maxIter-- > 0) { start.setOrigin(_currentPosition); end.setOrigin(_targetPosition); @@ -516,12 +516,14 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt end.setOrigin(_targetPosition); _ghostObject->convexSweepTest(_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); + _isOnGround = false; if (callback.hasHit()) { _currentPosition += callback.m_closestHitFraction * step; _verticalVelocity = 0.0f; _verticalOffset = 0.0f; - _wasJumping = false; - } else if (!_wasJumping) { + _isJumping = false; + _isOnGround = true; + } else if (!_isJumping) { // sweep again for floor within downStep threshold step = -_stepDownHeight * up; StepDownConvexResultCallback callback2 (_ghostObject, @@ -545,9 +547,10 @@ void CharacterController::stepDown(btCollisionWorld* collisionWorld, btScalar dt _currentPosition += callback2.m_closestHitFraction * step; _verticalVelocity = 0.0f; _verticalOffset = 0.0f; - _wasJumping = false; + _isJumping = false; + _isOnGround = true; } else { - // nothing to step down on, so remove the stepUp effect + // nothing to step down on _lastStepUp = 0.0f; } } else { @@ -571,8 +574,8 @@ void CharacterController::setVelocityForTimeInterval(const btVector3& velocity, void CharacterController::reset(btCollisionWorld* collisionWorld) { _verticalVelocity = 0.0; _verticalOffset = 0.0; - _wasOnGround = false; - _wasJumping = false; + _isOnGround = false; + _isJumping = false; _walkDirection.setValue(0,0,0); _velocityTimeInterval = 0.0; @@ -620,11 +623,9 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // Update fall velocity. if (_isHovering) { - _wasOnGround = false; const btScalar HOVER_RELAXATION_TIMESCALE = 1.0f; _verticalVelocity *= (1.0f - dt / HOVER_RELAXATION_TIMESCALE); } else { - _wasOnGround = onGround(); _verticalVelocity -= _gravity * dt; if (_verticalVelocity > _jumpSpeed) { _verticalVelocity = _jumpSpeed; @@ -649,6 +650,7 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar // compute substep and decrement total interval btScalar dtMoving = (dt < _velocityTimeInterval) ? dt : _velocityTimeInterval; _velocityTimeInterval -= dt; + _stepDt += dt; // stepForward substep btVector3 move = _walkDirection * dtMoving; @@ -673,7 +675,7 @@ void CharacterController::setMaxJumpHeight(btScalar maxJumpHeight) { } bool CharacterController::canJump() const { - return onGround(); + return _isOnGround; } void CharacterController::jump() { @@ -698,7 +700,7 @@ btScalar CharacterController::getMaxSlope() const { } bool CharacterController::onGround() const { - return _enabled && _verticalVelocity == 0.0f && _verticalOffset == 0.0f; + return _isOnGround; } void CharacterController::debugDraw(btIDebugDraw* debugDrawer) { @@ -761,6 +763,7 @@ void CharacterController::setEnabled(bool enabled) { // it was previously set by something else (e.g. an UPDATE_SHAPE event). _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; + _isOnGround = false; } _enabled = enabled; } @@ -842,9 +845,12 @@ void CharacterController::preSimulation(btScalar timeStep) { _pendingFlags &= ~ PENDING_FLAG_JUMP; if (canJump()) { _verticalVelocity = _jumpSpeed; - _wasJumping = true; + _isJumping = true; } } + // remember last position so we can throttle the total motion from the next step + _lastPosition = position; + _stepDt = 0.0f; } } @@ -852,9 +858,24 @@ void CharacterController::postSimulation() { if (_enabled) { const btTransform& avatarTransform = _ghostObject->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); - glm::vec3 offset = rotation * _shapeLocalOffset; + glm::vec3 position = bulletToGLM(avatarTransform.getOrigin()); + + // cap the velocity of the step so that the character doesn't POP! so hard on steps + glm::vec3 finalStep = position - _lastPosition; + btVector3 finalVelocity = _walkDirection; + btVector3 up = quatRotate(_currentRotation, LOCAL_UP_AXIS); + finalVelocity += _verticalVelocity * up; + const btScalar MAX_RESOLUTION_SPEED = 5.0f; // m/sec + btScalar maxStepLength = glm::max(MAX_RESOLUTION_SPEED, 2.0f * finalVelocity.length()) * _stepDt; + btScalar stepLength = glm::length(finalStep); + if (stepLength > maxStepLength) { + position = _lastPosition + (maxStepLength / stepLength) * finalStep; + // NOTE: we don't need to move ghostObject to throttled position unless + // we want to support do async ray-traces/collision-queries against character + } + _avatarData->setOrientation(rotation); - _avatarData->setPosition(bulletToGLM(avatarTransform.getOrigin()) - offset); + _avatarData->setPosition(position - rotation * _shapeLocalOffset); } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index b31c4855ea..ec7d9426f4 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -72,6 +72,7 @@ protected: btVector3 _currentPosition; btQuaternion _currentRotation; btVector3 _targetPosition; + glm::vec3 _lastPosition; btScalar _lastStepUp; ///keep track of the contact manifolds @@ -81,10 +82,11 @@ protected: btVector3 _floorNormal; // points from object to character bool _enabled; - bool _wasOnGround; - bool _wasJumping; + bool _isOnGround; + bool _isJumping; bool _isHovering; btScalar _velocityTimeInterval; + btScalar _stepDt; uint32_t _pendingFlags; glm::vec3 _shapeLocalOffset; From daaba330d5e99efe704dc02be7bccc81aab445f0 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Fri, 27 Mar 2015 14:41:32 +0100 Subject: [PATCH 142/177] Turn lambda into helper function --- libraries/fbx/src/FSTReader.cpp | 47 +++++++++++++++++---------------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index 4f882d4bd8..82a8c338f0 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -54,44 +54,45 @@ QVariantHash readMapping(const QByteArray& data) { return parseMapping(&buffer); } +void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it) { + QByteArray key = it.key().toUtf8() + " = "; + QVariantHash hashValue = it.value().toHash(); + if (hashValue.isEmpty()) { + buffer.write(key + it.value().toByteArray() + "\n"); + return; + } + for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) { + QByteArray extendedKey = key + second.key().toUtf8(); + QVariantList listValue = second.value().toList(); + if (listValue.isEmpty()) { + buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n"); + continue; + } + buffer.write(extendedKey); + for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) { + buffer.write(" = " + third->toByteArray()); + } + buffer.write("\n"); + } +}; + QByteArray writeMapping(const QVariantHash& mapping) { static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << SCALE_FIELD << FILENAME_FIELD << TEXDIR_FIELD << JOINT_FIELD << FREE_JOINT_FIELD << BLENDSHAPE_FIELD << JOINT_INDEX_FIELD; QBuffer buffer; - auto writeVariant = [&buffer](QVariantHash::const_iterator& it) { - QByteArray key = it.key().toUtf8() + " = "; - QVariantHash hashValue = it.value().toHash(); - if (hashValue.isEmpty()) { - buffer.write(key + it.value().toByteArray() + "\n"); - return; - } - for (QVariantHash::const_iterator second = hashValue.constBegin(); second != hashValue.constEnd(); second++) { - QByteArray extendedKey = key + second.key().toUtf8(); - QVariantList listValue = second.value().toList(); - if (listValue.isEmpty()) { - buffer.write(extendedKey + " = " + second.value().toByteArray() + "\n"); - continue; - } - buffer.write(extendedKey); - for (QVariantList::const_iterator third = listValue.constBegin(); third != listValue.constEnd(); third++) { - buffer.write(" = " + third->toByteArray()); - } - buffer.write("\n"); - } - }; buffer.open(QIODevice::WriteOnly); for (auto key : PREFERED_ORDER) { auto it = mapping.find(key); if (it != mapping.constEnd()) { - writeVariant(it); + writeVariant(buffer, it); } } for (auto it = mapping.constBegin(); it != mapping.constEnd(); it++) { if (!PREFERED_ORDER.contains(it.key())) { - writeVariant(it); + writeVariant(buffer, it); } } return buffer.data(); From e16c8852fb1b379717b87b9e52d19641559f0db8 Mon Sep 17 00:00:00 2001 From: Atlante45 <clement.brisset@gmail.com> Date: Fri, 27 Mar 2015 14:43:09 +0100 Subject: [PATCH 143/177] extra ; --- libraries/fbx/src/FSTReader.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fbx/src/FSTReader.cpp b/libraries/fbx/src/FSTReader.cpp index 82a8c338f0..f1ffe11996 100644 --- a/libraries/fbx/src/FSTReader.cpp +++ b/libraries/fbx/src/FSTReader.cpp @@ -74,7 +74,7 @@ void writeVariant(QBuffer& buffer, QVariantHash::const_iterator& it) { } buffer.write("\n"); } -}; +} QByteArray writeMapping(const QVariantHash& mapping) { static const QStringList PREFERED_ORDER = QStringList() << NAME_FIELD << SCALE_FIELD << FILENAME_FIELD From b9b2c30bba5f78cad7fb3a38eb9a46a3e4108005 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Fri, 27 Mar 2015 09:01:44 -0700 Subject: [PATCH 144/177] use QObject::deleteLater() not explicit delete --- libraries/networking/src/AccountManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/networking/src/AccountManager.cpp b/libraries/networking/src/AccountManager.cpp index 5858c0926d..46c6418c63 100644 --- a/libraries/networking/src/AccountManager.cpp +++ b/libraries/networking/src/AccountManager.cpp @@ -282,7 +282,7 @@ void AccountManager::processReply() { } else { passErrorToCallback(requestReply); } - delete requestReply; + requestReply->deleteLater(); } void AccountManager::passSuccessToCallback(QNetworkReply* requestReply) { From c9f4f4626bea7d49f6e8dcf2f430e37f011765df Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Fri, 27 Mar 2015 09:21:32 -0700 Subject: [PATCH 145/177] Update default light color to (150,150,150) --- examples/edit.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 52e565f3f9..96b31cdce0 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -387,9 +387,7 @@ var toolBar = (function () { position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_LIGHT_DIMENSIONS), DEFAULT_LIGHT_DIMENSIONS), dimensions: DEFAULT_LIGHT_DIMENSIONS, isSpotlight: false, - diffuseColor: { red: 255, green: 255, blue: 255 }, - ambientColor: { red: 255, green: 255, blue: 255 }, - specularColor: { red: 0, green: 0, blue: 0 }, + color: { red: 150, green: 150, blue: 150 }, constantAttenuation: 1, linearAttenuation: 0, From 83af2feded2590f462075a65798b378359727b9d Mon Sep 17 00:00:00 2001 From: Chris Collins <chris@highfidelity.io> Date: Fri, 27 Mar 2015 09:33:19 -0700 Subject: [PATCH 146/177] Remove reference to FBX files Remove reference to FBX files --- examples/edit.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 52e565f3f9..07cd17c0ff 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -88,13 +88,7 @@ var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode"; var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain." var modelURLs = [ - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Alder.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush1.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/2-Terrain:%20Bush6.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed2.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed4.fbx", - HIFI_PUBLIC_BUCKET + "models/entities/3-Buildings-1-Rustic-Shed7.fbx" + "Insert the URL to your FBX" ]; var mode = 0; From 087248dffca654f6dc2444af5ca86715300672c5 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Fri, 27 Mar 2015 13:14:20 -0700 Subject: [PATCH 147/177] fix locking in ResourceCache::checkAsynchronousGets --- libraries/networking/src/ResourceCache.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index f6dfb94903..739e587f5f 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -58,14 +58,12 @@ void ResourceCache::getResourceAsynchronously(const QUrl& url) { void ResourceCache::checkAsynchronousGets() { assert(QThread::currentThread() == thread()); - _resourcesToBeGottenLock.lockForRead(); - if (_resourcesToBeGotten.isEmpty()) { + if (!_resourcesToBeGotten.isEmpty()) { + _resourcesToBeGottenLock.lockForWrite(); + QUrl url = _resourcesToBeGotten.dequeue(); _resourcesToBeGottenLock.unlock(); - return; + getResource(url); } - QUrl url = _resourcesToBeGotten.dequeue(); - _resourcesToBeGottenLock.unlock(); - getResource(url); } QSharedPointer<Resource> ResourceCache::getResource(const QUrl& url, const QUrl& fallback, From 81cb1e98bae3d195be27c6211a3d66495f60b2f5 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Fri, 27 Mar 2015 13:35:58 -0700 Subject: [PATCH 148/177] Rename attribution to marketplaceID --- libraries/entities/src/EntityItem.cpp | 18 +++++++++--------- libraries/entities/src/EntityItem.h | 6 +++--- .../entities/src/EntityItemProperties.cpp | 14 +++++++------- libraries/entities/src/EntityItemProperties.h | 8 ++++---- .../src/EntityItemPropertiesDefaults.h | 2 +- libraries/networking/src/PacketHeaders.cpp | 2 +- libraries/networking/src/PacketHeaders.h | 4 ++-- 7 files changed, 27 insertions(+), 27 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index d54e7e6cc1..a73f652282 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -57,7 +57,7 @@ void EntityItem::initFromEntityItemID(const EntityItemID& entityItemID) { _collisionsWillMove = ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE; _locked = ENTITY_ITEM_DEFAULT_LOCKED; _userData = ENTITY_ITEM_DEFAULT_USER_DATA; - _attribution = ENTITY_ITEM_DEFAULT_ATTRIBUTION; + _marketplaceID = ENTITY_ITEM_DEFAULT_MARKETPLACE_ID; } EntityItem::EntityItem(const EntityItemID& entityItemID) { @@ -117,7 +117,7 @@ EntityPropertyFlags EntityItem::getEntityProperties(EncodeBitstreamParams& param requestedProperties += PROP_COLLISIONS_WILL_MOVE; requestedProperties += PROP_LOCKED; requestedProperties += PROP_USER_DATA; - requestedProperties += PROP_ATTRIBUTION; + requestedProperties += PROP_MARKETPLACE_ID; return requestedProperties; } @@ -240,7 +240,7 @@ OctreeElement::AppendState EntityItem::appendEntityData(OctreePacketData* packet APPEND_ENTITY_PROPERTY(PROP_COLLISIONS_WILL_MOVE, appendValue, getCollisionsWillMove()); APPEND_ENTITY_PROPERTY(PROP_LOCKED, appendValue, getLocked()); APPEND_ENTITY_PROPERTY(PROP_USER_DATA, appendValue, getUserData()); - APPEND_ENTITY_PROPERTY(PROP_ATTRIBUTION, appendValue, getAttribution()); + APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, getMarketplaceID()); appendSubclassData(packetData, params, entityTreeElementExtraEncodeData, requestedProperties, @@ -555,8 +555,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef READ_ENTITY_PROPERTY(PROP_LOCKED, bool, _locked); READ_ENTITY_PROPERTY_STRING(PROP_USER_DATA, setUserData); - if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_ATTRIBUTION) { - READ_ENTITY_PROPERTY_STRING(PROP_ATTRIBUTION, setAttribution); + if (args.bitstreamVersion >= VERSION_ENTITIES_HAS_MARKETPLACE_ID) { + READ_ENTITY_PROPERTY_STRING(PROP_MARKETPLACE_ID, setMarketplaceID); } bytesRead += readEntitySubclassDataFromBuffer(dataAt, (bytesLeftToRead - bytesRead), args, propertyFlags, overwriteLocalData); @@ -568,8 +568,8 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef // by doing this parsing here... but it's not likely going to fully recover the content. // // TODO: Remove this conde once we've sufficiently migrated content past this damaged version - if (args.bitstreamVersion == VERSION_ENTITIES_HAS_ATTRIBUTION_DAMAGED) { - READ_ENTITY_PROPERTY_STRING(PROP_ATTRIBUTION, setAttribution); + if (args.bitstreamVersion == VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED) { + READ_ENTITY_PROPERTY_STRING(PROP_MARKETPLACE_ID, setMarketplaceID); } if (overwriteLocalData && (getDirtyFlags() & (EntityItem::DIRTY_POSITION | EntityItem::DIRTY_VELOCITY))) { @@ -838,7 +838,7 @@ EntityItemProperties EntityItem::getProperties() const { COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionsWillMove, getCollisionsWillMove); COPY_ENTITY_PROPERTY_TO_PROPERTIES(locked, getLocked); COPY_ENTITY_PROPERTY_TO_PROPERTIES(userData, getUserData); - COPY_ENTITY_PROPERTY_TO_PROPERTIES(attribution, getAttribution); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(marketplaceID, getMarketplaceID); properties._defaultSettings = false; @@ -867,7 +867,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); SET_ENTITY_PROPERTY_FROM_PROPERTIES(locked, setLocked); SET_ENTITY_PROPERTY_FROM_PROPERTIES(userData, setUserData); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(attribution, setAttribution); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(marketplaceID, setMarketplaceID); if (somethingChanged) { somethingChangedNotification(); // notify derived classes that something has changed diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index 88287f8965..840bc54a2f 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -251,8 +251,8 @@ public: const QString& getUserData() const { return _userData; } void setUserData(const QString& value) { _userData = value; } - const QString& getAttribution() const { return _attribution; } - void setAttribution(const QString& value) { _attribution = value; } + const QString& getMarketplaceID() const { return _marketplaceID; } + void setMarketplaceID(const QString& value) { _marketplaceID = value; } // TODO: get rid of users of getRadius()... float getRadius() const; @@ -342,7 +342,7 @@ protected: bool _collisionsWillMove; bool _locked; QString _userData; - QString _attribution; + QString _marketplaceID; // NOTE: Damping is applied like this: v *= pow(1 - damping, dt) // diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index 32352f557d..6e6e897230 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -70,7 +70,7 @@ EntityItemProperties::EntityItemProperties() : CONSTRUCT_PROPERTY(emitStrength, ParticleEffectEntityItem::DEFAULT_EMIT_STRENGTH), CONSTRUCT_PROPERTY(localGravity, ParticleEffectEntityItem::DEFAULT_LOCAL_GRAVITY), CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS), - CONSTRUCT_PROPERTY(attribution, ENTITY_ITEM_DEFAULT_ATTRIBUTION), + CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID), _id(UNKNOWN_ENTITY_ID), _idSet(false), @@ -260,7 +260,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_EMIT_STRENGTH, emitStrength); CHECK_PROPERTY_CHANGE(PROP_LOCAL_GRAVITY, localGravity); CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius); - CHECK_PROPERTY_CHANGE(PROP_ATTRIBUTION, attribution); + CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID); return changedProperties; } @@ -323,7 +323,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons COPY_PROPERTY_TO_QSCRIPTVALUE(emitStrength); COPY_PROPERTY_TO_QSCRIPTVALUE(localGravity); COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius); - COPY_PROPERTY_TO_QSCRIPTVALUE(attribution); + COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID); // Sitting properties support QScriptValue sittingPoints = engine->newObject(); @@ -405,7 +405,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) { COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(emitStrength, setEmitStrength); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(localGravity, setLocalGravity); COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(particleRadius, setParticleRadius); - COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(attribution, setAttribution); + COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(marketplaceID, setMarketplaceID); _lastEdited = usecTimestampNow(); } @@ -591,7 +591,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, properties.getParticleRadius()); } - APPEND_ENTITY_PROPERTY(PROP_ATTRIBUTION, appendValue, properties.getAttribution()); + APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, properties.getMarketplaceID()); } if (propertyCount > 0) { int endOfEntityItemData = packetData->getUncompressedByteOffset(); @@ -822,7 +822,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius); } - READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ATTRIBUTION, setAttribution); + READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MARKETPLACE_ID, setMarketplaceID); return valid; } @@ -905,7 +905,7 @@ void EntityItemProperties::markAllChanged() { _localGravityChanged = true; _particleRadiusChanged = true; - _attributionChanged = true; + _marketplaceIDChanged = true; } /// The maximum bounding cube for the entity, independent of it's rotation. diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 39e290e602..3f492d649c 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -94,11 +94,11 @@ enum EntityPropertyList { PROP_PARTICLE_RADIUS, PROP_COLLISION_MODEL_URL, - PROP_ATTRIBUTION, + PROP_MARKETPLACE_ID, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties ABOVE this line and then modify PROP_LAST_ITEM below - PROP_LAST_ITEM = PROP_ATTRIBUTION, + PROP_LAST_ITEM = PROP_MARKETPLACE_ID, //////////////////////////////////////////////////////////////////////////////////////////////////// @@ -205,7 +205,7 @@ public: DEFINE_PROPERTY(PROP_EMIT_STRENGTH, EmitStrength, emitStrength, float); DEFINE_PROPERTY(PROP_LOCAL_GRAVITY, LocalGravity, localGravity, float); DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float); - DEFINE_PROPERTY_REF(PROP_ATTRIBUTION, Attribution, attribution, QString); + DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString); public: float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); } @@ -333,7 +333,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) { DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitStrength, emitStrength, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, LocalGravity, localGravity, ""); DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, ""); - DEBUG_PROPERTY_IF_CHANGED(debug, properties, Attribution, attribution, ""); + DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, ""); debug << " last edited:" << properties.getLastEdited() << "\n"; debug << " edited ago:" << properties.getEditedAgo() << "\n"; diff --git a/libraries/entities/src/EntityItemPropertiesDefaults.h b/libraries/entities/src/EntityItemPropertiesDefaults.h index e57aea3d85..aa7c77ede4 100644 --- a/libraries/entities/src/EntityItemPropertiesDefaults.h +++ b/libraries/entities/src/EntityItemPropertiesDefaults.h @@ -22,7 +22,7 @@ const glm::vec3 ENTITY_ITEM_ZERO_VEC3(0.0f); const bool ENTITY_ITEM_DEFAULT_LOCKED = false; const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString(""); -const QString ENTITY_ITEM_DEFAULT_ATTRIBUTION = QString(""); +const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString(""); const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f; const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f; diff --git a/libraries/networking/src/PacketHeaders.cpp b/libraries/networking/src/PacketHeaders.cpp index abac09d238..78a27af686 100644 --- a/libraries/networking/src/PacketHeaders.cpp +++ b/libraries/networking/src/PacketHeaders.cpp @@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) { return 1; case PacketTypeEntityAddOrEdit: case PacketTypeEntityData: - return VERSION_ENTITIES_HAS_ATTRIBUTION; + return VERSION_ENTITIES_HAS_MARKETPLACE_ID; case PacketTypeEntityErase: return 2; case PacketTypeAudioStreamStats: diff --git a/libraries/networking/src/PacketHeaders.h b/libraries/networking/src/PacketHeaders.h index 5822f2af3a..924d219b75 100644 --- a/libraries/networking/src/PacketHeaders.h +++ b/libraries/networking/src/PacketHeaders.h @@ -132,8 +132,8 @@ const PacketVersion VERSION_ENTITIES_LIGHT_HAS_INTENSITY_AND_COLOR_PROPERTIES = const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10; const PacketVersion VERSION_ENTITIES_USE_METERS_AND_RADIANS = 11; const PacketVersion VERSION_ENTITIES_HAS_COLLISION_MODEL = 12; -const PacketVersion VERSION_ENTITIES_HAS_ATTRIBUTION_DAMAGED = 13; -const PacketVersion VERSION_ENTITIES_HAS_ATTRIBUTION = 14; +const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED = 13; +const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14; const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1; #endif // hifi_PacketHeaders_h From be5fdbf2175afc894166c1d12d1a559706519f94 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Fri, 27 Mar 2015 13:36:20 -0700 Subject: [PATCH 149/177] enable avatar collisions by default also remove old gravity features --- interface/src/Application.cpp | 11 ---- interface/src/Menu.cpp | 4 +- interface/src/Menu.h | 3 +- interface/src/avatar/MyAvatar.cpp | 50 ++----------------- interface/src/avatar/MyAvatar.h | 11 +--- libraries/avatars/src/AvatarData.h | 12 +---- libraries/physics/src/CharacterController.cpp | 30 ++++++----- libraries/physics/src/CharacterController.h | 1 + libraries/script-engine/src/ScriptEngine.cpp | 4 -- 9 files changed, 27 insertions(+), 99 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8cd36b501f..99777d22bf 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -987,12 +987,6 @@ void Application::keyPressEvent(QKeyEvent* event) { resetSensors(); break; - case Qt::Key_G: - if (isShifted) { - Menu::getInstance()->triggerOption(MenuOption::ObeyEnvironmentalGravity); - } - break; - case Qt::Key_A: if (isShifted) { Menu::getInstance()->triggerOption(MenuOption::Atmosphere); @@ -1165,10 +1159,6 @@ void Application::keyPressEvent(QKeyEvent* event) { break; } - case Qt::Key_Comma: { - _myAvatar->togglePhysicsEnabled(); - } - default: event->ignore(); break; @@ -2192,7 +2182,6 @@ void Application::update(float deltaTime) { { PerformanceTimer perfTimer("physics"); - _myAvatar->preSimulation(); _physicsEngine.stepSimulation(); } diff --git a/interface/src/Menu.cpp b/interface/src/Menu.cpp index 2ec5c12ca0..5867dd29e2 100644 --- a/interface/src/Menu.cpp +++ b/interface/src/Menu.cpp @@ -201,9 +201,7 @@ Menu::Menu() { addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::NamesAboveHeads, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::GlowWhenSpeaking, 0, true); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::BlueSpeechSphere, 0, true); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ObeyEnvironmentalGravity, Qt::SHIFT | Qt::Key_G, false, - avatar, SLOT(updateMotionBehavior())); - addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::StandOnNearbyFloors, 0, true, + addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::EnableCharacterController, 0, true, avatar, SLOT(updateMotionBehavior())); addCheckableActionToQMenuAndActionHash(avatarMenu, MenuOption::ShiftHipsForIdleAnimations, 0, false, avatar, SLOT(updateMotionBehavior())); diff --git a/interface/src/Menu.h b/interface/src/Menu.h index b3d2d548df..a4e644f20f 100644 --- a/interface/src/Menu.h +++ b/interface/src/Menu.h @@ -153,6 +153,7 @@ namespace MenuOption { const QString EchoServerAudio = "Echo Server Audio"; const QString EditEntitiesHelp = "Edit Entities Help..."; const QString Enable3DTVMode = "Enable 3DTV Mode"; + const QString EnableCharacterController = "Enable avatar collisions"; const QString EnableGlowEffect = "Enable Glow Effect (Warning: Poor Oculus Performance)"; const QString EnableVRMode = "Enable VR Mode"; const QString Entities = "Entities"; @@ -185,7 +186,6 @@ namespace MenuOption { const QString MuteAudio = "Mute Microphone"; const QString MuteEnvironment = "Mute Environment"; const QString NoFaceTracking = "None"; - const QString ObeyEnvironmentalGravity = "Obey Environmental Gravity"; const QString OctreeStats = "Entity Statistics"; const QString OffAxisProjection = "Off-Axis Projection"; const QString OnlyDisplayTopTen = "Only Display Top Ten"; @@ -236,7 +236,6 @@ namespace MenuOption { const QString SixenseEnabled = "Enable Hydra Support"; const QString SixenseMouseInput = "Enable Sixense Mouse Input"; const QString SixenseLasers = "Enable Sixense UI Lasers"; - const QString StandOnNearbyFloors = "Stand on nearby floors"; const QString ShiftHipsForIdleAnimations = "Shift hips for idle animations"; const QString Stars = "Stars"; const QString Stats = "Stats"; diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index aa36748f0c..26b777b35b 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -81,7 +81,6 @@ MyAvatar::MyAvatar() : _scriptedMotorTimescale(DEFAULT_SCRIPTED_MOTOR_TIMESCALE), _scriptedMotorFrame(SCRIPTED_MOTOR_CAMERA_FRAME), _motionBehaviors(AVATAR_MOTION_DEFAULTS), - _enablePhysics(false), _characterController(this), _lookAtTargetAvatar(), _shouldRender(true), @@ -101,6 +100,7 @@ MyAvatar::MyAvatar() : // connect to AddressManager signal for location jumps connect(DependencyManager::get<AddressManager>().data(), &AddressManager::locationChangeRequired, this, &MyAvatar::goToLocation); + _characterController.setEnabled(true); } MyAvatar::~MyAvatar() { @@ -147,10 +147,6 @@ void MyAvatar::update(float deltaTime) { head->setAudioLoudness(audio->getLastInputLoudness()); head->setAudioAverageLoudness(audio->getAudioAverageInputLoudness()); - if (_motionBehaviors & AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY) { - setGravity(Application::getInstance()->getEnvironment()->getGravity(getPosition())); - } - simulate(deltaTime); if (_feetTouchFloor) { _skeletonModel.updateStandingFoot(); @@ -480,26 +476,6 @@ void MyAvatar::loadLastRecording() { _player->loadRecording(_recorder->getRecording()); } -void MyAvatar::setLocalGravity(glm::vec3 gravity) { - _motionBehaviors |= AVATAR_MOTION_OBEY_LOCAL_GRAVITY; - // Environmental and Local gravities are incompatible. Since Local is being set here - // the environmental setting must be removed. - _motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY; - setGravity(gravity); -} - -void MyAvatar::setGravity(const glm::vec3& gravity) { - _gravity = gravity; - - // use the gravity to determine the new world up direction, if possible - float gravityLength = glm::length(gravity); - if (gravityLength > EPSILON) { - _worldUpDirection = _gravity / -gravityLength; - } - // NOTE: the else case here it to leave _worldUpDirection unchanged - // so it continues to point opposite to the previous gravity setting. -} - AnimationHandlePointer MyAvatar::addAnimationHandle() { AnimationHandlePointer handle = _skeletonModel.createAnimationHandle(); _animationHandles.append(handle); @@ -1276,7 +1252,7 @@ void MyAvatar::updatePosition(float deltaTime) { speed = MAX_AVATAR_SPEED; } - if (speed > MIN_AVATAR_SPEED && !isPhysicsEnabled()) { + if (speed > MIN_AVATAR_SPEED && !_characterController.isEnabled()) { // update position ourselves applyPositionDelta(deltaTime * _velocity); measureMotionDerivatives(deltaTime); @@ -1402,23 +1378,6 @@ void MyAvatar::goToLocation(const glm::vec3& newPosition, void MyAvatar::updateMotionBehavior() { Menu* menu = Menu::getInstance(); - if (menu->isOptionChecked(MenuOption::ObeyEnvironmentalGravity)) { - _motionBehaviors |= AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY; - // Environmental and Local gravities are incompatible. Environmental setting trumps local. - _motionBehaviors &= ~AVATAR_MOTION_OBEY_LOCAL_GRAVITY; - } else { - _motionBehaviors &= ~AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY; - } - if (! (_motionBehaviors & (AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | AVATAR_MOTION_OBEY_LOCAL_GRAVITY))) { - setGravity(glm::vec3(0.0f)); - } - if (menu->isOptionChecked(MenuOption::StandOnNearbyFloors)) { - _motionBehaviors |= AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; - // standing on floors requires collision with voxels - // TODO: determine what to do with this now that voxels are gone - } else { - _motionBehaviors &= ~AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; - } if (menu->isOptionChecked(MenuOption::KeyboardMotorControl)) { _motionBehaviors |= AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED; } else { @@ -1429,6 +1388,7 @@ void MyAvatar::updateMotionBehavior() { } else { _motionBehaviors &= ~AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; } + _characterController.setEnabled(menu->isOptionChecked(MenuOption::EnableCharacterController)); _feetTouchFloor = menu->isOptionChecked(MenuOption::ShiftHipsForIdleAnimations); } @@ -1487,10 +1447,6 @@ glm::vec3 MyAvatar::getLaserPointerTipPosition(const PalmData* palm) { return palm->getPosition(); } -void MyAvatar::preSimulation() { - _characterController.setEnabled(_enablePhysics); -} - void MyAvatar::clearDriveKeys() { for (int i = 0; i < MAX_DRIVE_KEYS; ++i) { _driveKeys[i] = 0.0f; diff --git a/interface/src/avatar/MyAvatar.h b/interface/src/avatar/MyAvatar.h index 320a3179bc..99c0bdb5df 100644 --- a/interface/src/avatar/MyAvatar.h +++ b/interface/src/avatar/MyAvatar.h @@ -25,7 +25,7 @@ class MyAvatar : public Avatar { Q_PROPERTY(glm::vec3 motorVelocity READ getScriptedMotorVelocity WRITE setScriptedMotorVelocity) Q_PROPERTY(float motorTimescale READ getScriptedMotorTimescale WRITE setScriptedMotorTimescale) Q_PROPERTY(QString motorReferenceFrame READ getScriptedMotorFrame WRITE setScriptedMotorFrame) - Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setLocalGravity) + //TODO: make gravity feature work Q_PROPERTY(glm::vec3 gravity READ getGravity WRITE setGravity) public: MyAvatar(); @@ -44,13 +44,11 @@ public: // setters void setLeanScale(float scale) { _leanScale = scale; } - void setLocalGravity(glm::vec3 gravity); void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; } void setRealWorldFieldOfView(float realWorldFov) { _realWorldFieldOfView.set(realWorldFov); } // getters float getLeanScale() const { return _leanScale; } - glm::vec3 getGravity() const { return _gravity; } Q_INVOKABLE glm::vec3 getDefaultEyePosition() const; bool getShouldRenderLocally() const { return _shouldRender; } float getRealWorldFieldOfView() { return _realWorldFieldOfView.get(); } @@ -148,11 +146,6 @@ public: const RecorderPointer getRecorder() const { return _recorder; } const PlayerPointer getPlayer() const { return _player; } - - void togglePhysicsEnabled() { _enablePhysics = !_enablePhysics; } - bool isPhysicsEnabled() { return _enablePhysics; } - void setPhysicsEnabled(bool enablePhysics) { _enablePhysics = enablePhysics; } - void preSimulation(); public slots: void increaseSize(); @@ -209,7 +202,6 @@ private: int _scriptedMotorFrame; quint32 _motionBehaviors; - bool _enablePhysics; CharacterController _characterController; QWeakPointer<AvatarData> _lookAtTargetAvatar; @@ -236,7 +228,6 @@ private: void updatePosition(float deltaTime); void updateCollisionSound(const glm::vec3& penetration, float deltaTime, float frequency); void maybeUpdateBillboard(); - void setGravity(const glm::vec3& gravity); }; #endif // hifi_MyAvatar_h diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a2feb98798..2bbd2ee386 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -61,21 +61,13 @@ typedef unsigned long long quint64; const quint32 AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED = 1U << 0; const quint32 AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED = 1U << 1; -const quint32 AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY = 1U << 2; -const quint32 AVATAR_MOTION_OBEY_LOCAL_GRAVITY = 1U << 3; -const quint32 AVATAR_MOTION_STAND_ON_NEARBY_FLOORS = 1U << 4; - const quint32 AVATAR_MOTION_DEFAULTS = AVATAR_MOTION_KEYBOARD_MOTOR_ENABLED | - AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED | - AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; + AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; // these bits will be expanded as features are exposed const quint32 AVATAR_MOTION_SCRIPTABLE_BITS = - AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED | - AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY | - AVATAR_MOTION_OBEY_LOCAL_GRAVITY | - AVATAR_MOTION_STAND_ON_NEARBY_FLOORS; + AVATAR_MOTION_SCRIPTED_MOTOR_ENABLED; // Bitset of state flags - we store the key state, hand state, faceshift, chat circling, and existance of diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index aa0d109732..40b9076a6a 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -217,9 +217,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { assert(avatarData); _avatarData = avatarData; - // cache the "PhysicsEnabled" state of _avatarData _enabled = false; - _ghostObject = NULL; _convexShape = NULL; @@ -730,10 +728,12 @@ void CharacterController::setLocalBoundingBox(const glm::vec3& corner, const glm if (radiusDelta < FLT_EPSILON && heightDelta < FLT_EPSILON) { // shape hasn't changed --> nothing to do } else { - // we always need to: REMOVE when UPDATE_SHAPE, to avoid deleting shapes out from under the PhysicsEngine - _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION - | PENDING_FLAG_UPDATE_SHAPE; - // but only need to ADD back when we happen to be enabled + if (_dynamicsWorld) { + // must REMOVE from world prior to shape update + _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + } + _pendingFlags |= PENDING_FLAG_UPDATE_SHAPE; + // only need to ADD back when we happen to be enabled if (_enabled) { _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; } @@ -759,9 +759,9 @@ void CharacterController::setEnabled(bool enabled) { _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION; _isHovering = true; } else { - // Always set REMOVE bit when going disabled, and we always clear the ADD bit just in case - // it was previously set by something else (e.g. an UPDATE_SHAPE event). - _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + if (_dynamicsWorld) { + _pendingFlags |= PENDING_FLAG_REMOVE_FROM_SIMULATION; + } _pendingFlags &= ~ PENDING_FLAG_ADD_TO_SIMULATION; _isOnGround = false; } @@ -777,17 +777,23 @@ void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { } _dynamicsWorld = world; if (_dynamicsWorld) { - _pendingFlags &= ~ (PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_JUMP); + _pendingFlags &= ~ PENDING_FLAG_JUMP; _dynamicsWorld->addCollisionObject(getGhostObject(), btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); _dynamicsWorld->addAction(this); reset(_dynamicsWorld); + } + } + if (_dynamicsWorld) { + if (_pendingFlags & PENDING_FLAG_UPDATE_SHAPE) { + // shouldn't fall in here, but if we do make sure both ADD and REMOVE bits are still set + _pendingFlags |= PENDING_FLAG_ADD_TO_SIMULATION | PENDING_FLAG_REMOVE_FROM_SIMULATION; } else { - _pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION; + _pendingFlags &= ~PENDING_FLAG_ADD_TO_SIMULATION; } } else { - _pendingFlags &= ~ (PENDING_FLAG_REMOVE_FROM_SIMULATION | PENDING_FLAG_ADD_TO_SIMULATION); + _pendingFlags &= ~ PENDING_FLAG_REMOVE_FROM_SIMULATION; } } diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index ec7d9426f4..6751277c83 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -166,6 +166,7 @@ public: bool needsRemoval() const; bool needsAddition() const; void setEnabled(bool enabled); + bool isEnabled() const { return _enabled; } void setDynamicsWorld(btDynamicsWorld* world); void setLocalBoundingBox(const glm::vec3& corner, const glm::vec3& scale); diff --git a/libraries/script-engine/src/ScriptEngine.cpp b/libraries/script-engine/src/ScriptEngine.cpp index 716af1d188..831db73a0a 100644 --- a/libraries/script-engine/src/ScriptEngine.cpp +++ b/libraries/script-engine/src/ScriptEngine.cpp @@ -360,10 +360,6 @@ void ScriptEngine::init() { globalObject().setProperty("TREE_SCALE", newVariant(QVariant(TREE_SCALE))); globalObject().setProperty("COLLISION_GROUP_ENVIRONMENT", newVariant(QVariant(COLLISION_GROUP_ENVIRONMENT))); globalObject().setProperty("COLLISION_GROUP_AVATARS", newVariant(QVariant(COLLISION_GROUP_AVATARS))); - - globalObject().setProperty("AVATAR_MOTION_OBEY_LOCAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_LOCAL_GRAVITY))); - globalObject().setProperty("AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY", newVariant(QVariant(AVATAR_MOTION_OBEY_ENVIRONMENTAL_GRAVITY))); - } QScriptValue ScriptEngine::registerGlobalObject(const QString& name, QObject* object) { From 1bdfa3abb5f9efeb2468d740e5fc0dd633453535 Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Fri, 27 Mar 2015 13:36:22 -0700 Subject: [PATCH 150/177] Update right-click menu to look for marketplaceID --- examples/edit.js | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/examples/edit.js b/examples/edit.js index 2529b617d9..1ea7647a54 100644 --- a/examples/edit.js +++ b/examples/edit.js @@ -718,13 +718,8 @@ function mouseClickEvent(event) { var result = findClickedEntity(event); if (result) { var properties = Entities.getEntityProperties(result.entityID); - var data = {}; - try { - data = JSON.parse(properties.attribution); - } catch (e) { - } - if (data.marketplaceID) { - propertyMenu.marketplaceID = data.marketplaceID; + if (properties.marketplaceID) { + propertyMenu.marketplaceID = properties.marketplaceID; propertyMenu.updateMenuItemText(showMenuItem, "Show in Marketplace"); } else { propertyMenu.marketplaceID = null; From ed62356f65bb5e42809ad28921cd37ef7488bb3c Mon Sep 17 00:00:00 2001 From: Ryan Huffman <ryanhuffman@gmail.com> Date: Fri, 27 Mar 2015 13:36:56 -0700 Subject: [PATCH 151/177] Remove attribution field from edit properties window --- examples/html/entityProperties.html | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/examples/html/entityProperties.html b/examples/html/entityProperties.html index dc632d76fd..596bf5c9d5 100644 --- a/examples/html/entityProperties.html +++ b/examples/html/entityProperties.html @@ -140,7 +140,6 @@ var elLifetime = document.getElementById("property-lifetime"); var elScriptURL = document.getElementById("property-script-url"); var elUserData = document.getElementById("property-user-data"); - var elAttribution = document.getElementById("property-attribution"); var elBoxSections = document.querySelectorAll(".box-section"); var elBoxColorRed = document.getElementById("property-box-red"); @@ -264,7 +263,6 @@ elLifetime.value = properties.lifetime; elScriptURL.value = properties.script; elUserData.value = properties.userData; - elAttribution.value = properties.attribution; if (properties.type != "Box") { for (var i = 0; i < elBoxSections.length; i++) { @@ -395,7 +393,6 @@ elLifetime.addEventListener('change', createEmitNumberPropertyUpdateFunction('lifetime')); elScriptURL.addEventListener('change', createEmitTextPropertyUpdateFunction('script')); elUserData.addEventListener('change', createEmitTextPropertyUpdateFunction('userData')); - elAttribution.addEventListener('change', createEmitTextPropertyUpdateFunction('attribution')); var boxColorChangeFunction = createEmitColorPropertyUpdateFunction( 'color', elBoxColorRed, elBoxColorGreen, elBoxColorBlue); @@ -630,13 +627,6 @@ </div> </div> - <div class="property"> - <div class="label">Attribution</div> - <div class="value"> - <textarea id="property-attribution"></textarea> - </div> - </div> - <div class="box-section property"> <div class="label">Color</div> From bee8c0e2377f5e3a9a06f538cb894084a2ccf189 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Fri, 27 Mar 2015 13:56:03 -0700 Subject: [PATCH 152/177] "hover" if the "jump" key is held down long enough --- libraries/physics/src/CharacterController.cpp | 15 +++++++++++++++ libraries/physics/src/CharacterController.h | 1 + 2 files changed, 16 insertions(+) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 40b9076a6a..09c6b5599f 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -232,6 +232,7 @@ CharacterController::CharacterController(AvatarData* avatarData) { _isOnGround = false; _isJumping = false; _isHovering = true; + _jumpToHoverStart = 0; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; _pendingFlags = 0; @@ -678,6 +679,20 @@ bool CharacterController::canJump() const { void CharacterController::jump() { _pendingFlags |= PENDING_FLAG_JUMP; + + // check for case where user is holding down "jump" key... + // we'll eventually tansition to "hover" + if (!_isHovering) { + if (!_isJumping) { + _jumpToHoverStart = usecTimestampNow(); + } else { + quint64 now = usecTimestampNow(); + const quint64 JUMP_TO_HOVER_PERIOD = USECS_PER_SECOND; + if (now - _jumpToHoverStart < JUMP_TO_HOVER_PERIOD) { + _isHovering = true; + } + } + } } void CharacterController::setGravity(btScalar gravity) { diff --git a/libraries/physics/src/CharacterController.h b/libraries/physics/src/CharacterController.h index 6751277c83..eeaa5836dd 100644 --- a/libraries/physics/src/CharacterController.h +++ b/libraries/physics/src/CharacterController.h @@ -85,6 +85,7 @@ protected: bool _isOnGround; bool _isJumping; bool _isHovering; + quint64 _jumpToHoverStart; btScalar _velocityTimeInterval; btScalar _stepDt; uint32_t _pendingFlags; From 1ee797efa4f1258b4567b81a6b7ec8b90fed03ac Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Fri, 27 Mar 2015 13:59:52 -0700 Subject: [PATCH 153/177] Fix authorization of API calls in XMLHttpRequest --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index 8755527860..f408e2001d 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -207,7 +207,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a notImplemented(); } } else { - if (url.toLower().left(33) == "https://metaverse.highfidelity.com/api/") { + if (url.toLower().left(39) == "https://metaverse.highfidelity.com/api/") { AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.hasValidAccessToken()) { From cfa30594cc5187889968d79916c06ca6a902dddd Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Fri, 27 Mar 2015 14:24:36 -0700 Subject: [PATCH 154/177] make obj reader handle faces with more than 4 vertices --- libraries/fbx/src/OBJReader.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libraries/fbx/src/OBJReader.cpp b/libraries/fbx/src/OBJReader.cpp index 0aaf8772a2..db2733f27b 100644 --- a/libraries/fbx/src/OBJReader.cpp +++ b/libraries/fbx/src/OBJReader.cpp @@ -249,7 +249,20 @@ bool parseOBJGroup(OBJTokenizer &tokenizer, const QVariantHash& mapping, } else if (indices.count() == 4) { meshPart.quadIndices << indices; } else { - qDebug() << "no support for more than 4 vertices on a face in OBJ files"; + // some obj writers (maya) will write a face with lots of points. + for (int i = 1; i < indices.count() - 1; i++) { + // break the face into triangles + meshPart.triangleIndices.append(indices[0]); + meshPart.triangleIndices.append(indices[i]); + meshPart.triangleIndices.append(indices[i+1]); + } + if (indices.count() == normalIndices.count()) { + for (int i = 1; i < normalIndices.count() - 1; i++) { + faceNormalIndexes.append(normalIndices[0]); + faceNormalIndexes.append(normalIndices[i]); + faceNormalIndexes.append(normalIndices[i+1]); + } + } } } else { // something we don't (yet) care about From 0fd17b3303865a587b2f251ec20594e03eb59040 Mon Sep 17 00:00:00 2001 From: Grayson Stebbins <g@graysonstebbins.com> Date: Fri, 27 Mar 2015 14:40:16 -0700 Subject: [PATCH 155/177] editEntities.js --> edit.js --- interface/resources/html/interface-welcome.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/resources/html/interface-welcome.html b/interface/resources/html/interface-welcome.html index ed905eb392..26ae6ff5c0 100644 --- a/interface/resources/html/interface-welcome.html +++ b/interface/resources/html/interface-welcome.html @@ -138,7 +138,7 @@ <h3>Import models</h3> <img class="grid-img" src="img/models.png" alt"Import models"></img> <p> - Use the editEntitles.js script to<br> + Use the <strong>edit.js</strong> script to<br> add FBX models in-world. You<br> can use grids and fine tune<br> placement-related parameters<br> From 1821683453f8bab2f83850aa71154ba062af0c1c Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Fri, 27 Mar 2015 14:44:35 -0700 Subject: [PATCH 156/177] fix bug in default avatars --- libraries/avatars/src/AvatarData.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/avatars/src/AvatarData.h b/libraries/avatars/src/AvatarData.h index a2feb98798..20366e590f 100644 --- a/libraries/avatars/src/AvatarData.h +++ b/libraries/avatars/src/AvatarData.h @@ -365,8 +365,8 @@ protected: HeadData* _headData; HandData* _handData; - QUrl _faceModelURL = DEFAULT_HEAD_MODEL_URL; - QUrl _skeletonModelURL = DEFAULT_BODY_MODEL_URL; + QUrl _faceModelURL; // These need to be empty so that on first time setting them they will not short circuit + QUrl _skeletonModelURL; // These need to be empty so that on first time setting them they will not short circuit QVector<AttachmentData> _attachmentData; QString _displayName; From c45676041941ae3e2c6985f10f895a3df5155ff6 Mon Sep 17 00:00:00 2001 From: David Rowe <david@ctrlaltstudio.com> Date: Fri, 27 Mar 2015 15:24:55 -0700 Subject: [PATCH 157/177] Extract API URL into a const --- libraries/script-engine/src/XMLHttpRequestClass.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/script-engine/src/XMLHttpRequestClass.cpp b/libraries/script-engine/src/XMLHttpRequestClass.cpp index f408e2001d..3054472a3c 100644 --- a/libraries/script-engine/src/XMLHttpRequestClass.cpp +++ b/libraries/script-engine/src/XMLHttpRequestClass.cpp @@ -22,6 +22,8 @@ #include "XMLHttpRequestClass.h" #include "ScriptEngine.h" +const QString METAVERSE_API_URL = "https://metaverse.highfidelity.com/api/"; + Q_DECLARE_METATYPE(QByteArray*) XMLHttpRequestClass::XMLHttpRequestClass(QScriptEngine* engine) : @@ -207,7 +209,7 @@ void XMLHttpRequestClass::open(const QString& method, const QString& url, bool a notImplemented(); } } else { - if (url.toLower().left(39) == "https://metaverse.highfidelity.com/api/") { + if (url.toLower().left(METAVERSE_API_URL.length()) == METAVERSE_API_URL) { AccountManager& accountManager = AccountManager::getInstance(); if (accountManager.hasValidAccessToken()) { From 90f51e7d4c5d18f1df7c9c4cc07150f74ec3fc49 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Fri, 27 Mar 2015 16:15:54 -0700 Subject: [PATCH 158/177] print a warning when ShapeManager is skipping over a too-large or too-small shape --- libraries/physics/src/ShapeManager.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 9b3b2f6d35..2a8705561d 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -9,6 +9,8 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +#include <QDebug> + #include <glm/gtx/norm.hpp> #include "ShapeInfoUtil.h" @@ -35,6 +37,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e4f; // 100 m cube if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) { + qDebug() << "ShapeManager::getShape -- not making shape due to size" << diagonal; return NULL; } DoubleHashKey key = info.getHash(); From a765b4c8a5858a030e63bc8984f307324b40390a Mon Sep 17 00:00:00 2001 From: ZappoMan <bradh@konamoxt.com> Date: Fri, 27 Mar 2015 18:56:55 -0700 Subject: [PATCH 159/177] fix to preload getting called when you change a script --- libraries/entities/src/EntityTree.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/entities/src/EntityTree.cpp b/libraries/entities/src/EntityTree.cpp index 3ccff46a04..266aa2bdce 100644 --- a/libraries/entities/src/EntityTree.cpp +++ b/libraries/entities/src/EntityTree.cpp @@ -148,6 +148,7 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro } } } else { + QString entityScriptBefore = entity->getScript(); uint32_t preFlags = entity->getDirtyFlags(); UpdateEntityOperator theOperator(this, containingElement, entity, properties); recurseTreeWithOperator(&theOperator); @@ -166,6 +167,11 @@ bool EntityTree::updateEntityWithElement(EntityItem* entity, const EntityItemPro entity->clearDirtyFlags(); } } + + QString entityScriptAfter = entity->getScript(); + if (entityScriptBefore != entityScriptAfter) { + emitEntityScriptChanging(entity->getEntityItemID()); // the entity script has changed + } } // TODO: this final containingElement check should eventually be removed (or wrapped in an #ifdef DEBUG). From 9428857194d6c0c7781f7709f607b0510d7a8939 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 28 Mar 2015 17:10:16 -0700 Subject: [PATCH 160/177] quiet compiler, remove extra-assignment/typo --- assignment-client/src/avatars/AvatarMixer.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/assignment-client/src/avatars/AvatarMixer.cpp b/assignment-client/src/avatars/AvatarMixer.cpp index 176fd51eea..dae6af3fc5 100644 --- a/assignment-client/src/avatars/AvatarMixer.cpp +++ b/assignment-client/src/avatars/AvatarMixer.cpp @@ -149,7 +149,8 @@ void AvatarMixer::broadcastAvatarData() { // about a given otherNode to this node // FIXME does this mean we should sort the othernodes by distance before iterating // over them? - float outputBandwidth = node->getOutboundBandwidth(); + // float outputBandwidth = + node->getOutboundBandwidth(); // this is an AGENT we have received head data from // send back a packet with other active node data to this node @@ -169,7 +170,7 @@ void AvatarMixer::broadcastAvatarData() { return true; }, [&](const SharedNodePointer& otherNode) { - AvatarMixerClientData* otherNodeData = otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData()); + AvatarMixerClientData* otherNodeData = reinterpret_cast<AvatarMixerClientData*>(otherNode->getLinkedData()); MutexTryLocker lock(otherNodeData->getMutex()); if (!lock.isLocked()) { return; From 986bc71e938f8843a07bc6d8851ab648d9bb33a1 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 28 Mar 2015 17:10:26 -0700 Subject: [PATCH 161/177] quiet compiler --- interface/src/scripting/ControllerScriptingInterface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/scripting/ControllerScriptingInterface.cpp b/interface/src/scripting/ControllerScriptingInterface.cpp index 35c24346d2..7d6012c880 100644 --- a/interface/src/scripting/ControllerScriptingInterface.cpp +++ b/interface/src/scripting/ControllerScriptingInterface.cpp @@ -353,7 +353,7 @@ void InputController::update() { // TODO for now the InputController is only supporting a JointTracker from a MotionTracker MotionTracker* motionTracker = dynamic_cast< MotionTracker*> (DeviceTracker::getDevice(_deviceTrackerId)); if (motionTracker) { - if (_subTrackerId < motionTracker->numJointTrackers()) { + if ((int)_subTrackerId < motionTracker->numJointTrackers()) { const MotionTracker::JointTracker* joint = motionTracker->getJointTracker(_subTrackerId); if (joint->isActive()) { From fc1e45fc58a82c42eeb4460d5ecde11e62636419 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 28 Mar 2015 17:10:46 -0700 Subject: [PATCH 162/177] valgrind says this is used before it's initialized --- interface/src/ui/ApplicationOverlay.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index d9adaf02e6..633eafc202 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -139,6 +139,7 @@ ApplicationOverlay::ApplicationOverlay() : _magnifier(true), _alpha(1.0f), _oculusUIRadius(1.0f), + _trailingAudioLoudness(0.0f), _crosshairTexture(0), _previousBorderWidth(-1), _previousBorderHeight(-1), From faa3ed6c292ec8b6dc682f929c49c2ead6021a11 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 28 Mar 2015 17:11:23 -0700 Subject: [PATCH 163/177] valgrind wants [] --- libraries/audio/src/AudioBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioBuffer.h b/libraries/audio/src/AudioBuffer.h index 4849289743..621b7b1b8c 100644 --- a/libraries/audio/src/AudioBuffer.h +++ b/libraries/audio/src/AudioBuffer.h @@ -90,7 +90,7 @@ void AudioFrameBuffer< T >::deallocateFrames() { for (uint32_t i = 0; i < _channelCountMax; ++i) { delete _frameBuffer[i]; } - delete _frameBuffer; + delete[] _frameBuffer; } _frameBuffer = NULL; } From 78b46cff2be0bfe3e722489a7f9448a384dbbd1a Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 28 Mar 2015 17:11:36 -0700 Subject: [PATCH 164/177] quiet compiler --- libraries/audio/src/AudioFilterBank.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioFilterBank.h b/libraries/audio/src/AudioFilterBank.h index 723fa6b270..7b3b45f56b 100644 --- a/libraries/audio/src/AudioFilterBank.h +++ b/libraries/audio/src/AudioFilterBank.h @@ -88,7 +88,7 @@ public: } void loadProfile(int profileIndex) { - if (profileIndex >= 0 && profileIndex < _profileCount) { + if (profileIndex >= 0 && profileIndex < (int)_profileCount) { for (uint32_t i = 0; i < _filterCount; ++i) { FilterParameter p = _profiles[profileIndex][i]; From 96bfc5339182177f7a3fcf7f19b056adba4a022e Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 28 Mar 2015 17:11:56 -0700 Subject: [PATCH 165/177] prototype has no code and isn't used --- libraries/entities/src/EntityTree.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libraries/entities/src/EntityTree.h b/libraries/entities/src/EntityTree.h index 8536e74e9a..29fecc88b4 100644 --- a/libraries/entities/src/EntityTree.h +++ b/libraries/entities/src/EntityTree.h @@ -95,7 +95,6 @@ public: void deleteEntity(const EntityItemID& entityID, bool force = false, bool ignoreWarnings = false); void deleteEntities(QSet<EntityItemID> entityIDs, bool force = false, bool ignoreWarnings = false); - void removeEntityFromSimulation(EntityItem* entity); /// \param position point of query in world-frame (meters) /// \param targetRadius radius of query (meters) From 1e166eef0f647e7b9a0f451cc7c1d86023fc467e Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 28 Mar 2015 17:12:55 -0700 Subject: [PATCH 166/177] valgrind says _ghostObject is used before it's initialized --- libraries/physics/src/CharacterController.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 09c6b5599f..ba0cfb3c80 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -235,7 +235,9 @@ CharacterController::CharacterController(AvatarData* avatarData) { _jumpToHoverStart = 0; setMaxSlope(btRadians(45.0f)); _lastStepUp = 0.0f; - _pendingFlags = 0; + + _pendingFlags = PENDING_FLAG_UPDATE_SHAPE; + updateShapeIfNecessary(); } CharacterController::~CharacterController() { From a47ae9212b6406f7cb8abb7a14bf9eaa146b388a Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 28 Mar 2015 17:13:31 -0700 Subject: [PATCH 167/177] quiet compiler --- libraries/render-utils/src/DeferredLightingEffect.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index 13bf947d71..ffa84adbdf 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -134,7 +134,7 @@ void DeferredLightingEffect::addPointLight(const glm::vec3& position, float radi void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radius, const glm::vec3& color, float intensity, const glm::quat& orientation, float exponent, float cutoff) { - int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size(); + unsigned int lightID = _pointLights.size() + _spotLights.size() + _globalLights.size(); if (lightID >= _allocatedLights.size()) { _allocatedLights.push_back(model::LightPointer(new model::Light())); } From 43c3c621a8e9db8359a4a3c522de5275b53f3243 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sat, 28 Mar 2015 17:14:39 -0700 Subject: [PATCH 168/177] I can't set VHACD_ROOT_DIR and run cmake with this line. --- tools/CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/CMakeLists.txt b/tools/CMakeLists.txt index 5c7c306a62..ba2938aaa6 100644 --- a/tools/CMakeLists.txt +++ b/tools/CMakeLists.txt @@ -8,5 +8,5 @@ set_target_properties(scribe PROPERTIES FOLDER "Tools") find_package(VHACD) if(VHACD_FOUND) add_subdirectory(vhacd) -set_target_properties(vhacd PROPERTIES FOLDER "Tools") +# set_target_properties(vhacd PROPERTIES FOLDER "Tools") endif() From 2dd33e5334d771c0d8cbdf361a41d086c87e3ae4 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sun, 29 Mar 2015 05:40:16 -0700 Subject: [PATCH 169/177] don't include build-ext in tags --- tools/refresh-tags.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/refresh-tags.sh b/tools/refresh-tags.sh index d3157fa179..e8040dac81 100755 --- a/tools/refresh-tags.sh +++ b/tools/refresh-tags.sh @@ -2,13 +2,13 @@ rm -f TAGS -find . -name *.h -print | while read I +find . -name *.h -print | grep -v build-ext |while read I do etags --append "$I" done -find . -name *.cpp -print | grep -v 'moc_' | while read I +find . -name *.cpp -print | grep -v 'moc_' | grep -v build-ext | while read I do etags --append "$I" done From 26230cf493f35cfe53b39942eee8f23b0a17f003 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sun, 29 Mar 2015 05:40:39 -0700 Subject: [PATCH 170/177] uninitialized variable (quiet valgrind) --- libraries/shared/src/SimpleMovingAverage.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/shared/src/SimpleMovingAverage.cpp b/libraries/shared/src/SimpleMovingAverage.cpp index 64198d2a06..90a9509c91 100644 --- a/libraries/shared/src/SimpleMovingAverage.cpp +++ b/libraries/shared/src/SimpleMovingAverage.cpp @@ -14,6 +14,7 @@ SimpleMovingAverage::SimpleMovingAverage(int numSamplesToAverage) : _numSamples(0), + _lastEventTimestamp(0), _average(0.0f), _eventDeltaAverage(0.0f), WEIGHTING(1.0f / numSamplesToAverage), From 4bf86bb824a800ad31f9be54b3a8b3322b1b535a Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Sun, 29 Mar 2015 17:59:57 -0700 Subject: [PATCH 171/177] another [] needed after delete --- libraries/audio/src/AudioBuffer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/audio/src/AudioBuffer.h b/libraries/audio/src/AudioBuffer.h index 621b7b1b8c..d2f7c50c91 100644 --- a/libraries/audio/src/AudioBuffer.h +++ b/libraries/audio/src/AudioBuffer.h @@ -88,7 +88,7 @@ template< typename T > void AudioFrameBuffer< T >::deallocateFrames() { if (_frameBuffer) { for (uint32_t i = 0; i < _channelCountMax; ++i) { - delete _frameBuffer[i]; + delete[] _frameBuffer[i]; } delete[] _frameBuffer; } From 7de15cda87b779606c71cc4c7fe4d5b7a22e8a04 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Mon, 30 Mar 2015 09:30:13 -0700 Subject: [PATCH 172/177] quiet compiler --- interface/src/Application.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 99777d22bf..e9ea5bebf8 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -3125,7 +3125,7 @@ void Application::renderRearViewMirror(const QRect& region, bool billboard) { int viewport[4]; glGetIntegerv(GL_VIEWPORT, viewport); - bool eyeRelativeCamera = false; + // bool eyeRelativeCamera = false; if (billboard) { _mirrorCamera.setFieldOfView(BILLBOARD_FIELD_OF_VIEW); // degees _mirrorCamera.setPosition(_myAvatar->getPosition() + From 7137b4137554605cd27d26faca9e6da8ba4f210b Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Mon, 30 Mar 2015 09:30:37 -0700 Subject: [PATCH 173/177] free these so it's easier to see other leaks in valgrind --- libraries/physics/src/PhysicsEngine.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libraries/physics/src/PhysicsEngine.cpp b/libraries/physics/src/PhysicsEngine.cpp index 9ca718e19a..f7dc90e72f 100644 --- a/libraries/physics/src/PhysicsEngine.cpp +++ b/libraries/physics/src/PhysicsEngine.cpp @@ -29,6 +29,12 @@ PhysicsEngine::PhysicsEngine(const glm::vec3& offset) PhysicsEngine::~PhysicsEngine() { // TODO: delete engine components... if we ever plan to create more than one instance + delete _collisionConfig; + delete _collisionDispatcher; + delete _broadphaseFilter; + delete _constraintSolver; + delete _dynamicsWorld; + // delete _ghostPairCallback; } // begin EntitySimulation overrides From adf076a63077fed8168233629cefc20ebe3c0322 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Mon, 30 Mar 2015 09:56:30 -0700 Subject: [PATCH 174/177] optimizations when creating convex hull shapes --- libraries/physics/src/ShapeInfoUtil.cpp | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/libraries/physics/src/ShapeInfoUtil.cpp b/libraries/physics/src/ShapeInfoUtil.cpp index 1073fbae3f..8900c5a0dc 100644 --- a/libraries/physics/src/ShapeInfoUtil.cpp +++ b/libraries/physics/src/ShapeInfoUtil.cpp @@ -136,28 +136,32 @@ btCollisionShape* ShapeInfoUtil::createShapeFromInfo(const ShapeInfo& info) { } break; case SHAPE_TYPE_CONVEX_HULL: { - shape = new btConvexHullShape(); + auto hull = new btConvexHullShape(); const QVector<QVector<glm::vec3>>& points = info.getPoints(); foreach (glm::vec3 point, points[0]) { btVector3 btPoint(point[0], point[1], point[2]); - static_cast<btConvexHullShape*>(shape)->addPoint(btPoint); + hull->addPoint(btPoint, false); } + hull->recalcLocalAabb(); + shape = hull; } break; case SHAPE_TYPE_COMPOUND: { - shape = new btCompoundShape(); + auto compound = new btCompoundShape(); const QVector<QVector<glm::vec3>>& points = info.getPoints(); - foreach (QVector<glm::vec3> hullPoints, info.getPoints()) { + btTransform trans; + trans.setIdentity(); + foreach (QVector<glm::vec3> hullPoints, points) { auto hull = new btConvexHullShape(); foreach (glm::vec3 point, hullPoints) { btVector3 btPoint(point[0], point[1], point[2]); - hull->addPoint(btPoint); + hull->addPoint(btPoint, false); } - btTransform trans; - trans.setIdentity(); - static_cast<btCompoundShape*>(shape)->addChildShape (trans, hull); + hull->recalcLocalAabb(); + compound->addChildShape (trans, hull); } + shape = compound; } break; } From da9ceac9ae086287c0c23e6fd2ffc59e6eba3d81 Mon Sep 17 00:00:00 2001 From: Andrew Meadows <andrew@highfidelity.io> Date: Mon, 30 Mar 2015 11:06:02 -0700 Subject: [PATCH 175/177] fix crash for bad avatar body on login --- libraries/physics/src/CharacterController.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/libraries/physics/src/CharacterController.cpp b/libraries/physics/src/CharacterController.cpp index 09c6b5599f..518e49ed81 100644 --- a/libraries/physics/src/CharacterController.cpp +++ b/libraries/physics/src/CharacterController.cpp @@ -786,14 +786,17 @@ void CharacterController::setEnabled(bool enabled) { void CharacterController::setDynamicsWorld(btDynamicsWorld* world) { if (_dynamicsWorld != world) { - if (_dynamicsWorld) { - _dynamicsWorld->removeCollisionObject(getGhostObject()); - _dynamicsWorld->removeAction(this); + if (_dynamicsWorld) { + if (_ghostObject) { + _dynamicsWorld->removeCollisionObject(_ghostObject); + _dynamicsWorld->removeAction(this); + } + _dynamicsWorld = NULL; } - _dynamicsWorld = world; - if (_dynamicsWorld) { + if (world && _ghostObject) { + _dynamicsWorld = world; _pendingFlags &= ~ PENDING_FLAG_JUMP; - _dynamicsWorld->addCollisionObject(getGhostObject(), + _dynamicsWorld->addCollisionObject(_ghostObject, btBroadphaseProxy::CharacterFilter, btBroadphaseProxy::StaticFilter | btBroadphaseProxy::DefaultFilter); _dynamicsWorld->addAction(this); @@ -876,7 +879,7 @@ void CharacterController::preSimulation(btScalar timeStep) { } void CharacterController::postSimulation() { - if (_enabled) { + if (_enabled && _ghostObject) { const btTransform& avatarTransform = _ghostObject->getWorldTransform(); glm::quat rotation = bulletToGLM(avatarTransform.getRotation()); glm::vec3 position = bulletToGLM(avatarTransform.getOrigin()); From 8a5192c1d93af5fa65964dc75963a2967dd6265a Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Mon, 30 Mar 2015 11:22:31 -0700 Subject: [PATCH 176/177] attempt to handle registration point in hull collisions --- libraries/entities-renderer/src/RenderableModelEntityItem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp index 43dbb95b6d..eb6706e27f 100644 --- a/libraries/entities-renderer/src/RenderableModelEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableModelEntityItem.cpp @@ -366,6 +366,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) { // multiply each point by scale before handing the point-set off to the physics engine for (int i = 0; i < _points.size(); i++) { for (int j = 0; j < _points[i].size(); j++) { + // compensate for registraion + _points[i][j] += _model->getOffset(); + // scale so the collision points match the model points _points[i][j] *= scale; } } From e730109c51eea2bd22981cbe7a66be6866ec2b02 Mon Sep 17 00:00:00 2001 From: Seth Alves <seth.alves@gmail.com> Date: Mon, 30 Mar 2015 11:46:48 -0700 Subject: [PATCH 177/177] quiet debuging spew --- libraries/physics/src/ShapeManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/physics/src/ShapeManager.cpp b/libraries/physics/src/ShapeManager.cpp index 2a8705561d..b4d322a4a3 100644 --- a/libraries/physics/src/ShapeManager.cpp +++ b/libraries/physics/src/ShapeManager.cpp @@ -37,7 +37,7 @@ btCollisionShape* ShapeManager::getShape(const ShapeInfo& info) { const float MIN_SHAPE_DIAGONAL_SQUARED = 3.0e-4f; // 1 cm cube const float MAX_SHAPE_DIAGONAL_SQUARED = 3.0e4f; // 100 m cube if (diagonal < MIN_SHAPE_DIAGONAL_SQUARED || diagonal > MAX_SHAPE_DIAGONAL_SQUARED) { - qDebug() << "ShapeManager::getShape -- not making shape due to size" << diagonal; + // qDebug() << "ShapeManager::getShape -- not making shape due to size" << diagonal; return NULL; } DoubleHashKey key = info.getHash();