bool get_hud_matrices(const LLRect& screen_region, LLMatrix4a &proj, LLMatrix4a &model)
{
	if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment())
	{
		F32 zoom_level = gAgentCamera.mHUDCurZoom;
		LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
		
		F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
		proj = gGL.genOrtho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
		proj.getRow<2>().copyComponent<2>(LLVector4a(-0.01f));

		F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect();
		
		F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth();
		F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight();

		proj.applyTranslation_affine(
			clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio),
			clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y),
			0.f);
		proj.applyScale_affine(scale_x, scale_y, 1.f);

		model = OGL_TO_CFR_ROTATION;
		model.applyTranslation_affine(LLVector3(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f));
		model.applyScale_affine(zoom_level);

		return TRUE;
	}
	else
	{
		return FALSE;
	}
}
示例#2
0
	F32 getCollapseFactor()
	{
		if (mOrientation == HORIZONTAL)
		{
			F32 collapse_amt = 
				clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinWidth / (F32)llmax(1, mPanel->getRect().getWidth()));
			return mVisibleAmt * collapse_amt;
		}
		else
		{
			F32 collapse_amt = 
				clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinHeight / (F32)llmax(1, mPanel->getRect().getHeight())));
			return mVisibleAmt * collapse_amt;
		}
	}
F32 LLLayoutPanel::getCollapseFactor(LLLayoutStack::ELayoutOrientation orientation)
{
	if (orientation == LLLayoutStack::HORIZONTAL)
	{
		F32 collapse_amt = 
		clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, (F32)mMinDim / (F32)llmax(1, getRect().getWidth()));
		return mVisibleAmt * collapse_amt;
	}
	else
	{
			F32 collapse_amt = 
			clamp_rescale(mCollapseAmt, 0.f, 1.f, 1.f, llmin(1.f, (F32)mMinDim / (F32)llmax(1, getRect().getHeight())));
			return mVisibleAmt * collapse_amt;
	}
}
/*virtual*/
void LLPanelNearByMedia::draw()
{
	// keep bottom of panel on screen
	LLRect screen_rect = calcScreenRect();
	if (screen_rect.mBottom < 0)
	{
		LLRect new_rect = getRect();
		new_rect.mBottom += 0 - screen_rect.mBottom;
		setShape(new_rect);
	}

	refreshList();
	updateControls();
	

	F32 alpha = mHoverTimer.getStarted() 
		? clamp_rescale(mHoverTimer.getElapsedTimeF32(), AUTO_CLOSE_FADE_TIME_START, AUTO_CLOSE_FADE_TIME_END, 1.f, 0.f)
		: 1.0f;

	LLViewDrawContext context(alpha);

	LLPanel::draw();

	if (alpha == 0.f)
	{
		setVisible(false);
	}
}
示例#5
0
// virtual
void LLInspect::draw()
{
	static LLCachedControl<F32> FADE_TIME(*LLUI::sSettingGroups["config"], "InspectorFadeTime", 1.f);
	static LLCachedControl<F32> STAY_TIME(*LLUI::sSettingGroups["config"], "InspectorShowTime", 1.f);
	if (mOpenTimer.getStarted())
	{
		LLFloater::draw();
		if (mOpenTimer.getElapsedTimeF32() > STAY_TIME)
		{
			mOpenTimer.stop();
			mCloseTimer.start();
		}

	}
	else if (mCloseTimer.getStarted())
	{
		F32 alpha = clamp_rescale(mCloseTimer.getElapsedTimeF32(), 0.f, FADE_TIME, 1.f, 0.f);
		LLViewDrawContext context(alpha);
		LLFloater::draw();
		if (mCloseTimer.getElapsedTimeF32() > FADE_TIME)
		{
			closeFloater(false);
		}
	}
	else
	{
		LLFloater::draw();
	}
}
BOOL setup_hud_matrices(const LLRect& screen_region)
{
	LLVOAvatar* my_avatarp = gAgent.getAvatarObject();
	if (my_avatarp && my_avatarp->hasHUDAttachment())
	{
		F32 zoom_level = gAgent.mHUDCurZoom;
		LLBBox hud_bbox = my_avatarp->getHUDBBox();

		// set up transform to keep HUD objects in front of camera
		glMatrixMode(GL_PROJECTION);
		F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
		glh::matrix4f proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
		proj.element(2,2) = -0.01f;

		F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect();

		glh::matrix4f mat;
		F32 scale_x = (F32)gViewerWindow->getWindowWidth() / (F32)screen_region.getWidth();
		F32 scale_y = (F32)gViewerWindow->getWindowHeight() / (F32)screen_region.getHeight();
		mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f));
		mat.set_translate(
			glh::vec3f(clamp_rescale((F32)screen_region.getCenterX(), 0.f, (F32)gViewerWindow->getWindowWidth(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio),
						clamp_rescale((F32)screen_region.getCenterY(), 0.f, (F32)gViewerWindow->getWindowHeight(), 0.5f * scale_y, -0.5f * scale_y),
						0.f));
		proj *= mat;

		glLoadMatrixf(proj.m);
		glh_set_current_projection(proj);

		glMatrixMode(GL_MODELVIEW);
		glh::matrix4f model((GLfloat*) OGL_TO_CFR_ROTATION);
		
		mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level));
		mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f));

		model *= mat;
		glLoadMatrixf(model.m);
		glh_set_current_modelview(model);

		return TRUE;
	}
	else
	{
		return FALSE;
	}
}
void LLProgressView::draw()
{
	static LLTimer timer;

	if (mFadeFromLoginTimer.getStarted())
	{
		F32 alpha = clamp_rescale(mFadeFromLoginTimer.getElapsedTimeF32(), 0.f, FADE_TO_WORLD_TIME, 0.f, 1.f);
		LLViewDrawContext context(alpha);

		drawStartTexture(alpha);
		
		LLPanel::draw();
		return;
	}

	// handle fade out to world view when we're asked to
	if (mFadeToWorldTimer.getStarted())
	{
		// draw fading panel
		F32 alpha = clamp_rescale(mFadeToWorldTimer.getElapsedTimeF32(), 0.f, FADE_TO_WORLD_TIME, 1.f, 0.f);
		LLViewDrawContext context(alpha);
				
		drawStartTexture(alpha);
		LLPanel::draw();

		// faded out completely - remove panel and reveal world
		if (mFadeToWorldTimer.getElapsedTimeF32() > FADE_TO_WORLD_TIME )
		{
			mFadeToWorldTimer.stop();

			// Fade is complete, release focus
			gFocusMgr.releaseFocusIfNeeded( this );

			// turn off panel that hosts intro so we see the world
			setVisible(FALSE);

			gStartTexture = NULL;
		}
		return;
	}

	drawStartTexture(1.0f);
	// draw children
	LLPanel::draw();
}
示例#8
0
void LLProgressView::draw()
{
	static LLTimer timer;

	// Paint bitmap if we've got one
	glPushMatrix();	
	if (gStartTexture)
	{
		LLGLSUIDefault gls_ui;
		gGL.getTexUnit(0)->bind(gStartTexture.get());
		gGL.color4f(1.f, 1.f, 1.f, mFadeTimer.getStarted() ? clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, FADE_IN_TIME, 1.f, 0.f) : 1.f);
		F32 image_aspect = (F32)gStartImageWidth / (F32)gStartImageHeight;
		S32 width = getRect().getWidth();
		S32 height = getRect().getHeight();
		F32 view_aspect = (F32)width / (F32)height;
		// stretch image to maintain aspect ratio
		if (image_aspect > view_aspect)
		{
			glTranslatef(-0.5f * (image_aspect / view_aspect - 1.f) * width, 0.f, 0.f);
			glScalef(image_aspect / view_aspect, 1.f, 1.f);
		}
		else
		{
			glTranslatef(0.f, -0.5f * (view_aspect / image_aspect - 1.f) * height, 0.f);
			glScalef(1.f, view_aspect / image_aspect, 1.f);
		}
		gl_rect_2d_simple_tex( getRect().getWidth(), getRect().getHeight() );
		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
	}
	else
	{
		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
		gGL.color4f(0.f, 0.f, 0.f, 1.f);
		gl_rect_2d(getRect());
	}
	glPopMatrix();

	// Handle fade-in animation
	if (mFadeTimer.getStarted())
	{
		LLPanel::draw();
		if (mFadeTimer.getElapsedTimeF32() > FADE_IN_TIME)
		{
			// Fade is complete, release focus
			gFocusMgr.releaseFocusIfNeeded( this );
			LLPanel::setVisible(FALSE);
			mFadeTimer.stop();

			gStartTexture = NULL;
		}
		return;
	}

	// draw children
	LLPanel::draw();
}
//-----------------------------------------------------------------------------
// LLKeyframeFallMotion::onUpdate()
//-----------------------------------------------------------------------------
BOOL LLKeyframeFallMotion::onUpdate(F32 activeTime, U8* joint_mask)
{
	BOOL result = LLKeyframeMotion::onUpdate(activeTime, joint_mask);
	F32  slerp_amt = clamp_rescale(activeTime / getDuration(), 0.5f, 0.75f, 0.f, 1.f);

	if (mPelvisState.notNull())
	{
		mPelvisState->setRotation(mPelvisState->getRotation() * slerp(slerp_amt, mRotationToGroundNormal, LLQuaternion()));
	}
	
	return result;
}
示例#10
0
文件: lltoolgun.cpp 项目: Boy/rainbow
BOOL LLToolGun::handleHover(S32 x, S32 y, MASK mask) 
{
	if( gAgent.cameraMouselook() )
	{
		const F32 NOMINAL_MOUSE_SENSITIVITY = 0.0025f;

		F32 mouse_sensitivity = gSavedSettings.getF32("MouseSensitivity");
		mouse_sensitivity = clamp_rescale(mouse_sensitivity, 0.f, 15.f, 0.5f, 2.75f) * NOMINAL_MOUSE_SENSITIVITY;

		// ...move the view with the mouse

		// get mouse movement delta
		S32 dx = -gViewerWindow->getCurrentMouseDX();
		S32 dy = -gViewerWindow->getCurrentMouseDY();
		
		if (dx != 0 || dy != 0)
		{
			// ...actually moved off center
			if (gSavedSettings.getBOOL("InvertMouse"))
			{
				gAgent.pitch(mouse_sensitivity * -dy);
			}
			else
			{
				gAgent.pitch(mouse_sensitivity * dy);
			}
			LLVector3 skyward = gAgent.getReferenceUpVector();
			gAgent.rotate(mouse_sensitivity * dx, skyward.mV[VX], skyward.mV[VY], skyward.mV[VZ]);

			if (gSavedSettings.getBOOL("MouseSun"))
			{
				gSky.setSunDirection(LLViewerCamera::getInstance()->getAtAxis(), LLVector3(0.f, 0.f, 0.f));
				gSky.setOverrideSun(TRUE);
				gSavedSettings.setVector3("SkySunDefaultPosition", LLViewerCamera::getInstance()->getAtAxis());
			}

			gViewerWindow->moveCursorToCenter();
			gViewerWindow->hideCursor();
		}

		lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGun (mouselook)" << llendl;
	}
	else
	{
		lldebugst(LLERR_USER_INPUT) << "hover handled by LLToolGun (not mouselook)" << llendl;
	}

	// HACK to avoid assert: error checking system makes sure that the cursor is set during every handleHover.  This is actually a no-op since the cursor is hidden.
	gViewerWindow->setCursor(UI_CURSOR_ARROW);  

	return TRUE;
}
//virtual
void LLPanelVolumePulldown::draw()
{
	F32 alpha = mHoverTimer.getStarted() 
		? clamp_rescale(mHoverTimer.getElapsedTimeF32(), sAutoCloseFadeStartTimeSec, sAutoCloseTotalTimeSec, 1.f, 0.f)
		: 1.0f;
	LLViewDrawContext context(alpha);

	LLPanel::draw();

	if (alpha == 0.f)
	{
		setVisible(FALSE);
	}
}
bool get_hud_matrices(const LLRect& screen_region, glh::matrix4f &proj, glh::matrix4f &model)
{
	if (isAgentAvatarValid() && gAgentAvatarp->hasHUDAttachment())
	{
		F32 zoom_level = gAgentCamera.mHUDCurZoom;
		LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
		
		F32 hud_depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
		proj = gl_ortho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, hud_depth);
		proj.element(2,2) = -0.01f;
		
		F32 aspect_ratio = LLViewerCamera::getInstance()->getAspect();
		
		glh::matrix4f mat;
		F32 scale_x = (F32)gViewerWindow->getWorldViewWidthScaled() / (F32)screen_region.getWidth();
		F32 scale_y = (F32)gViewerWindow->getWorldViewHeightScaled() / (F32)screen_region.getHeight();
		mat.set_scale(glh::vec3f(scale_x, scale_y, 1.f));
		mat.set_translate(
			glh::vec3f(clamp_rescale((F32)(screen_region.getCenterX() - screen_region.mLeft), 0.f, (F32)gViewerWindow->getWorldViewWidthScaled(), 0.5f * scale_x * aspect_ratio, -0.5f * scale_x * aspect_ratio),
					   clamp_rescale((F32)(screen_region.getCenterY() - screen_region.mBottom), 0.f, (F32)gViewerWindow->getWorldViewHeightScaled(), 0.5f * scale_y, -0.5f * scale_y),
					   0.f));
		proj *= mat;
		
		glh::matrix4f tmp_model((GLfloat*) OGL_TO_CFR_ROTATION);
		
		mat.set_scale(glh::vec3f(zoom_level, zoom_level, zoom_level));
		mat.set_translate(glh::vec3f(-hud_bbox.getCenterLocal().mV[VX] + (hud_depth * 0.5f), 0.f, 0.f));
		
		tmp_model *= mat;
		model = tmp_model;		
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}
示例#13
0
//-----------------------------------------------------------------------------
// LLFlyAdjustMotion::onUpdate()
//-----------------------------------------------------------------------------
BOOL LLFlyAdjustMotion::onUpdate(F32 time, U8* joint_mask)
{
	LLVector3 ang_vel = mCharacter->getCharacterAngularVelocity() * mCharacter->getTimeDilation();
	F32 speed = mCharacter->getCharacterVelocity().magVec();

	F32 roll_factor = clamp_rescale(speed, 7.f, 15.f, 0.f, -MAX_ROLL);
	F32 target_roll = llclamp(ang_vel.mV[VZ], -4.f, 4.f) * roll_factor;

	// roll is critically damped interpolation between current roll and angular velocity-derived target roll
	mRoll = lerp(mRoll, target_roll, LLCriticalDamp::getInterpolant(0.1f));

	LLQuaternion roll(mRoll, LLVector3(0.f, 0.f, 1.f));
	mPelvisState->setRotation(roll);

	return TRUE;
}
void LLDebugVarMessageBox::draw()
{
	std::string text;
	switch(mVarType)
	{
	  case VAR_TYPE_F32:
		text = llformat("%.3f", *((F32*)mVarData));
		break;
	  case VAR_TYPE_S32:
		text = llformat("%d", *((S32*)mVarData));
		break;
	  case VAR_TYPE_VEC3:
	  {
		  LLVector3* vec_p = (LLVector3*)mVarData;
		  text= llformat("%.3f %.3f %.3f", vec_p->mV[VX], vec_p->mV[VY], vec_p->mV[VZ]);
		  break;
	  }
	  default:
		llwarns << "Unhandled var type " << mVarType << llendl;
		break;
	}
	mText->setText(text);

	if(mAnimate)
	{
		if (mSlider1)
		{
			F32 animated_val = clamp_rescale(fmodf((F32)LLFrameTimer::getElapsedSeconds() / 5.f, 1.f), 0.f, 1.f, 0.f, mSlider1->getMaxValue());
			mSlider1->setValue(animated_val);
			slider_changed(mSlider1, this);
			if (mSlider2)
			{
				mSlider2->setValue(animated_val);
				slider_changed(mSlider2, this);
			}
			if (mSlider3)
			{
				mSlider3->setValue(animated_val);
				slider_changed(mSlider3, this);
			}
		}
	}
	LLFloater::draw();
}
示例#15
0
void LLToolTip::draw()
{
	F32 alpha = 1.f;

	if (mFadeTimer.getStarted())
	{
		F32 tool_tip_fade_time = LLUI::sSettingGroups["config"]->getF32("ToolTipFadeTime");
		alpha = clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, tool_tip_fade_time, 1.f, 0.f);
		if (alpha == 0.f)
		{
			// finished fading out, so hide ourselves
			mFadeTimer.stop();
			LLPanel::setVisible(false);
		}
	}

	// draw tooltip contents with appropriate alpha
	{
		LLViewDrawContext context(alpha);
		LLPanel::draw();
	}
}
void LLHUDEffectBlob::render()
{
	F32 time = mTimer.getElapsedTimeF32();
	if (mDuration < time)
	{
		markDead();
	}

	LLVector3 pos_agent = gAgent.getPosAgentFromGlobal(mPositionGlobal);

	LLVector3 pixel_up, pixel_right;

	LLViewerCamera::instance().getPixelVectors(pos_agent, pixel_up, pixel_right);

	LLGLSPipelineAlpha gls_pipeline_alpha;
	gGL.getTexUnit(0)->bind(mImage->getImage());

	LLColor4U color = mColor;
	color.mV[VALPHA] = (U8)clamp_rescale(time, 0.f, mDuration, 255.f, 0.f);
	gGL.color4ubv(color.mV);

	{ gGL.pushMatrix();
		gGL.translatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]);
		LLVector3 u_scale = pixel_right * (F32)mPixelSize;
		LLVector3 v_scale = pixel_up * (F32)mPixelSize;
		
		{ gGL.begin(LLRender::QUADS);
			gGL.texCoord2f(0.f, 1.f);
			gGL.vertex3fv((v_scale - u_scale).mV);
			gGL.texCoord2f(0.f, 0.f);
			gGL.vertex3fv((-v_scale - u_scale).mV);
			gGL.texCoord2f(1.f, 0.f);
			gGL.vertex3fv((-v_scale + u_scale).mV);
			gGL.texCoord2f(1.f, 1.f);
			gGL.vertex3fv((v_scale + u_scale).mV);
		} gGL.end();

	} gGL.popMatrix();
}
示例#17
0
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_embedded, BOOL use_ellipses) const
{
	LLFastTimer _(FTM_RENDER_FONTS);

	if(!sDisplayFont) //do not display texts
	{
		return wstr.length() ;
	}

	if (wstr.empty() || !max_pixels)
	{
		return 0;
	} 

	if (max_chars == -1)
		max_chars = S32_MAX;

	const S32 max_index = llmin(llmax(max_chars, begin_offset + max_chars), S32(wstr.length()));
	if (max_index <= 0 || begin_offset >= max_index || max_pixels <= 0)
		return 0;

	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);

	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);

	// Strip off any style bits that are already accounted for by the font.
	style = style & (~getFontDesc().getStyle());

	F32 drop_shadow_strength = 0.f;
	if (shadow != NO_SHADOW)
	{
		F32 luminance;
		color.calcHSL(NULL, NULL, &luminance);
		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
		if (luminance < 0.35f)
		{
			shadow = NO_SHADOW;
		}
	}

	gGL.pushUIMatrix();

	gGL.loadUIIdentity();
	
	LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY));

	// Depth translation, so that floating text appears 'in-world'
	// and is correctly occluded.
	gGL.translatef(0.f,0.f,sCurDepth);

	S32 chars_drawn = 0;
	S32 i;
	S32 length = max_index - begin_offset;

	F32 cur_x, cur_y, cur_render_x, cur_render_y;

 	// Not guaranteed to be set correctly
	gGL.setSceneBlendType(LLRender::BT_ALPHA);
	
	cur_x = ((F32)x * sScaleX) + origin.mV[VX];
	cur_y = ((F32)y * sScaleY) + origin.mV[VY];

	// Offset y by vertical alignment.
	// use unscaled font metrics here
	switch (valign)
	{
	case TOP:
		cur_y -= llceil(mFontFreetype->getAscenderHeight());
		break;
	case BOTTOM:
		cur_y += llceil(mFontFreetype->getDescenderHeight());
		break;
	case VCENTER:
		cur_y -= llceil((llceil(mFontFreetype->getAscenderHeight()) - llceil(mFontFreetype->getDescenderHeight())) / 2.f);
		break;
	case BASELINE:
		// Baseline, do nothing.
		break;
	default:
		break;
	}

	switch (halign)
	{
	case LEFT:
		break;
	case RIGHT:
	  	cur_x -= llmin(scaled_max_pixels, ll_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX));
		break;
	case HCENTER:
	    cur_x -= llmin(scaled_max_pixels, ll_round(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2;
		break;
	default:
		break;
	}

	cur_render_y = cur_y;
	cur_render_x = cur_x;

	F32 start_x = (F32)ll_round(cur_x);

	const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();

	F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth();
	F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight();

	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;


	BOOL draw_ellipses = FALSE;
	if (use_ellipses && halign == LEFT)
	{
		// check for too long of a string
		S32 string_width = ll_round(getWidthF32(wstr, begin_offset, max_chars) * sScaleX);
		if (string_width > scaled_max_pixels)
		{
			// use four dots for ellipsis width to generate padding
			const LLWString dots(utf8str_to_wstring(std::string("....")));
			scaled_max_pixels = llmax(0, scaled_max_pixels - ll_round(getWidthF32(dots.c_str())));
			draw_ellipses = TRUE;
		}
	}

	const LLFontGlyphInfo* next_glyph = NULL;

	const S32 GLYPH_BATCH_SIZE = 30;
	static LL_ALIGN_16(LLVector4a vertices[GLYPH_BATCH_SIZE * 4]);
	static LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
	static LLColor4U colors[GLYPH_BATCH_SIZE * 4];

	LLColor4U text_color(color);

	S32 bitmap_num = -1;
	S32 glyph_count = 0;
	for (i = begin_offset; i < begin_offset + length; i++)
	{
		llwchar wch = wstr[i];

		// Handle embedded characters first, if they're enabled.
		// Embedded characters are a hack for notecards
		const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
		if (ext_data)
		{
			LLImageGL* ext_image = ext_data->mImage;
			const LLWString& label = ext_data->mLabel;

			F32 ext_height = (F32)ext_image->getHeight() * sScaleY;

			F32 ext_width = (F32)ext_image->getWidth() * sScaleX;
			F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width;

			if (!label.empty())
			{
				ext_advance += (EXT_X_BEARING + getFontExtChar()->getWidthF32( label.c_str() )) * sScaleX;
			}

			if (start_x + scaled_max_pixels < cur_x + ext_advance)
			{
				// Not enough room for this character.
				break;
			}

			gGL.getTexUnit(0)->bind(ext_image);

			// snap origin to whole screen pixel
			const F32 ext_x = (F32)ll_round(cur_render_x + (EXT_X_BEARING * sScaleX));
			const F32 ext_y = (F32)ll_round(cur_render_y + (EXT_Y_BEARING * sScaleY + mFontFreetype->getAscenderHeight() - mFontFreetype->getLineHeight()));

			LLRectf uv_rect(0.f, 1.f, 1.f, 0.f);
			LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y);

			if (glyph_count > 0)
			{
				gGL.begin(LLRender::QUADS);
				{
					gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
				}
				gGL.end();
				glyph_count = 0;
			}
			renderQuad(vertices, uvs, colors, screen_rect, uv_rect, LLColor4U::white, 0);
			//No batching here. It will never happen.
			gGL.begin(LLRender::QUADS);
			{
				gGL.vertexBatchPreTransformed(vertices, uvs, colors, 4);
			}
			gGL.end();

			if (!label.empty())
			{
				gGL.pushMatrix();
				getFontExtChar()->render(label, 0,
									 /*llfloor*/(ext_x / sScaleX) + ext_image->getWidth() + EXT_X_BEARING - sCurOrigin.mX, 
									 /*llfloor*/(cur_render_y / sScaleY) - sCurOrigin.mY,
									 color,
									 halign, BASELINE, UNDERLINE, NO_SHADOW, S32_MAX, S32_MAX, NULL,
									 TRUE );
				gGL.popMatrix();
			}

			chars_drawn++;
			cur_x += ext_advance;
			if (((i + 1) < length) && wstr[i+1])
			{
				cur_x += EXT_KERNING * sScaleX;
			}
			cur_render_x = cur_x;
		}
		else
		{
			const LLFontGlyphInfo* fgi = next_glyph;
			next_glyph = NULL;
			if(!fgi)
			{
				fgi = mFontFreetype->getGlyphInfo(wch);
			}
			if (!fgi)
			{
				LL_ERRS() << "Missing Glyph Info" << LL_ENDL;
				break;
			}
			// Per-glyph bitmap texture.
			S32 next_bitmap_num = fgi->mBitmapNum;
			if (next_bitmap_num != bitmap_num)
			{
				// Actually draw the queued glyphs before switching their texture;
				// otherwise the queued glyphs will be taken from wrong textures.
				if (glyph_count > 0)
				{
					gGL.begin(LLRender::QUADS);
					{
						gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
					}
					gGL.end();
					glyph_count = 0;
				}

				bitmap_num = next_bitmap_num;
				LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num);
				gGL.getTexUnit(0)->bind(font_image);
			}

			if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
			{
				// Not enough room for this character.
				break;
			}

			// Draw the text at the appropriate location
			//Specify vertices and texture coordinates
			LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width,
					(fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height,
					(fgi->mXBitmapOffset + fgi->mWidth) * inv_width,
				(fgi->mYBitmapOffset - PAD_UVY) * inv_height);
			// snap glyph origin to whole screen pixel
			LLRectf screen_rect((F32)ll_round(cur_render_x + (F32)fgi->mXBearing),
				    (F32)ll_round(cur_render_y + (F32)fgi->mYBearing),
				    (F32)ll_round(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
				    (F32)ll_round(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
			
			if (glyph_count >= GLYPH_BATCH_SIZE)
			{
				gGL.begin(LLRender::QUADS);
				{
					gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
				}
				gGL.end();

				glyph_count = 0;
			}

			drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style, shadow, drop_shadow_strength);

			chars_drawn++;
			cur_x += fgi->mXAdvance;
			cur_y += fgi->mYAdvance;

			llwchar next_char = wstr[i+1];
			if (next_char && (next_char < LAST_CHARACTER))
			{
				// Kern this puppy.
				next_glyph = mFontFreetype->getGlyphInfo(next_char);
				cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
			}

			// Round after kerning.
			// Must do this to cur_x, not just to cur_render_x, otherwise you
			// will squish sub-pixel kerned characters too close together.
			// For example, "CCCCC" looks bad.
			cur_x = (F32)ll_round(cur_x);
			//cur_y = (F32)ll_round(cur_y);

			cur_render_x = cur_x;
			cur_render_y = cur_y;
		}
	}

	if(glyph_count)
	{
		gGL.begin(LLRender::QUADS);
		{
			gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
		}
		gGL.end();
	}


	if (right_x)
	{
		*right_x = (cur_x - origin.mV[VX]) / sScaleX;
	}

	if (style & UNDERLINE)
	{
		F32 descender = (F32)llfloor(mFontFreetype->getDescenderHeight());

		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
		gGL.begin(LLRender::LINES);
		gGL.vertex2f(start_x, cur_y - descender);
		gGL.vertex2f(cur_x, cur_y - descender);
		gGL.end();
	}

	if (draw_ellipses)
	{

		// recursively render ellipses at end of string
		// we've already reserved enough room
		gGL.pushUIMatrix();
		renderUTF8(std::string("..."), 
				0,
				(cur_x - origin.mV[VX]) / sScaleX, (F32)y,
				color,
				LEFT, valign,
				style,
				shadow,
				S32_MAX, max_pixels,
				right_x,
				FALSE); 
		gGL.popUIMatrix();
	}

	gGL.popUIMatrix();

	return chars_drawn;
}
示例#18
0
F32 LLFocusMgr::getFocusFlashAmt() const
{
	return clamp_rescale(getFocusTime(), 0.f, FOCUS_FADE_TIME, mFocusWeight, 0.f);
}
示例#19
0
//-----------------------------------------------------------------------------
// LLWalkAdjustMotion::onUpdate()
//-----------------------------------------------------------------------------
BOOL LLWalkAdjustMotion::onUpdate(F32 time, U8* joint_mask)
{
	// delta_time is guaranteed to be non zero
	F32 delta_time = llclamp(time - mLastTime, TIME_EPSILON, MAX_TIME_DELTA);
	mLastTime = time;

	// find the avatar motion vector in the XY plane
	LLVector3 avatar_velocity = mCharacter->getCharacterVelocity() * mCharacter->getTimeDilation();
	avatar_velocity.mV[VZ] = 0.f;

	F32 speed = llclamp(avatar_velocity.magVec(), 0.f, MAX_WALK_PLAYBACK_SPEED);

	// grab avatar->world transforms
	LLQuaternion avatar_to_world_rot = mCharacter->getRootJoint()->getWorldRotation();

	LLQuaternion world_to_avatar_rot(avatar_to_world_rot);
	world_to_avatar_rot.conjugate();

	LLVector3 foot_slip_vector;

	// find foot drift along velocity vector
	if (speed > MIN_WALK_SPEED)
	{	// walking/running

		// calculate world-space foot drift
		// use global coordinates to seamlessly handle region crossings
		LLVector3d leftFootGlobalPosition = mCharacter->getPosGlobalFromAgent(mLeftAnkleJoint->getWorldPosition());
		leftFootGlobalPosition.mdV[VZ] = 0.0;
		LLVector3 leftFootDelta(leftFootGlobalPosition - mLastLeftFootGlobalPos);
		mLastLeftFootGlobalPos = leftFootGlobalPosition;

		LLVector3d rightFootGlobalPosition = mCharacter->getPosGlobalFromAgent(mRightAnkleJoint->getWorldPosition());
		rightFootGlobalPosition.mdV[VZ] = 0.0;
		LLVector3 rightFootDelta(rightFootGlobalPosition - mLastRightFootGlobalPos);
		mLastRightFootGlobalPos = rightFootGlobalPosition;

		// get foot drift along avatar direction of motion
		F32 left_foot_slip_amt = leftFootDelta * avatar_velocity;
		F32 right_foot_slip_amt = rightFootDelta * avatar_velocity;

		// if right foot is pushing back faster than left foot...
		if (right_foot_slip_amt < left_foot_slip_amt)
		{	//...use it to calculate optimal animation speed
			foot_slip_vector = rightFootDelta;
		} 
		else
		{	// otherwise use the left foot
			foot_slip_vector = leftFootDelta;
		}

		// calculate ideal pelvis offset so that foot is glued to ground and damp towards it
		// this will soak up transient slippage
		//
		// FIXME: this interacts poorly with speed adjustment
		// mPelvisOffset compensates for foot drift by moving the avatar pelvis in the opposite
		// direction of the drift, up to a certain limited distance
		// but this will cause the animation playback rate calculation below to 
		// kick in too slowly and sometimes start playing the animation in reverse.

		//mPelvisOffset -= PELVIS_COMPENSATION_WIEGHT * (foot_slip_vector * world_to_avatar_rot);//lerp(LLVector3::zero, -1.f * (foot_slip_vector * world_to_avatar_rot), LLCriticalDamp::getInterpolant(0.1f));

		////F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL * (llclamp(speed, 0.f, DRIFT_COMP_MAX_SPEED) / DRIFT_COMP_MAX_SPEED);
		//F32 drift_comp_max = DRIFT_COMP_MAX_TOTAL;

		//// clamp pelvis offset to a 90 degree arc behind the nominal position
		//// NB: this is an ADDITIVE amount that is accumulated every frame, so clamping it alone won't do the trick
		//// must clamp with absolute position of pelvis in mind
		//LLVector3 currentPelvisPos = mPelvisState->getJoint()->getPosition();
		//mPelvisOffset.mV[VX] = llclamp( mPelvisOffset.mV[VX], -drift_comp_max, drift_comp_max );
		//mPelvisOffset.mV[VY] = llclamp( mPelvisOffset.mV[VY], -drift_comp_max, drift_comp_max );
		//mPelvisOffset.mV[VZ] = 0.f;
		//
		//mLastRightFootGlobalPos += LLVector3d(mPelvisOffset * avatar_to_world_rot);
		//mLastLeftFootGlobalPos += LLVector3d(mPelvisOffset * avatar_to_world_rot);

		//foot_slip_vector -= mPelvisOffset;

		LLVector3 avatar_movement_dir = avatar_velocity;
		avatar_movement_dir.normalize();

		// planted foot speed is avatar velocity - foot slip amount along avatar movement direction
		F32 foot_speed = speed - ((foot_slip_vector * avatar_movement_dir) / delta_time);

		// multiply animation playback rate so that foot speed matches avatar speed
		F32 min_speed_multiplier = clamp_rescale(speed, 0.f, 1.f, 0.f, 0.1f);
		F32 desired_speed_multiplier = llclamp(speed / foot_speed, min_speed_multiplier, ANIM_SPEED_MAX);

		// blend towards new speed adjustment value
		F32 new_speed_adjust = lerp(mAdjustedSpeed, desired_speed_multiplier, LLCriticalDamp::getInterpolant(SPEED_ADJUST_TIME_CONSTANT));

		// limit that rate at which the speed adjustment changes
		F32 speedDelta = llclamp(new_speed_adjust - mAdjustedSpeed, -SPEED_ADJUST_MAX_SEC * delta_time, SPEED_ADJUST_MAX_SEC * delta_time);
		mAdjustedSpeed += speedDelta;

		// modulate speed by dot products of facing and velocity
		// so that if we are moving sideways, we slow down the animation
		// and if we're moving backward, we walk backward
		// do this at the end to be more responsive to direction changes instead of in the above speed calculations
		F32 directional_factor = (avatar_movement_dir * world_to_avatar_rot).mV[VX];

		mAnimSpeed = mAdjustedSpeed * directional_factor;
	}
	else
	{	// standing/turning

		// damp out speed adjustment to 0
		mAnimSpeed = lerp(mAnimSpeed, 1.f, LLCriticalDamp::getInterpolant(0.2f));
		//mPelvisOffset = lerp(mPelvisOffset, LLVector3::zero, LLCriticalDamp::getInterpolant(0.2f));
	}

	// broadcast walk speed change
 	mCharacter->setAnimationData("Walk Speed", &mAnimSpeed);

	// set position
	// need to update *some* joint to keep this animation active
	mPelvisState->setPosition(mPelvisOffset);

	return TRUE;
}
S32 LLFontGL::render(const LLWString &wstr, 
					 const S32 begin_offset,
					 const F32 x, const F32 y,
					 const LLColor4 &color,
					 const HAlign halign, const VAlign valign,
					 U8 style,
					 const S32 max_chars, S32 max_pixels,
					 F32* right_x,
					 BOOL use_embedded,
					 BOOL use_ellipses) const
{
	if(!sDisplayFont) //do not display texts
	{
		return wstr.length() ;
	}

	if (wstr.empty())
	{
		return 0;
	} 

	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);

	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);

	// Strip off any style bits that are already accounted for by the font.
	style = style & (~getFontDesc().getStyle());

	F32 drop_shadow_strength = 0.f;
	if (style & (DROP_SHADOW | DROP_SHADOW_SOFT))
	{
		F32 luminance;
		color.calcHSL(NULL, NULL, &luminance);
		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
		if (luminance < 0.35f)
		{
			style = style & ~(DROP_SHADOW | DROP_SHADOW_SOFT);
		}
	}

	gGL.pushMatrix();
	glLoadIdentity();
	gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);

	// this code snaps the text origin to a pixel grid to start with
	F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
	F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
	gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f);

	LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS);

	gGL.color4fv( color.mV );

	S32 chars_drawn = 0;
	S32 i;
	S32 length;

	if (-1 == max_chars)
	{
		length = (S32)wstr.length() - begin_offset;
	}
	else
	{
		length = llmin((S32)wstr.length() - begin_offset, max_chars );
	}

	F32 cur_x, cur_y, cur_render_x, cur_render_y;

 	// Not guaranteed to be set correctly
	gGL.setSceneBlendType(LLRender::BT_ALPHA);
	
	cur_x = ((F32)x * sScaleX);
	cur_y = ((F32)y * sScaleY);

	// Offset y by vertical alignment.
	switch (valign)
	{
	case TOP:
		cur_y -= mAscender;
		break;
	case BOTTOM:
		cur_y += mDescender;
		break;
	case VCENTER:
		cur_y -= ((mAscender - mDescender)/2.f);
		break;
	case BASELINE:
		// Baseline, do nothing.
		break;
	default:
		break;
	}

	switch (halign)
	{
	case LEFT:
		break;
	case RIGHT:
	  	cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX));
		break;
	case HCENTER:
	    cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX)) / 2;
		break;
	default:
		break;
	}

	cur_render_y = cur_y;
	cur_render_x = cur_x;

	F32 start_x = cur_x;

	F32 inv_width = 1.f / mFontBitmapCachep->getBitmapWidth();
	F32 inv_height = 1.f / mFontBitmapCachep->getBitmapHeight();

	const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;


	BOOL draw_ellipses = FALSE;
	if (use_ellipses && halign == LEFT)
	{
		// check for too long of a string
		if (getWidthF32(wstr.c_str(), 0, max_chars) * sScaleX > scaled_max_pixels)
		{
			// use four dots for ellipsis width to generate padding
			const LLWString dots(utf8str_to_wstring(std::string("....")));
			scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
			draw_ellipses = TRUE;
		}
	}


	// Remember last-used texture to avoid unnecesssary bind calls.
	LLImageGL *last_bound_texture = NULL;

	for (i = begin_offset; i < begin_offset + length; i++)
	{
		llwchar wch = wstr[i];

		// Handle embedded characters first, if they're enabled.
		// Embedded characters are a hack for notecards
		const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
		if (ext_data)
		{
			LLImageGL* ext_image = ext_data->mImage;
			const LLWString& label = ext_data->mLabel;

			F32 ext_height = (F32)ext_image->getHeight() * sScaleY;

			F32 ext_width = (F32)ext_image->getWidth() * sScaleX;
			F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width;

			if (!label.empty())
			{
				ext_advance += (EXT_X_BEARING + getFontExtChar()->getWidthF32( label.c_str() )) * sScaleX;
			}

			if (start_x + scaled_max_pixels < cur_x + ext_advance)
			{
				// Not enough room for this character.
				break;
			}

			if (last_bound_texture != ext_image)
			{
				gGL.getTexUnit(0)->bind(ext_image);
				last_bound_texture = ext_image;
			}

			// snap origin to whole screen pixel
			const F32 ext_x = (F32)llround(cur_render_x + (EXT_X_BEARING * sScaleX));
			const F32 ext_y = (F32)llround(cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight));

			LLRectf uv_rect(0.f, 1.f, 1.f, 0.f);
			LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y);
			drawGlyph(screen_rect, uv_rect, LLColor4::white, style, drop_shadow_strength);

			if (!label.empty())
			{
				gGL.pushMatrix();
				//glLoadIdentity();
				//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
				//glScalef(sScaleX, sScaleY, 1.f);
				getFontExtChar()->render(label, 0,
									 /*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX), 
									 /*llfloor*/(cur_y / sScaleY),
									 color,
									 halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL,
									 TRUE );
				gGL.popMatrix();
			}

			gGL.color4fv(color.mV);

			chars_drawn++;
			cur_x += ext_advance;
			if (((i + 1) < length) && wstr[i+1])
			{
				cur_x += EXT_KERNING * sScaleX;
			}
			cur_render_x = cur_x;
		}
		else
		{
			if (!hasGlyph(wch))
			{
				addChar(wch);
			}

			const LLFontGlyphInfo* fgi= getGlyphInfo(wch);
			if (!fgi)
			{
				llerrs << "Missing Glyph Info" << llendl;
				break;
			}
			// Per-glyph bitmap texture.
			LLImageGL *image_gl = mFontBitmapCachep->getImageGL(fgi->mBitmapNum);
			if (last_bound_texture != image_gl)
			{
				gGL.getTexUnit(0)->bind(image_gl);
				last_bound_texture = image_gl;
			}

			if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
			{
				// Not enough room for this character.
				break;
			}

			// Draw the text at the appropriate location
			//Specify vertices and texture coordinates
			LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width,
					(fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height,
					(fgi->mXBitmapOffset + fgi->mWidth) * inv_width,
					(fgi->mYBitmapOffset - PAD_UVY) * inv_height);
			// snap glyph origin to whole screen pixel
			LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing),
					    llround(cur_render_y + (F32)fgi->mYBearing),
					    llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
					    llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
			
			drawGlyph(screen_rect, uv_rect, color, style, drop_shadow_strength);

			chars_drawn++;
			cur_x += fgi->mXAdvance;
			cur_y += fgi->mYAdvance;

			llwchar next_char = wstr[i+1];
			if (next_char && (next_char < LAST_CHARACTER))
			{
				// Kern this puppy.
				if (!hasGlyph(next_char))
				{
					addChar(next_char);
				}
				cur_x += getXKerning(wch, next_char);
			}

			// Round after kerning.
			// Must do this to cur_x, not just to cur_render_x, otherwise you
			// will squish sub-pixel kerned characters too close together.
			// For example, "CCCCC" looks bad.
			cur_x = (F32)llfloor(cur_x + 0.5f);
			//cur_y = (F32)llfloor(cur_y + 0.5f);

			cur_render_x = cur_x;
			cur_render_y = cur_y;
		}
	}

	if (right_x)
	{
		*right_x = cur_x / sScaleX;
	}

	if (style & UNDERLINE)
	{
		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
		gGL.begin(LLRender::LINES);
		gGL.vertex2f(start_x, cur_y - (mDescender));
		gGL.vertex2f(cur_x, cur_y - (mDescender));
		gGL.end();
	}

	// *FIX: get this working in all alignment cases, etc.
	if (draw_ellipses)
	{
		// recursively render ellipses at end of string
		// we've already reserved enough room
		gGL.pushMatrix();
		//glLoadIdentity();
		//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
		//glScalef(sScaleX, sScaleY, 1.f);
		renderUTF8(std::string("..."), 
				0,
				cur_x / sScaleX, (F32)y,
				color,
				LEFT, valign,
				style,
				S32_MAX, max_pixels,
				right_x,
				FALSE); 
		gGL.popMatrix();
	}

	gGL.popMatrix();

	return chars_drawn;
}
示例#21
0
S32 LLFontGL::render(const LLWString &wstr, 
					 const S32 begin_offset,
					 const F32 x, const F32 y,
					 const LLColor4 &color,
					 const HAlign halign, const VAlign valign,
					 U8 style,
					 const S32 max_chars, S32 max_pixels,
					 F32* right_x,
					 BOOL use_embedded,
					 BOOL use_ellipses) const
{
	if(!sDisplayFont) //do not display texts
	{
		return wstr.length() ;
	}

	LLGLEnable tex(GL_TEXTURE_2D);

	if (wstr.empty())
	{
		return 0;
	} 

	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);

	// HACK for better bolding
	if (style & BOLD)
	{
		if (this == LLFontGL::sSansSerif)
		{
			return LLFontGL::sSansSerifBold->render(
				wstr, begin_offset,
				x, y,
				color,
				halign, valign, 
				(style & ~BOLD),
				max_chars, max_pixels,
				right_x, use_embedded);
		}
	}

	F32 drop_shadow_strength = 0.f;
	if (style & (DROP_SHADOW | DROP_SHADOW_SOFT))
	{
		F32 luminance;
		color.calcHSL(NULL, NULL, &luminance);
		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
		if (luminance < 0.35f)
		{
			style = style & ~(DROP_SHADOW | DROP_SHADOW_SOFT);
		}
	}

	gGL.pushMatrix();
	glLoadIdentity();
	gGL.translatef(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);
	//glScalef(sScaleX, sScaleY, 1.0f);
	
	// avoid half pixels
	// RN: if we're going to this trouble, might as well snap to nearest pixel all the time
	// but the plan is to get rid of this so that fonts "just work"
	//F32 half_pixel_distance = llabs(fmodf(sCurOrigin.mX * sScaleX, 1.f) - 0.5f);
	//if (half_pixel_distance < PIXEL_BORDER_THRESHOLD)
	//{
		gGL.translatef(PIXEL_CORRECTION_DISTANCE*sScaleX, 0.f, 0.f);
	//}

	// this code would just snap to pixel grid, although it seems to introduce more jitter
	//F32 pixel_offset_x = llround(sCurOrigin.mX * sScaleX) - (sCurOrigin.mX * sScaleX);
	//F32 pixel_offset_y = llround(sCurOrigin.mY * sScaleY) - (sCurOrigin.mY * sScaleY);
	//gGL.translatef(-pixel_offset_x, -pixel_offset_y, 0.f);

	// scale back to native pixel size
	//glScalef(1.f / sScaleX, 1.f / sScaleY, 1.f);
	//glScaled(1.0 / (F64) sScaleX, 1.0 / (F64) sScaleY, 1.0f);
	LLFastTimer t(LLFastTimer::FTM_RENDER_FONTS);

	gGL.color4fv( color.mV );

	S32 chars_drawn = 0;
	S32 i;
	S32 length;

	if (-1 == max_chars)
	{
		length = (S32)wstr.length() - begin_offset;
	}
	else
	{
		length = llmin((S32)wstr.length() - begin_offset, max_chars );
	}

	F32 cur_x, cur_y, cur_render_x, cur_render_y;

	// Bind the font texture
	
	mImageGLp->bind(0);
	
 	// Not guaranteed to be set correctly
	gGL.setSceneBlendType(LLRender::BT_ALPHA);
	
	cur_x = ((F32)x * sScaleX);
	cur_y = ((F32)y * sScaleY);

	// Offset y by vertical alignment.
	switch (valign)
	{
	case TOP:
		cur_y -= mAscender;
		break;
	case BOTTOM:
		cur_y += mDescender;
		break;
	case VCENTER:
		cur_y -= ((mAscender - mDescender)/2.f);
		break;
	case BASELINE:
		// Baseline, do nothing.
		break;
	default:
		break;
	}

	switch (halign)
	{
	case LEFT:
		break;
	case RIGHT:
	  	cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX));
		break;
	case HCENTER:
	    cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), 0, length) * sScaleX)) / 2;
		break;
	default:
		break;
	}

	// Round properly.
	//cur_render_y = (F32)llfloor(cur_y/sScaleY + 0.5f)*sScaleY;
	//cur_render_x = (F32)llfloor(cur_x/sScaleX + 0.5f)*sScaleX;
	
	cur_render_y = cur_y;
	cur_render_x = cur_x;

	F32 start_x = cur_x;

	F32 inv_width = 1.f / mImageGLp->getWidth();
	F32 inv_height = 1.f / mImageGLp->getHeight();

	const S32 LAST_CHARACTER = LLFont::LAST_CHAR_FULL;


	BOOL draw_ellipses = FALSE;
	if (use_ellipses && halign == LEFT)
	{
		// check for too long of a string
		if (getWidthF32(wstr.c_str(), 0, max_chars) * sScaleX > scaled_max_pixels)
		{
			// use four dots for ellipsis width to generate padding
			const LLWString dots(utf8str_to_wstring(std::string("....")));
			scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
			draw_ellipses = TRUE;
		}
	}


	for (i = begin_offset; i < begin_offset + length; i++)
	{
		llwchar wch = wstr[i];

		// Handle embedded characters first, if they're enabled.
		// Embedded characters are a hack for notecards
		const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
		if (ext_data)
		{
			LLImageGL* ext_image = ext_data->mImage;
			const LLWString& label = ext_data->mLabel;

			F32 ext_height = (F32)ext_image->getHeight() * sScaleY;

			F32 ext_width = (F32)ext_image->getWidth() * sScaleX;
			F32 ext_advance = (EXT_X_BEARING * sScaleX) + ext_width;

			if (!label.empty())
			{
				ext_advance += (EXT_X_BEARING + gExtCharFont->getWidthF32( label.c_str() )) * sScaleX;
			}

			if (start_x + scaled_max_pixels < cur_x + ext_advance)
			{
				// Not enough room for this character.
				break;
			}

			ext_image->bind();
			const F32 ext_x = cur_render_x + (EXT_X_BEARING * sScaleX);
			const F32 ext_y = cur_render_y + (EXT_Y_BEARING * sScaleY + mAscender - mLineHeight);

			LLRectf uv_rect(0.f, 1.f, 1.f, 0.f);
			LLRectf screen_rect(ext_x, ext_y + ext_height, ext_x + ext_width, ext_y);
			drawGlyph(screen_rect, uv_rect, LLColor4::white, style, drop_shadow_strength);

			if (!label.empty())
			{
				gGL.pushMatrix();
				//glLoadIdentity();
				//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
				//glScalef(sScaleX, sScaleY, 1.f);
				gExtCharFont->render(label, 0,
									 /*llfloor*/((ext_x + (F32)ext_image->getWidth() + EXT_X_BEARING) / sScaleX), 
									 /*llfloor*/(cur_y / sScaleY),
									 color,
									 halign, BASELINE, NORMAL, S32_MAX, S32_MAX, NULL,
									 TRUE );
				gGL.popMatrix();
			}

			gGL.color4fv(color.mV);

			chars_drawn++;
			cur_x += ext_advance;
			if (((i + 1) < length) && wstr[i+1])
			{
				cur_x += EXT_KERNING * sScaleX;
			}
			cur_render_x = cur_x;

			// Bind the font texture
			mImageGLp->bind();
		}
		else
		{
			if (!hasGlyph(wch))
			{
				(const_cast<LLFontGL*>(this))->addChar(wch);
			}

			const LLFontGlyphInfo* fgi= getGlyphInfo(wch);
			if (!fgi)
			{
				llerrs << "Missing Glyph Info" << llendl;
				break;
			}
			if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
			{
				// Not enough room for this character.
				break;
			}

			// Draw the text at the appropriate location
			//Specify vertices and texture coordinates
			LLRectf uv_rect((fgi->mXBitmapOffset - PAD_AMT) * inv_width,
							(fgi->mYBitmapOffset + fgi->mHeight + PAD_AMT) * inv_height,
							(fgi->mXBitmapOffset + fgi->mWidth + PAD_AMT) * inv_width,
							(fgi->mYBitmapOffset - PAD_AMT) * inv_height);
			LLRectf screen_rect(cur_render_x + (F32)fgi->mXBearing - PAD_AMT,
								cur_render_y + (F32)fgi->mYBearing + PAD_AMT,
								cur_render_x + (F32)fgi->mXBearing + (F32)fgi->mWidth + PAD_AMT,
								cur_render_y + (F32)fgi->mYBearing - (F32)fgi->mHeight - PAD_AMT);

			drawGlyph(screen_rect, uv_rect, color, style, drop_shadow_strength);

			chars_drawn++;
			cur_x += fgi->mXAdvance;
			cur_y += fgi->mYAdvance;

			llwchar next_char = wstr[i+1];
			if (next_char && (next_char < LAST_CHARACTER))
			{
				// Kern this puppy.
				if (!hasGlyph(next_char))
				{
					(const_cast<LLFontGL*>(this))->addChar(next_char);
				}
				cur_x += getXKerning(wch, next_char);
			}

			// Round after kerning.
			// Must do this to cur_x, not just to cur_render_x, otherwise you
			// will squish sub-pixel kerned characters too close together.
			// For example, "CCCCC" looks bad.
			cur_x = (F32)llfloor(cur_x + 0.5f);
			//cur_y = (F32)llfloor(cur_y + 0.5f);

			cur_render_x = cur_x;
			cur_render_y = cur_y;
		}
	}

	if (right_x)
	{
		*right_x = cur_x / sScaleX;
	}

	if (style & UNDERLINE)
	{
		LLGLSNoTexture no_texture;
		gGL.begin(LLVertexBuffer::LINES);
		gGL.vertex2f(start_x, cur_y - (mDescender));
		gGL.vertex2f(cur_x, cur_y - (mDescender));
		gGL.end();
	}

	// *FIX: get this working in all alignment cases, etc.
	if (draw_ellipses)
	{
		// recursively render ellipses at end of string
		// we've already reserved enough room
		gGL.pushMatrix();
		//glLoadIdentity();
		//gGL.translatef(sCurOrigin.mX, sCurOrigin.mY, 0.0f);
		//glScalef(sScaleX, sScaleY, 1.f);
		renderUTF8(std::string("..."), 
				0,
				cur_x / sScaleX, (F32)y,
				color,
				LEFT, valign,
				style,
				S32_MAX, max_pixels,
				right_x,
				FALSE); 
		gGL.popMatrix();
	}

	gGL.popMatrix();

	return chars_drawn;
}
示例#22
0
F32 LLFocusMgr::getFocusFlashAmt() const
{
	return clamp_rescale(mFocusFlashTimer.getElapsedTimeF32(), 0.f, FOCUS_FADE_TIME, 1.f, 0.f);
}
void LLProgressView::draw()
{
	static LLTimer timer;

	if (mFadeFromLoginTimer.getStarted())
	{
		F32 alpha = clamp_rescale(mFadeFromLoginTimer.getElapsedTimeF32(), 0.f, FADE_TO_WORLD_TIME, 0.f, 1.f);
		LLViewDrawContext context(alpha);

		if (!mMediaCtrl->getVisible())
		{
			drawStartTexture(alpha);
		}
		
		LLPanel::draw();
		return;
	}

	// handle fade out to world view when we're asked to
	if (mFadeToWorldTimer.getStarted())
	{
		// draw fading panel
		F32 alpha = clamp_rescale(mFadeToWorldTimer.getElapsedTimeF32(), 0.f, FADE_TO_WORLD_TIME, 1.f, 0.f);
		LLViewDrawContext context(alpha);
				
		drawStartTexture(alpha);
		LLPanel::draw();

		// faded out completely - remove panel and reveal world
		if (mFadeToWorldTimer.getElapsedTimeF32() > FADE_TO_WORLD_TIME )
		{
			mFadeToWorldTimer.stop();

			LLViewerMedia::setOnlyAudibleMediaTextureID(LLUUID::null);

			// Fade is complete, release focus
			gFocusMgr.releaseFocusIfNeeded( this );

			// turn off panel that hosts intro so we see the world
			LLPanel::setVisible(FALSE);

			// stop observing events since we no longer care
			mMediaCtrl->remObserver( this );

			// hide the intro
			mMediaCtrl->setVisible( false );

			// navigate away from intro page to something innocuous since 'unload' is broken right now
			//mMediaCtrl->navigateTo( "about:blank" );

			// FIXME: this causes a crash that i haven't been able to fix
			mMediaCtrl->unloadMediaSource();	

			gStartTexture = NULL;
		}
		return;
	}

	drawStartTexture(1.0f);
	// draw children
	LLPanel::draw();
}
示例#24
0
void LLSpeakerMgr::update(BOOL resort_ok)
{
	if (!LLVoiceClient::getInstance())
	{
		return;
	}
	
	LLColor4 speaking_color = LLUIColorTable::instance().getColor("SpeakingColor");
	LLColor4 overdriven_color = LLUIColorTable::instance().getColor("OverdrivenColor");

	if(resort_ok) // only allow list changes when user is not interacting with it
	{
		updateSpeakerList();
	}

	// update status of all current speakers
	BOOL voice_channel_active = (!mVoiceChannel && LLVoiceClient::getInstance()->inProximalChannel()) || (mVoiceChannel && mVoiceChannel->isActive());
	for (speaker_map_t::iterator speaker_it = mSpeakers.begin(); speaker_it != mSpeakers.end();)
	{
		LLUUID speaker_id = speaker_it->first;
		LLSpeaker* speakerp = speaker_it->second;
		
		speaker_map_t::iterator  cur_speaker_it = speaker_it++;

		if (voice_channel_active && LLVoiceClient::getInstance()->getVoiceEnabled(speaker_id))
		{
			speakerp->mSpeechVolume = LLVoiceClient::getInstance()->getCurrentPower(speaker_id);
			BOOL moderator_muted_voice = LLVoiceClient::getInstance()->getIsModeratorMuted(speaker_id);
			if (moderator_muted_voice != speakerp->mModeratorMutedVoice)
			{
				speakerp->mModeratorMutedVoice = moderator_muted_voice;
				speakerp->fireEvent(new LLSpeakerVoiceModerationEvent(speakerp));
			}

			if (LLVoiceClient::getInstance()->getOnMuteList(speaker_id) || speakerp->mModeratorMutedVoice)
			{
				speakerp->mStatus = LLSpeaker::STATUS_MUTED;
			}
			else if (LLVoiceClient::getInstance()->getIsSpeaking(speaker_id))
			{
				// reset inactivity expiration
				if (speakerp->mStatus != LLSpeaker::STATUS_SPEAKING)
				{
					speakerp->mLastSpokeTime = mSpeechTimer.getElapsedTimeF32();
					speakerp->mHasSpoken = TRUE;
				}
				speakerp->mStatus = LLSpeaker::STATUS_SPEAKING;
				// interpolate between active color and full speaking color based on power of speech output
				speakerp->mDotColor = speaking_color;
				if (speakerp->mSpeechVolume > LLVoiceClient::OVERDRIVEN_POWER_LEVEL)
				{
					speakerp->mDotColor = overdriven_color;
				}
			}
			else
			{
				speakerp->mSpeechVolume = 0.f;
				speakerp->mDotColor = ACTIVE_COLOR;

				if (speakerp->mHasSpoken)
				{
					// have spoken once, not currently speaking
					speakerp->mStatus = LLSpeaker::STATUS_HAS_SPOKEN;
				}
				else
				{
					// default state for being in voice channel
					speakerp->mStatus = LLSpeaker::STATUS_VOICE_ACTIVE;
				}
			}
		}
		// speaker no longer registered in voice channel, demote to text only
		else if (speakerp->mStatus != LLSpeaker::STATUS_NOT_IN_CHANNEL)
		{
			if(speakerp->mType == LLSpeaker::SPEAKER_EXTERNAL)
			{
				// external speakers should be timed out when they leave the voice channel (since they only exist via SLVoice)
				speakerp->mStatus = LLSpeaker::STATUS_NOT_IN_CHANNEL;
			}
			else
			{
				speakerp->mStatus = LLSpeaker::STATUS_TEXT_ONLY;
				speakerp->mSpeechVolume = 0.f;
				speakerp->mDotColor = ACTIVE_COLOR;
			}
		}
	}

	if(resort_ok)  // only allow list changes when user is not interacting with it
	{
		// sort by status then time last spoken
		std::sort(mSpeakersSorted.begin(), mSpeakersSorted.end(), LLSortRecentSpeakers());
	}

	// for recent speakers who are not currently speaking, show "recent" color dot for most recent
	// fading to "active" color

	S32 recent_speaker_count = 0;
	S32 sort_index = 0;
	speaker_list_t::iterator sorted_speaker_it;
	for(sorted_speaker_it = mSpeakersSorted.begin(); 
		sorted_speaker_it != mSpeakersSorted.end(); ++sorted_speaker_it)
	{
		LLPointer<LLSpeaker> speakerp = *sorted_speaker_it;
		
		// color code recent speakers who are not currently speaking
		if (speakerp->mStatus == LLSpeaker::STATUS_HAS_SPOKEN)
		{
			speakerp->mDotColor = lerp(speaking_color, ACTIVE_COLOR, clamp_rescale((F32)recent_speaker_count, -2.f, 3.f, 0.f, 1.f));
			recent_speaker_count++;
		}

		// stuff sort ordinal into speaker so the ui can sort by this value
		speakerp->mSortIndex = sort_index++;
	}
}
示例#25
0
void LLProgressView::draw()
{
	static LLTimer timer;

	if (gNoRender)
	{
		return;
	}

	// Make sure the progress view always fills the entire window.
	S32 width = gViewerWindow->getWindowWidth();
	S32 height = gViewerWindow->getWindowHeight();
	if( (width != getRect().getWidth()) || (height != getRect().getHeight()) )
	{
		reshape( width, height );
	}

	// Paint bitmap if we've got one
	glPushMatrix();
	if (gStartImageGL)
	{
		LLGLSUIDefault gls_ui;
		LLViewerImage::bindTexture(gStartImageGL);
		gGL.color4f(1.f, 1.f, 1.f, mFadeTimer.getStarted() ? clamp_rescale(mFadeTimer.getElapsedTimeF32(), 0.f, FADE_IN_TIME, 1.f, 0.f) : 1.f);
		F32 image_aspect = (F32)gStartImageWidth / (F32)gStartImageHeight;
		F32 view_aspect = (F32)width / (F32)height;
		// stretch image to maintain aspect ratio
		if (image_aspect > view_aspect)
		{
			glTranslatef(-0.5f * (image_aspect / view_aspect - 1.f) * width, 0.f, 0.f);
			glScalef(image_aspect / view_aspect, 1.f, 1.f);
		}
		else
		{
			glTranslatef(0.f, -0.5f * (view_aspect / image_aspect - 1.f) * height, 0.f);
			glScalef(1.f, view_aspect / image_aspect, 1.f);
		}
		gl_rect_2d_simple_tex( getRect().getWidth(), getRect().getHeight() );
		gStartImageGL->unbindTexture(0, GL_TEXTURE_2D);
	}
	else
	{
		LLGLSNoTexture gls_no_texture;
		gGL.color4f(0.f, 0.f, 0.f, 1.f);
		gl_rect_2d(getRect());
	}
	glPopMatrix();

	// Handle fade-in animation
	if (mFadeTimer.getStarted())
	{
		LLView::draw();
		if (mFadeTimer.getElapsedTimeF32() > FADE_IN_TIME)
		{
			gFocusMgr.removeTopCtrlWithoutCallback(this);
			LLView::setVisible(FALSE);
			gStartImageGL = NULL;
		}
		return;
	}

	S32 line_x = getRect().getWidth() / 2;
	S32 line_one_y = getRect().getHeight() / 2 + 64;
	const S32 LINE_SPACING = 25;
	S32 line_two_y = line_one_y - LINE_SPACING;
	const LLFontGL* font = LLFontGL::sSansSerif;

	LLUIImagePtr shadow_imagep = LLUI::getUIImage("rounded_square_soft.tga");
	LLUIImagePtr bar_fg_imagep = LLUI::getUIImage("progressbar_fill.tga");
	LLUIImagePtr bar_bg_imagep = LLUI::getUIImage("progressbar_track.tga");
	LLUIImagePtr bar_imagep = LLUI::getUIImage("rounded_square.tga");
	
	LLColor4 background_color = gColors.getColor("LoginProgressBarBgColor");

	F32 alpha = 0.5f + 0.5f*0.5f*(1.f + (F32)sin(3.f*timer.getElapsedTimeF32()));
	// background_color.mV[3] = background_color.mV[3]*alpha;

	std::string top_line = LLAppViewer::instance()->getSecondLifeTitle();

	S32 bar_bottom = line_two_y - 30;
	S32 bar_height = 18;
	S32 bar_width = getRect().getWidth() * 2 / 3;
	S32 bar_left = (getRect().getWidth() / 2) - (bar_width / 2);

	// translucent outline box
	S32 background_box_left = ( ( ( getRect().getWidth() / 2 ) - ( bar_width / 2 ) ) / 4 ) * 3;
	S32 background_box_top = ( getRect().getHeight() / 2 ) + LINE_SPACING * 5;
	S32 background_box_right = getRect().getWidth() - background_box_left;
	S32 background_box_bottom = ( getRect().getHeight() / 2 ) - LINE_SPACING * 5;
	S32 background_box_width = background_box_right - background_box_left + 1;
	S32 background_box_height = background_box_top - background_box_bottom + 1;

//	shadow_imagep->draw( background_box_left + 2, 
//									background_box_bottom - 2, 
//									background_box_width, 
//									background_box_height,
//									gColors.getColor( "LoginProgressBoxShadowColor" ) );
//	bar_outline_imagep->draw( background_box_left, 
//									background_box_bottom, 
//									background_box_width, 
//									background_box_height,
//									gColors.getColor("LoginProgressBoxBorderColor") );

	bar_imagep->draw( background_box_left + 1,
									background_box_bottom + 1, 
									background_box_width - 2,
									background_box_height - 2,
									gColors.getColor("LoginProgressBoxCenterColor") );

	// we'll need this later for catching a click if it looks like it contains a link
	if ( mMessage.find( "http://" ) != std::string::npos )
		mOutlineRect.set( background_box_left, background_box_top, background_box_right, background_box_bottom );
	else
		mOutlineRect.set( 0, 0, 0, 0 );

	// draw loading bar
	font->renderUTF8(top_line, 0,
		line_x, line_one_y,
		//LLColor4::white,
		gColors.getColor("LoginProgressBoxTextColor"),
		LLFontGL::HCENTER, LLFontGL::BASELINE,
		LLFontGL::DROP_SHADOW);
	font->renderUTF8(mText, 0,
		line_x, line_two_y,
		//LLColor4::white,
		gColors.getColor("LoginProgressBoxTextColor"),
		LLFontGL::HCENTER, LLFontGL::BASELINE,
		LLFontGL::DROP_SHADOW);
		
//	shadow_imagep->draw(
//		bar_left + 2, 
//		bar_bottom - 2, 
//		bar_width, 
//		bar_height,
//		gColors.getColor("LoginProgressBoxShadowColor"));

//	bar_imagep->draw(
//		bar_left, 
//		bar_bottom, 
//		bar_width, 
//		bar_height,
//		LLColor4(0.7f, 0.7f, 0.8f, 1.0f));

	bar_bg_imagep->draw(
		bar_left + 2, 
		bar_bottom + 2,
		bar_width - 4, 
		bar_height - 4,
		background_color);

	LLColor4 bar_color = gColors.getColor("LoginProgressBarFgColor");
	bar_color.mV[3] = alpha;
	bar_fg_imagep->draw(
		bar_left + 2, 
		bar_bottom + 2,
		llround((bar_width - 4) * (mPercentDone / 100.f)), 
		bar_height - 4,
		bar_color);

	S32 line_three_y = line_two_y - LINE_SPACING * 3;
	
	// draw the message if there is one
	if(!mMessage.empty())
	{
		LLColor4 text_message_color = gColors.getColor("LoginProgressBoxTextColor");
		LLWString wmessage = utf8str_to_wstring(mMessage);
		const F32 MAX_PIXELS = 640.0f;
		S32 chars_left = wmessage.length();
		S32 chars_this_time = 0;
		S32 msgidx = 0;
		while(chars_left > 0)
		{
			chars_this_time = font->maxDrawableChars(wmessage.substr(msgidx).c_str(),
													 MAX_PIXELS,
													 MAX_STRING - 1,
													 TRUE);
			LLWString wbuffer = wmessage.substr(msgidx, chars_this_time);
			font->render(wbuffer, 0,
						 (F32)line_x, (F32)line_three_y,
						 //LLColor4::white,
						 gColors.getColor("LoginProgressBoxTextColor"),
						 LLFontGL::HCENTER, LLFontGL::BASELINE,
						 LLFontGL::DROP_SHADOW);
			msgidx += chars_this_time;
			chars_left -= chars_this_time;
			line_three_y -= LINE_SPACING;
		}
	}

	// draw children
	LLView::draw();
}
//-----------------------------------------------------------------------------
// LLEditingMotion::onUpdate()
//-----------------------------------------------------------------------------
BOOL LLEditingMotion::onUpdate(F32 time, U8* joint_mask)
{
	LLVector3 focus_pt;
	LLVector3* pointAtPt = (LLVector3*)mCharacter->getAnimationData("PointAtPoint");


	BOOL result = TRUE;

	if (!pointAtPt)
	{
		focus_pt = mLastSelectPt;
		result = FALSE;
	}
	else
	{
		focus_pt = *pointAtPt;
		mLastSelectPt = focus_pt;
	}

	focus_pt += mCharacter->getCharacterPosition();

	// propagate joint positions to kinematic chain
	mParentJoint.setPosition(	mParentState->getJoint()->getWorldPosition() );
	mShoulderJoint.setPosition(	mShoulderState->getJoint()->getPosition() );
	mElbowJoint.setPosition(	mElbowState->getJoint()->getPosition() );
	mWristJoint.setPosition(	mWristState->getJoint()->getPosition() + mWristOffset );

	// propagate current joint rotations to kinematic chain
	mParentJoint.setRotation(	mParentState->getJoint()->getWorldRotation() );
	mShoulderJoint.setRotation(	mShoulderState->getJoint()->getRotation() );
	mElbowJoint.setRotation(	mElbowState->getJoint()->getRotation() );

	// update target position from character
	LLVector3 target = focus_pt - mParentJoint.getPosition();
	F32 target_dist = target.normVec();
	
	LLVector3 edit_plane_normal(1.f / F_SQRT2, 1.f / F_SQRT2, 0.f);
	edit_plane_normal.normVec();

	edit_plane_normal.rotVec(mTorsoState->getJoint()->getWorldRotation());
	
	F32 dot = edit_plane_normal * target;

	if (dot < 0.f)
	{
		target = target + (edit_plane_normal * (dot * 2.f));
		target.mV[VZ] += clamp_rescale(dot, 0.f, -1.f, 0.f, 5.f);
		target.normVec();
	}

	target = target * target_dist;
	if (!target.isFinite())
	{
		LL_WARNS() << "Non finite target in editing motion with target distance of " << target_dist << 
			" and focus point " << focus_pt << " and pointAtPt: ";
		if (pointAtPt)
		{
		  LL_CONT << *pointAtPt;
		}
		else
		{
		  LL_CONT << "NULL";
		}
		LL_CONT << LL_ENDL;
		target.setVec(1.f, 1.f, 1.f);
	}
	
	mTarget.setPosition( target + mParentJoint.getPosition());

//	LL_INFOS() << "Point At: " << mTarget.getPosition() << LL_ENDL;

	// update the ikSolver
	if (!mTarget.getPosition().isExactlyZero())
	{
		LLQuaternion shoulderRot = mShoulderJoint.getRotation();
		LLQuaternion elbowRot = mElbowJoint.getRotation();
		mIKSolver.solve();

		// use blending...
		F32 slerp_amt = LLSmoothInterpolation::getInterpolant(TARGET_LAG_HALF_LIFE);
		shoulderRot = slerp(slerp_amt, mShoulderJoint.getRotation(), shoulderRot);
		elbowRot = slerp(slerp_amt, mElbowJoint.getRotation(), elbowRot);

		// now put blended values back into joints
		llassert(shoulderRot.isFinite());
		llassert(elbowRot.isFinite());
		mShoulderState->setRotation(shoulderRot);
		mElbowState->setRotation(elbowRot);
		mWristState->setRotation(LLQuaternion::DEFAULT);
	}

	mCharacter->setAnimationData("Hand Pose", &sHandPose);
	mCharacter->setAnimationData("Hand Pose Priority", &sHandPosePriority);
	return result;
}
示例#27
0
S32 LLFontGL::render(const LLWString &wstr, S32 begin_offset, F32 x, F32 y, const LLColor4 &color, HAlign halign, VAlign valign, U8 style, 
					 ShadowType shadow, S32 max_chars, S32 max_pixels, F32* right_x, BOOL use_ellipses) const
{
	LLFastTimer _(FTM_RENDER_FONTS);

	if(!sDisplayFont) //do not display texts
	{
		return wstr.length() ;
	}

	if (wstr.empty())
	{
		return 0;
	} 

	gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);

	S32 scaled_max_pixels = max_pixels == S32_MAX ? S32_MAX : llceil((F32)max_pixels * sScaleX);

	// determine which style flags need to be added programmatically by stripping off the
	// style bits that are drawn by the underlying Freetype font
	U8 style_to_add = (style | mFontDescriptor.getStyle()) & ~mFontFreetype->getStyle();

	F32 drop_shadow_strength = 0.f;
	if (shadow != NO_SHADOW)
	{
		F32 luminance;
		color.calcHSL(NULL, NULL, &luminance);
		drop_shadow_strength = clamp_rescale(luminance, 0.35f, 0.6f, 0.f, 1.f);
		if (luminance < 0.35f)
		{
			shadow = NO_SHADOW;
		}
	}

	gGL.pushUIMatrix();

	gGL.loadUIIdentity();
	
	//gGL.translateUI(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY), sCurOrigin.mZ);

	// this code snaps the text origin to a pixel grid to start with
	//F32 pixel_offset_x = llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
	//F32 pixel_offset_y = llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);
	//gGL.translateUI(-pixel_offset_x, -pixel_offset_y, 0.f);

	LLVector2 origin(floorf(sCurOrigin.mX*sScaleX), floorf(sCurOrigin.mY*sScaleY));
	// snap the text origin to a pixel grid to start with
	origin.mV[VX] -= llround((F32)sCurOrigin.mX) - (sCurOrigin.mX);
	origin.mV[VY] -= llround((F32)sCurOrigin.mY) - (sCurOrigin.mY);


	S32 chars_drawn = 0;
	S32 i;
	S32 length;

	if (-1 == max_chars)
	{
		length = (S32)wstr.length() - begin_offset;
	}
	else
	{
		length = llmin((S32)wstr.length() - begin_offset, max_chars );
	}

	F32 cur_x, cur_y, cur_render_x, cur_render_y;

 	// Not guaranteed to be set correctly
	gGL.setSceneBlendType(LLRender::BT_ALPHA);
	
	cur_x = ((F32)x * sScaleX) + origin.mV[VX];
	cur_y = ((F32)y * sScaleY) + origin.mV[VY];

	// Offset y by vertical alignment.
	switch (valign)
	{
	case TOP:
		cur_y -= mFontFreetype->getAscenderHeight();
		break;
	case BOTTOM:
		cur_y += mFontFreetype->getDescenderHeight();
		break;
	case VCENTER:
		cur_y -= (mFontFreetype->getAscenderHeight() - mFontFreetype->getDescenderHeight()) / 2.f;
		break;
	case BASELINE:
		// Baseline, do nothing.
		break;
	default:
		break;
	}

	switch (halign)
	{
	case LEFT:
		break;
	case RIGHT:
	  	cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX));
		break;
	case HCENTER:
	    cur_x -= llmin(scaled_max_pixels, llround(getWidthF32(wstr.c_str(), begin_offset, length) * sScaleX)) / 2;
		break;
	default:
		break;
	}

	cur_render_y = cur_y;
	cur_render_x = cur_x;

	F32 start_x = llround(cur_x);

	const LLFontBitmapCache* font_bitmap_cache = mFontFreetype->getFontBitmapCache();

	F32 inv_width = 1.f / font_bitmap_cache->getBitmapWidth();
	F32 inv_height = 1.f / font_bitmap_cache->getBitmapHeight();

	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;


	BOOL draw_ellipses = FALSE;
	if (use_ellipses)
	{
		// check for too long of a string
		S32 string_width = llround(getWidthF32(wstr.c_str(), begin_offset, max_chars) * sScaleX);
		if (string_width > scaled_max_pixels)
		{
			// use four dots for ellipsis width to generate padding
			const LLWString dots(utf8str_to_wstring(std::string("....")));
			scaled_max_pixels = llmax(0, scaled_max_pixels - llround(getWidthF32(dots.c_str())));
			draw_ellipses = TRUE;
		}
	}

	const LLFontGlyphInfo* next_glyph = NULL;

	const S32 GLYPH_BATCH_SIZE = 30;
	LLVector3 vertices[GLYPH_BATCH_SIZE * 4];
	LLVector2 uvs[GLYPH_BATCH_SIZE * 4];
	LLColor4U colors[GLYPH_BATCH_SIZE * 4];

	LLColor4U text_color(color);

	S32 bitmap_num = -1;
	S32 glyph_count = 0;
	for (i = begin_offset; i < begin_offset + length; i++)
	{
		llwchar wch = wstr[i];

		const LLFontGlyphInfo* fgi = next_glyph;
		next_glyph = NULL;
		if(!fgi)
		{
			fgi = mFontFreetype->getGlyphInfo(wch);
		}
		if (!fgi)
		{
			llerrs << "Missing Glyph Info" << llendl;
			break;
		}
		// Per-glyph bitmap texture.
		S32 next_bitmap_num = fgi->mBitmapNum;
		if (next_bitmap_num != bitmap_num)
		{
			bitmap_num = next_bitmap_num;
			LLImageGL *font_image = font_bitmap_cache->getImageGL(bitmap_num);
			gGL.getTexUnit(0)->bind(font_image);
		}
	
		if ((start_x + scaled_max_pixels) < (cur_x + fgi->mXBearing + fgi->mWidth))
		{
			// Not enough room for this character.
			break;
		}

		// Draw the text at the appropriate location
		//Specify vertices and texture coordinates
		LLRectf uv_rect((fgi->mXBitmapOffset) * inv_width,
				(fgi->mYBitmapOffset + fgi->mHeight + PAD_UVY) * inv_height,
				(fgi->mXBitmapOffset + fgi->mWidth) * inv_width,
				(fgi->mYBitmapOffset - PAD_UVY) * inv_height);
		// snap glyph origin to whole screen pixel
		LLRectf screen_rect(llround(cur_render_x + (F32)fgi->mXBearing),
				    llround(cur_render_y + (F32)fgi->mYBearing),
				    llround(cur_render_x + (F32)fgi->mXBearing) + (F32)fgi->mWidth,
				    llround(cur_render_y + (F32)fgi->mYBearing) - (F32)fgi->mHeight);
		
		if (glyph_count >= GLYPH_BATCH_SIZE)
		{
			gGL.begin(LLRender::QUADS);
			{
				gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
			}
			gGL.end();

			glyph_count = 0;
		}

		drawGlyph(glyph_count, vertices, uvs, colors, screen_rect, uv_rect, text_color, style_to_add, shadow, drop_shadow_strength);

		chars_drawn++;
		cur_x += fgi->mXAdvance;
		cur_y += fgi->mYAdvance;

		llwchar next_char = wstr[i+1];
		if (next_char && (next_char < LAST_CHARACTER))
		{
			// Kern this puppy.
			next_glyph = mFontFreetype->getGlyphInfo(next_char);
			cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
		}

		// Round after kerning.
		// Must do this to cur_x, not just to cur_render_x, otherwise you
		// will squish sub-pixel kerned characters too close together.
		// For example, "CCCCC" looks bad.
		cur_x = (F32)llround(cur_x);
		//cur_y = (F32)llround(cur_y);

		cur_render_x = cur_x;
		cur_render_y = cur_y;
	}

	gGL.begin(LLRender::QUADS);
	{
		gGL.vertexBatchPreTransformed(vertices, uvs, colors, glyph_count * 4);
	}
	gGL.end();


	if (right_x)
	{
		*right_x = (cur_x - origin.mV[VX]) / sScaleX;
	}

	//FIXME: add underline as glyph?
	if (style_to_add & UNDERLINE)
	{
		F32 descender = mFontFreetype->getDescenderHeight();

		gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
		gGL.begin(LLRender::LINES);
		gGL.vertex2f(start_x, cur_y - (descender));
		gGL.vertex2f(cur_x, cur_y - (descender));
		gGL.end();
	}

	if (draw_ellipses)
	{
		
		// recursively render ellipses at end of string
		// we've already reserved enough room
		gGL.pushUIMatrix();
		renderUTF8(std::string("..."), 
				0,
				(cur_x - origin.mV[VX]) / sScaleX, (F32)y,
				color,
				LEFT, valign,
				style_to_add,
				shadow,
				S32_MAX, max_pixels,
				right_x,
				FALSE); 
		gGL.popUIMatrix();
	}

	gGL.popUIMatrix();

	return chars_drawn;
}