Beispiel #1
0
void pack_instant_message_block(
	LLMessageSystem* msg,
	const LLUUID& from_id,
	BOOL from_group,
	const LLUUID& session_id,
	const LLUUID& to_id,
	const std::string& name,
	const std::string& message,
	U8 offline,
	EInstantMessage dialog,
	const LLUUID& id,
	U32 parent_estate_id,
	const LLUUID& region_id,
	const LLVector3& position,
	U32 timestamp,
	const U8* binary_bucket,
	S32 binary_bucket_size)
{
	msg->nextBlockFast(_PREHASH_AgentData);
	msg->addUUIDFast(_PREHASH_AgentID, from_id);
	msg->addUUIDFast(_PREHASH_SessionID, session_id);
	msg->nextBlockFast(_PREHASH_MessageBlock);
	msg->addBOOLFast(_PREHASH_FromGroup, from_group);
	msg->addUUIDFast(_PREHASH_ToAgentID, to_id);
	msg->addU32Fast(_PREHASH_ParentEstateID, parent_estate_id);
	msg->addUUIDFast(_PREHASH_RegionID, region_id);
	msg->addVector3Fast(_PREHASH_Position, position);
	msg->addU8Fast(_PREHASH_Offline, offline);
	msg->addU8Fast(_PREHASH_Dialog, (U8) dialog);
	msg->addUUIDFast(_PREHASH_ID, id);
	msg->addU32Fast(_PREHASH_Timestamp, timestamp);
	msg->addStringFast(_PREHASH_FromAgentName, name);
	S32 bytes_left = MTUBYTES;
	if(!message.empty())
	{
		char buffer[MTUBYTES];
		int num_written = snprintf(buffer, MTUBYTES, "%s", message.c_str());	/* Flawfinder: ignore */
		// snprintf returns number of bytes that would have been written
		// had the output not being truncated. In that case, it will
		// return either -1 or value >= passed in size value . So a check needs to be added
		// to detect truncation, and if there is any, only account for the
		// actual number of bytes written..and not what could have been
		// written.
		if (num_written < 0 || num_written >= MTUBYTES)
		{
			num_written = MTUBYTES - 1;
			LL_WARNS() << "pack_instant_message_block: message truncated: " << message << LL_ENDL;
		}

		bytes_left -= num_written;
		bytes_left = llmax(0, bytes_left);
		msg->addStringFast(_PREHASH_Message, buffer);
	}
	else
	{
		msg->addStringFast(_PREHASH_Message, NULL);
	}
	const U8* bb;
	if(binary_bucket)
	{
		bb = binary_bucket;
		binary_bucket_size = llmin(bytes_left, binary_bucket_size);
	}
	else
	{
		bb = (const U8*)EMPTY_BINARY_BUCKET;
		binary_bucket_size = EMPTY_BINARY_BUCKET_SIZE;
	}
	msg->addBinaryDataFast(_PREHASH_BinaryBucket, bb, binary_bucket_size);
}
 static U16 min(AIHTTPTimeoutPolicy const* policy) { return llmax(ABS_min_total_delay, (U16)(policy->mMaximumCurlTransaction + 1)); }
Beispiel #3
0
LLToastAlertPanel::LLToastAlertPanel( LLNotificationPtr notification, bool modal)
	  : LLToastPanel(notification),
		mDefaultOption( 0 ),
		mCheck(NULL),
		mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH),
		mLabel(notification->getName()),
		mLineEditor(NULL)
{
	const LLFontGL* font = LLFontGL::getFontSansSerif();
	const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f);
	const S32 EDITOR_HEIGHT = 20;

	LLNotificationFormPtr form = mNotification->getForm();
	std::string edit_text_name;
	std::string edit_text_contents;
	S32 edit_text_max_chars = 0;
	bool is_password = false;

	LLToastPanel::setBackgroundVisible(FALSE);
	LLToastPanel::setBackgroundOpaque(TRUE);


	typedef std::vector<std::pair<std::string, std::string> > options_t;
	options_t supplied_options;

	// for now, get LLSD to iterator over form elements
	LLSD form_sd = form->asLLSD();

	S32 option_index = 0;
	for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it)
	{
		std::string type = (*it)["type"].asString();
		if (type == "button")
		{
			if((*it)["default"])
			{
				mDefaultOption = option_index;
			}

			supplied_options.push_back(std::make_pair((*it)["name"].asString(), (*it)["text"].asString()));

			ButtonData data;
			if (option_index == mNotification->getURLOption())
			{
				data.mURL = mNotification->getURL();
				data.mURLExternal = mNotification->getURLOpenExternally();
			}

			mButtonData.push_back(data);
			option_index++;
		}
		else if (type == "text")
		{
			edit_text_contents = (*it)["value"].asString();
			edit_text_name = (*it)["name"].asString();
			edit_text_max_chars = (*it)["max_length_chars"].asInteger();
		}
		else if (type == "password")
		{
			edit_text_contents = (*it)["value"].asString();
			edit_text_name = (*it)["name"].asString();
			is_password = true;
		}
	}

	// Buttons
	options_t options;
	if (supplied_options.empty())
	{
		options.push_back(std::make_pair(std::string("close"), LLNotifications::instance().getGlobalString("implicitclosebutton")));

		// add data for ok button.
		ButtonData ok_button;
		mButtonData.push_back(ok_button);
		mDefaultOption = 0;
	}
	else
	{
		options = supplied_options;
	}

	S32 num_options = options.size();

	// Calc total width of buttons
	S32 button_width = 0;
	S32 sp = font->getWidth(std::string("OO"));
	for( S32 i = 0; i < num_options; i++ )
	{
		S32 w = S32(font->getWidth( options[i].second ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD;
		button_width = llmax( w, button_width );
	}
	S32 btn_total_width = button_width;
	if( num_options > 1 )
	{
		btn_total_width = (num_options * button_width) + ((num_options - 1) * BTN_HPAD);
	}

	// Message: create text box using raw string, as text has been structure deliberately
	// Use size of created text box to generate dialog box size
	std::string msg = mNotification->getMessage();
	llwarns << "Alert: " << msg << llendl;
	LLTextBox::Params params;
	params.name("Alert message");
	params.font(font);
	params.tab_stop(false);
	params.wrap(true);
	params.follows.flags(FOLLOWS_LEFT | FOLLOWS_TOP);
	params.allow_scroll(true);

	LLTextBox * msg_box = LLUICtrlFactory::create<LLTextBox> (params);
	// Compute max allowable height for the dialog text, so we can allocate
	// space before wrapping the text to fit.
	S32 max_allowed_msg_height = 
			gFloaterView->getRect().getHeight()
			- LINE_HEIGHT			// title bar
			- 3*VPAD - BTN_HEIGHT;
	// reshape to calculate real text width and height
	msg_box->reshape( MAX_ALLOWED_MSG_WIDTH, max_allowed_msg_height );
	msg_box->setValue(msg);

	S32 pixel_width = msg_box->getTextPixelWidth();
	S32 pixel_height = msg_box->getTextPixelHeight();

	// We should use some space to prevent set textbox's scroller visible when it is unnecessary.
	msg_box->reshape( llmin(MAX_ALLOWED_MSG_WIDTH,pixel_width + 2 * msg_box->getHPad() + HPAD),
		llmin(max_allowed_msg_height,pixel_height + 2 * msg_box->getVPad())  ) ;

	const LLRect& text_rect = msg_box->getRect();
	S32 dialog_width = llmax( btn_total_width, text_rect.getWidth() ) + 2 * HPAD;
	S32 dialog_height = text_rect.getHeight() + 3 * VPAD + BTN_HEIGHT;

	if (hasTitleBar())
	{
		dialog_height += LINE_HEIGHT; // room for title bar
	}

	// it's ok for the edit text body to be empty, but we want the name to exist if we're going to draw it
	if (!edit_text_name.empty())
	{
		dialog_height += EDITOR_HEIGHT + VPAD;
		dialog_width = llmax(dialog_width, (S32)(font->getWidth( edit_text_contents ) + 0.99f));
	}

	if (mCaution)
	{
		// Make room for the caution icon.
		dialog_width += 32 + HPAD;
	}

	LLToastPanel::reshape( dialog_width, dialog_height, FALSE );

	S32 msg_y = LLToastPanel::getRect().getHeight() - VPAD;
	S32 msg_x = HPAD;
	if (hasTitleBar())
	{
		msg_y -= LINE_HEIGHT; // room for title
	}

	static LLUIColor alert_caution_text_color = LLUIColorTable::instance().getColor("AlertCautionTextColor");
	if (mCaution)
	{
		LLIconCtrl* icon = LLUICtrlFactory::getInstance()->createFromFile<LLIconCtrl>("alert_icon.xml", this, LLPanel::child_registry_t::instance());
		if(icon)
		{
			icon->setRect(LLRect(msg_x, msg_y, msg_x+32, msg_y-32));
			LLToastPanel::addChild(icon);
		}
		
		msg_x += 32 + HPAD;
		msg_box->setColor( alert_caution_text_color );
	}

	LLRect rect;
	rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() );
	msg_box->setRect( rect );
	LLToastPanel::addChild(msg_box);

	// (Optional) Edit Box	
	if (!edit_text_name.empty())
	{
		S32 y = VPAD + BTN_HEIGHT + VPAD/2;
		mLineEditor = LLUICtrlFactory::getInstance()->createFromFile<LLLineEditor>("alert_line_editor.xml", this, LLPanel::child_registry_t::instance());
	
		if (mLineEditor)
		{
			LLRect leditor_rect = LLRect( HPAD, y+EDITOR_HEIGHT, dialog_width-HPAD, y);
			mLineEditor->setName(edit_text_name);
			mLineEditor->reshape(leditor_rect.getWidth(), leditor_rect.getHeight());
			mLineEditor->setRect(leditor_rect);
			mLineEditor->setMaxTextChars(edit_text_max_chars);
			mLineEditor->setText(edit_text_contents);

			// decrease limit of line editor of teleport offer dialog to avoid truncation of
			// location URL in invitation message, see EXT-6891
			if ("OfferTeleport" == mNotification->getName())
			{
				mLineEditor->setMaxTextLength(gSavedSettings.getS32(
						"teleport_offer_invitation_max_length"));
			}
			else
			{
				mLineEditor->setMaxTextLength(STD_STRING_STR_LEN - 1);
			}

			LLToastPanel::addChild(mLineEditor);

			mLineEditor->setDrawAsterixes(is_password);

			setEditTextArgs(notification->getSubstitutions());

			mLineEditor->setFollowsLeft();
			mLineEditor->setFollowsRight();

			// find form text input field
			LLSD form_text;
			for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it)
			{
				std::string type = (*it)["type"].asString();
				if (type == "text")
				{
					form_text = (*it);
				}
			}

			// if form text input field has width attribute
			if (form_text.has("width"))
			{
				// adjust floater width to fit line editor
				S32 editor_width = form_text["width"];
				LLRect editor_rect =  mLineEditor->getRect();
				U32 width_delta = editor_width  - editor_rect.getWidth();
				LLRect toast_rect = getRect();
				reshape(toast_rect.getWidth() +  width_delta, toast_rect.getHeight());
			}
		}
	}

	// Buttons
	S32 button_left = (LLToastPanel::getRect().getWidth() - btn_total_width) / 2;

	for( S32 i = 0; i < num_options; i++ )
	{
		LLRect button_rect;

		LLButton* btn = LLUICtrlFactory::getInstance()->createFromFile<LLButton>("alert_button.xml", this, LLPanel::child_registry_t::instance());
		if(btn)
		{
			btn->setName(options[i].first);
			btn->setRect(button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT ));
			btn->setLabel(options[i].second);
			btn->setFont(font);

			btn->setClickedCallback(boost::bind(&LLToastAlertPanel::onButtonPressed, this, _2, i));

			mButtonData[i].mButton = btn;

			LLToastPanel::addChild(btn);

			if( i == mDefaultOption )
			{
				btn->setFocus(TRUE);
			}
		}
		button_left += button_width + BTN_HPAD;
	}

	std::string ignore_label;

	if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE)
	{
		setCheckBox(LLNotifications::instance().getGlobalString("skipnexttime"), ignore_label);
	}
	else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
	{
		setCheckBox(LLNotifications::instance().getGlobalString("alwayschoose"), ignore_label);
	}

	// *TODO: check necessity of this code
	//gFloaterView->adjustToFitScreen(this, FALSE);
	if (mLineEditor)
	{
		mLineEditor->selectAll();
	}
	if(mDefaultOption >= 0)
	{
		// delay before enabling default button
		mDefaultBtnTimer.start();
		mDefaultBtnTimer.setTimerExpirySec(DEFAULT_BUTTON_DELAY);
	}

	LLTransientFloaterMgr::instance().addControlView(
			LLTransientFloaterMgr::GLOBAL, this);
}
Beispiel #4
0
void LLComboBox::showList()
{
	// Make sure we don't go off top of screen.
	LLCoordWindow window_size;
	getWindow()->getSize(&window_size);
	//HACK: shouldn't have to know about scale here
	mList->fitContents( 192, llfloor((F32)window_size.mY / LLUI::sGLScaleFactor.mV[VY]) - 50 );

	// Make sure that we can see the whole list
	LLRect root_view_local;
	LLView* root_view = getRootView();
	root_view->localRectToOtherView(root_view->getLocalRect(), &root_view_local, this);
	
	LLRect rect = mList->getRect();

	S32 min_width = getRect().getWidth();
	S32 max_width = llmax(min_width, MAX_COMBO_WIDTH);
	// make sure we have up to date content width metrics
	mList->calcColumnWidths();
	S32 list_width = llclamp(mList->getMaxContentWidth(), min_width, max_width);

	if (mListPosition == BELOW)
	{
		if (rect.getHeight() <= -root_view_local.mBottom)
		{
			// Move rect so it hangs off the bottom of this view
			rect.setLeftTopAndSize(0, 0, list_width, rect.getHeight() );
		}
		else
		{	
			// stack on top or bottom, depending on which has more room
			if (-root_view_local.mBottom > root_view_local.mTop - getRect().getHeight())
			{
				// Move rect so it hangs off the bottom of this view
				rect.setLeftTopAndSize(0, 0, list_width, llmin(-root_view_local.mBottom, rect.getHeight()));
			}
			else
			{
				// move rect so it stacks on top of this view (clipped to size of screen)
				rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight()));
			}
		}
	}
	else // ABOVE
	{
		if (rect.getHeight() <= root_view_local.mTop - getRect().getHeight())
		{
			// move rect so it stacks on top of this view (clipped to size of screen)
			rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight()));
		}
		else
		{
			// stack on top or bottom, depending on which has more room
			if (-root_view_local.mBottom > root_view_local.mTop - getRect().getHeight())
			{
				// Move rect so it hangs off the bottom of this view
				rect.setLeftTopAndSize(0, 0, list_width, llmin(-root_view_local.mBottom, rect.getHeight()));
			}
			else
			{
				// move rect so it stacks on top of this view (clipped to size of screen)
				rect.setOriginAndSize(0, getRect().getHeight(), list_width, llmin(root_view_local.mTop - getRect().getHeight(), rect.getHeight()));
			}
		}

	}
	mList->setOrigin(rect.mLeft, rect.mBottom);
	mList->reshape(rect.getWidth(), rect.getHeight());
	mList->translateIntoRect(root_view_local, FALSE);

	// Make sure we didn't go off bottom of screen
	S32 x, y;
	mList->localPointToScreen(0, 0, &x, &y);

	if (y < 0)
	{
		mList->translate(0, -y);
	}

	// NB: this call will trigger the focuslost callback which will hide the list, so do it first
	// before finally showing the list

	mList->setFocus(TRUE);

	// Show the list and push the button down
	mButton->setToggleState(TRUE);
	mList->setVisible(TRUE);
	
	LLUI::addPopup(this);

	setUseBoundingRect(TRUE);
//	updateBoundingRect();
}
static bool handleFogRatioChanged(const LLSD& newvalue)
{
	F32 fog_ratio = llmax(MIN_USER_FOG_RATIO, llmin((F32) newvalue.asReal(), MAX_USER_FOG_RATIO));
	gSky.setFogRatio(fog_ratio);
	return true;
}
void LLAudioEngine_OpenAL::updateWind(LLVector3 wind_vec, F32 camera_altitude)
{
	LLVector3 wind_pos;
	F64 pitch;
	F64 center_freq;
	ALenum error;
	
	if (!mEnableWind)
		return;
	
	if(!mWindBuf)
		return;
	
	if (mWindUpdateTimer.checkExpirationAndReset(LL_WIND_UPDATE_INTERVAL))
	{
		
		// wind comes in as Linden coordinate (+X = forward, +Y = left, +Z = up)
		// need to convert this to the conventional orientation DS3D and OpenAL use
		// where +X = right, +Y = up, +Z = backwards
		
		wind_vec.setVec(-wind_vec.mV[1], wind_vec.mV[2], -wind_vec.mV[0]);
		
		pitch = 1.0 + mapWindVecToPitch(wind_vec);
		center_freq = 80.0 * pow(pitch,2.5*(mapWindVecToGain(wind_vec)+1.0));
		
		mWindGen->mTargetFreq = (F32)center_freq;
		mWindGen->mTargetGain = (F32)mapWindVecToGain(wind_vec) * mMaxWindGain;
		mWindGen->mTargetPanGainR = (F32)mapWindVecToPan(wind_vec);
		
		alSourcei(mWindSource, AL_LOOPING, AL_FALSE);
		alSource3f(mWindSource, AL_POSITION, 0.0, 0.0, 0.0);
		alSource3f(mWindSource, AL_VELOCITY, 0.0, 0.0, 0.0);
		alSourcef(mWindSource, AL_ROLLOFF_FACTOR, 0.0);
		alSourcei(mWindSource, AL_SOURCE_RELATIVE, AL_TRUE);
	}

	// ok lets make a wind buffer now

	int processed, queued, unprocessed;
	alGetSourcei(mWindSource, AL_BUFFERS_PROCESSED, &processed);
	alGetSourcei(mWindSource, AL_BUFFERS_QUEUED, &queued);
	unprocessed = queued - processed;

	// ensure that there are always at least 3x as many filled buffers
	// queued as we managed to empty since last time.
	mNumEmptyWindALBuffers = llmin(mNumEmptyWindALBuffers + processed * 3 - unprocessed, MAX_NUM_WIND_BUFFERS-unprocessed);
	mNumEmptyWindALBuffers = llmax(mNumEmptyWindALBuffers, 0);

	//LL_INFOS("OpenAL") << "mNumEmptyWindALBuffers: " << mNumEmptyWindALBuffers	<<" (" << unprocessed << ":" << processed << ")" << LL_ENDL;

	while(processed--) // unqueue old buffers
	{
		ALuint buffer;
		int error;
		alGetError(); /* clear error */
		alSourceUnqueueBuffers(mWindSource, 1, &buffer);
		error = alGetError();
		if(error != AL_NO_ERROR)
		{
			LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::updateWind() error swapping (unqueuing) buffers" << LL_ENDL;
		}
		else
		{
			alDeleteBuffers(1, &buffer);
		}
	}

	unprocessed += mNumEmptyWindALBuffers;
	while (mNumEmptyWindALBuffers > 0) // fill+queue new buffers
	{
		ALuint buffer;
		alGetError(); /* clear error */
		alGenBuffers(1,&buffer);
		if((error=alGetError()) != AL_NO_ERROR)
		{
			LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::initWind() Error creating wind buffer: " << error << LL_ENDL;
			break;
		}

		alBufferData(buffer,
			     AL_FORMAT_STEREO16,
			     mWindGen->windGenerate(mWindBuf,
						    mWindBufSamples, 2),
			     mWindBufBytes,
			     mWindBufFreq);
		error = alGetError();
		if(error != AL_NO_ERROR)
			LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::updateWind() error swapping (bufferdata) buffers" << LL_ENDL;
		
		alSourceQueueBuffers(mWindSource, 1, &buffer);
		error = alGetError();
		if(error != AL_NO_ERROR)
			LL_WARNS("OpenAL") << "LLAudioEngine_OpenAL::updateWind() error swapping (queuing) buffers" << LL_ENDL;

		--mNumEmptyWindALBuffers;
	}

	int playing;
	alGetSourcei(mWindSource, AL_SOURCE_STATE, &playing);
	if(playing != AL_PLAYING)
	{
		alSourcePlay(mWindSource);

		LL_INFOS("OpenAL") << "Wind had stopped - probably ran out of buffers - restarting: " << (unprocessed+mNumEmptyWindALBuffers) << " now queued." << LL_ENDL;
	}
}
Beispiel #7
0
void LLParticlePartition::getGeometry(LLSpatialGroup* group)
{
	LL_RECORD_BLOCK_TIME(FTM_REBUILD_PARTICLE_GEOM);

	std::sort(mFaceList.begin(), mFaceList.end(), LLFace::CompareDistanceGreater());

	U32 index_count = 0;
	U32 vertex_count = 0;

	group->clearDrawMap();

	LLVertexBuffer* buffer = group->mVertexBuffer;

	LLStrider<U16> indicesp;
	LLStrider<LLVector4a> verticesp;
	LLStrider<LLVector3> normalsp;
	LLStrider<LLVector2> texcoordsp;
	LLStrider<LLColor4U> colorsp;
	LLStrider<LLColor4U> emissivep;

	buffer->getVertexStrider(verticesp);
	buffer->getNormalStrider(normalsp);
	buffer->getColorStrider(colorsp);
	buffer->getEmissiveStrider(emissivep);

	
	LLSpatialGroup::drawmap_elem_t& draw_vec = group->mDrawMap[mRenderPass];	

	for (std::vector<LLFace*>::iterator i = mFaceList.begin(); i != mFaceList.end(); ++i)
	{
		LLFace* facep = *i;
		LLAlphaObject* object = (LLAlphaObject*) facep->getViewerObject();

		//if (!facep->isState(LLFace::PARTICLE))
		{ //set the indices of this face
			S32 idx = LLVOPartGroup::findAvailableVBSlot();
			if (idx >= 0)
			{
				facep->setGeomIndex(idx*4);
				facep->setIndicesIndex(idx*6);
				facep->setVertexBuffer(LLVOPartGroup::sVB);
				facep->setPoolType(LLDrawPool::POOL_ALPHA);
				//facep->setState(LLFace::PARTICLE);
			}
			else
			{
				continue; //out of space in particle buffer
			}		
		}

		S32 geom_idx = (S32) facep->getGeomIndex();

		LLStrider<U16> cur_idx = indicesp + facep->getIndicesStart();
		LLStrider<LLVector4a> cur_vert = verticesp + geom_idx;
		LLStrider<LLVector3> cur_norm = normalsp + geom_idx;
		LLStrider<LLVector2> cur_tc = texcoordsp + geom_idx;
		LLStrider<LLColor4U> cur_col = colorsp + geom_idx;
		LLStrider<LLColor4U> cur_glow = emissivep + geom_idx;

		LLColor4U* start_glow = cur_glow.get();

		object->getGeometry(facep->getTEOffset(), cur_vert, cur_norm, cur_tc, cur_col, cur_glow, cur_idx);
		
		BOOL has_glow = FALSE;

		if (cur_glow.get() != start_glow)
		{
			has_glow = TRUE;
		}

		llassert(facep->getGeomCount() == 4);
		llassert(facep->getIndicesCount() == 6);


		vertex_count += facep->getGeomCount();
		index_count += facep->getIndicesCount();

		S32 idx = draw_vec.size()-1;

		BOOL fullbright = facep->isState(LLFace::FULLBRIGHT);
		F32 vsize = facep->getVirtualSize();

		bool batched = false;
	
		U32 bf_src = LLRender::BF_SOURCE_ALPHA;
		U32 bf_dst = LLRender::BF_ONE_MINUS_SOURCE_ALPHA;

		object->getBlendFunc(facep->getTEOffset(), bf_src, bf_dst);

		
		if (idx >= 0)
		{
			LLDrawInfo* info = draw_vec[idx];

			if (info->mTexture == facep->getTexture() &&
				info->mHasGlow == has_glow &&
				info->mFullbright == fullbright &&
				info->mBlendFuncDst == bf_dst &&
				info->mBlendFuncSrc == bf_src)
			{
				if (draw_vec[idx]->mEnd == facep->getGeomIndex()-1)
				{
					batched = true;
					info->mCount += facep->getIndicesCount();
					info->mEnd += facep->getGeomCount();
					info->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
				}
				else if (draw_vec[idx]->mStart == facep->getGeomIndex()+facep->getGeomCount()+1)
				{
					batched = true;
					info->mCount += facep->getIndicesCount();
					info->mStart -= facep->getGeomCount();
					info->mOffset = facep->getIndicesStart();
					info->mVSize = llmax(draw_vec[idx]->mVSize, vsize);
				}
			}
		}


		if (!batched)
		{
			U32 start = facep->getGeomIndex();
			U32 end = start + facep->getGeomCount()-1;
			U32 offset = facep->getIndicesStart();
			U32 count = facep->getIndicesCount();
			LLDrawInfo* info = new LLDrawInfo(start,end,count,offset,facep->getTexture(), 
				//facep->getTexture(),
				buffer, fullbright); 

			const LLVector4a* exts = group->getObjectExtents();
			info->mExtents[0] = exts[0];
			info->mExtents[1] = exts[1];
			info->mVSize = vsize;
			info->mBlendFuncDst = bf_dst;
			info->mBlendFuncSrc = bf_src;
			info->mHasGlow = has_glow;
			info->mParticle = TRUE;
			draw_vec.push_back(info);
			//for alpha sorting
			facep->setDrawInfo(info);
		}
	}

	mFaceList.clear();
}
F32 LLFontGL::getWidthF32(const LLWString& utf32text, const S32 begin_offset, const S32 max_chars, BOOL use_embedded) const
{
	const S32 LAST_CHARACTER = LLFontFreetype::LAST_CHAR_FULL;

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

	F32 cur_x = 0;

	const LLFontGlyphInfo* next_glyph = NULL;

	F32 width_padding = 0.f;
	for (S32 i = begin_offset; i < max_index; i++)
	{
		const llwchar wch = utf32text[i];
		const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
		if (ext_data)
		{
			// Handle crappy embedded hack
			cur_x += getEmbeddedCharAdvance(ext_data);

			if(i+1 < max_index)
			{
				cur_x += EXT_KERNING * sScaleX;
			}
		}
		else
		{
			const LLFontGlyphInfo* fgi = next_glyph;
			next_glyph = NULL;
			if(!fgi)
			{
				fgi = mFontFreetype->getGlyphInfo(wch);
			}

			F32 advance = mFontFreetype->getXAdvance(fgi);

			// for the last character we want to measure the greater of its width and xadvance values
			// so keep track of the difference between these values for the each character we measure
			// so we can fix things up at the end
			width_padding = llmax(	0.f,											// always use positive padding amount
									width_padding - advance,						// previous padding left over after advance of current character
									(F32)(fgi->mWidth + fgi->mXBearing) - advance);	// difference between width of this character and advance to next character

			cur_x += advance;
			if ((i + 1) < max_index)
			{
				llwchar next_char = utf32text[i+1];
				if (next_char < LAST_CHARACTER)
				{
					// Kern this puppy.
					next_glyph = mFontFreetype->getGlyphInfo(next_char);
					cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
				}
			}
			// Round after kerning.
			cur_x = (F32)ll_round(cur_x);
		}
	}

	// add in extra pixels for last character's width past its xadvance
	cur_x += width_padding;

	return cur_x / sScaleX;
}
// Returns the max number of complete characters from text (up to max_chars) that can be drawn in max_pixels
S32 LLFontGL::maxDrawableChars(const LLWString& utf32text, F32 max_pixels, S32 max_chars,
							   EWordWrapStyle end_on_word_boundary, const BOOL use_embedded,
							   F32* drawn_pixels) const
{
	const S32 max_index = llmin(max_chars, S32(utf32text.length()));
	if (max_index <= 0 || max_pixels <= 0.f)
		return 0;
	
	BOOL clip = FALSE;
	F32 cur_x = 0;
	F32 drawn_x = 0;

	S32 start_of_last_word = 0;
	BOOL in_word = FALSE;

	// avoid S32 overflow when max_pixels == S32_MAX by staying in floating point
	F32 scaled_max_pixels =	max_pixels * sScaleX;
	F32 width_padding = 0.f;
	
	LLFontGlyphInfo* next_glyph = NULL;

	S32 i;
	for (i=0; (i < max_index); i++)
	{
		llwchar wch = utf32text[i];
			
		const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
		if (ext_data)
		{
			if (in_word)
			{
				in_word = FALSE;
			}
			else
			{
				start_of_last_word = i;
			}
			cur_x += getEmbeddedCharAdvance(ext_data);
			
			if (scaled_max_pixels < cur_x)
			{
				clip = TRUE;
				break;
			}
			
			if ((i+1) < max_index)
			{
				cur_x += EXT_KERNING * sScaleX;
			}

			if( scaled_max_pixels < cur_x )
			{
				clip = TRUE;
				break;
			}
		}
		else
		{
			if (in_word)
			{
				if (iswspace(wch))
				{
					in_word = FALSE;
				}
			}
			else
			{
				start_of_last_word = i;
				if (!iswspace(wch))
				{
					in_word = TRUE;
				}
			}

			LLFontGlyphInfo* fgi = next_glyph;
			next_glyph = NULL;
			if(!fgi)
			{
				fgi = mFontFreetype->getGlyphInfo(wch);
			}

			// account for glyphs that run beyond the starting point for the next glyphs
			width_padding = llmax(	0.f,													// always use positive padding amount
									width_padding - fgi->mXAdvance,							// previous padding left over after advance of current character
									(F32)(fgi->mWidth + fgi->mXBearing) - fgi->mXAdvance);	// difference between width of this character and advance to next character

			cur_x += fgi->mXAdvance;
		
			// clip if current character runs past scaled_max_pixels (using width_padding)
			if (scaled_max_pixels < cur_x + width_padding)
			{
				clip = TRUE;
				break;
			}

			if ((i+1) < max_index)
			{
				// Kern this puppy.
				next_glyph = mFontFreetype->getGlyphInfo(utf32text[i + 1]);
				cur_x += mFontFreetype->getXKerning(fgi, next_glyph);
			}
		}
		// Round after kerning.
		cur_x = (F32)ll_round(cur_x);
		drawn_x = cur_x;
	}


	if( clip )
	{
		switch (end_on_word_boundary)
		{
		case ONLY_WORD_BOUNDARIES:
			i = start_of_last_word;
			break;
		case WORD_BOUNDARY_IF_POSSIBLE:
			if (start_of_last_word != 0)
			{
				i = start_of_last_word;
			}
			break;
		default:
		case ANYWHERE:
			// do nothing
			break;
		}
	}

	if (drawn_pixels)
	{
		*drawn_pixels = drawn_x;
	}
	return i;
}
LLAlertDialog::LLAlertDialog( LLNotificationPtr notification, bool modal)
	:	LLModalDialog( notification->getLabel(), 100, 100, modal ),  // dummy size.  Will reshape below.
		LLInstanceTracker<LLAlertDialog, LLUUID>(notification->getID()),
		mDefaultButton( NULL ),
		mCheck(NULL),
		mCaution(notification->getPriority() >= NOTIFICATION_PRIORITY_HIGH),
		mLabel(notification->getName()),
		mLineEditor(NULL),
		mNote(notification)
{
	const LLFontGL* font = LLResMgr::getInstance()->getRes( FONT_NAME );
	const S32 LINE_HEIGHT = llfloor(font->getLineHeight() + 0.99f);
	const S32 EDITOR_HEIGHT = 20;

	LLNotificationFormPtr form = mNote->getForm();
	std::string edit_text_name;
	std::string edit_text_contents;
	bool is_password = false;

	setBackgroundVisible(TRUE);
	setBackgroundOpaque(TRUE);

	typedef std::list<ButtonData> options_t;
	options_t options;

	// for now, get LLSD to iterator over form elements
	LLSD form_sd = form->asLLSD();

	for (LLSD::array_const_iterator it = form_sd.beginArray(); it != form_sd.endArray(); ++it)
	{
		std::string type = (*it)["type"].asString();
		if (type == "button")
		{
			options.push_back(ButtonData());
			ButtonData& button_data = options.back();
			button_data.mName = (*it)["name"].asString();
			button_data.mText = (*it)["text"].asString();
			button_data.mDefault = (*it)["default"].asBoolean();
			if(options.size()-1 == mNote->getURLOption())
				button_data.mUrl = mNote->getURL();
		}
		else if (type == "text")
		{
			edit_text_contents = (*it)["value"].asString();
			edit_text_name = (*it)["name"].asString();
		}
		else if (type == "password")
		{
			edit_text_contents = (*it)["value"].asString();
			edit_text_name = (*it)["name"].asString();
			is_password = true;
		}
	}
	// Buttons
	if (options.empty())
	{
		options.push_back(ButtonData());
		ButtonData& button_data = options.back();
		button_data.mName = "close";
		button_data.mText = "Close";
		button_data.mDefault = true;
	}

	S32 num_options = options.size();

	// Calc total width of buttons
	S32 button_width = 0;
	S32 sp = font->getWidth(std::string("OO"));
	for( options_t::iterator it = options.begin(); it != options.end(); it++ )
	{
		S32 w = S32(font->getWidth( it->mText ) + 0.99f) + sp + 2 * LLBUTTON_H_PAD;
		button_width = llmax( w, button_width );
	}
	S32 btn_total_width = button_width;
	if( num_options > 1 )
	{
		btn_total_width = (num_options * button_width) + ((num_options - 1) * BTN_HPAD);
	}

	// Message: create text box using raw string, as text has been structure deliberately
	// Use size of created text box to generate dialog box size
	std::string msg = mNote->getMessage();
	llwarns << "Alert: " << msg << llendl;
	LLTextBox* msg_box = new LLTextBox( std::string("Alert message"), msg, (F32)MAX_ALLOWED_MSG_WIDTH, font );

	const LLRect& text_rect = msg_box->getRect();
	S32 dialog_width = llmax( btn_total_width, text_rect.getWidth() ) + 2 * HPAD;
	S32 dialog_height = text_rect.getHeight() + 3 * VPAD + BTN_HEIGHT;

	if (hasTitleBar())
	{
		dialog_height += LINE_HEIGHT; // room for title bar
	}

	// it's ok for the edit text body to be empty, but we want the name to exist if we're going to draw it
	if (!edit_text_name.empty())
	{
		dialog_height += EDITOR_HEIGHT + VPAD;
		dialog_width = llmax(dialog_width, (S32)(font->getWidth( edit_text_contents ) + 0.99f));
	}

	if (mCaution)
	{
		// Make room for the caution icon.
		dialog_width += 32 + HPAD;
	}

	reshape( dialog_width, dialog_height, FALSE );

	S32 msg_y = getRect().getHeight() - VPAD;
	S32 msg_x = HPAD;
	if (hasTitleBar())
	{
		msg_y -= LINE_HEIGHT; // room for title
	}

	if (mCaution)
	{
		LLIconCtrl* icon = new LLIconCtrl(std::string("icon"), LLRect(msg_x, msg_y, msg_x+32, msg_y-32), std::string("notify_caution_icon.tga"));
		icon->setMouseOpaque(FALSE);
		addChild(icon);
		msg_x += 32 + HPAD;
		msg_box->setColor( LLUI::sColorsGroup->getColor( "AlertCautionTextColor" ) );
	}
	else
	{
		msg_box->setColor( LLUI::sColorsGroup->getColor( "AlertTextColor" ) );
	}

	LLRect rect;
	rect.setLeftTopAndSize( msg_x, msg_y, text_rect.getWidth(), text_rect.getHeight() );
	msg_box->setRect( rect );
	addChild(msg_box);

	// Buttons	
	S32 button_left = (getRect().getWidth() - btn_total_width) / 2;

	for( options_t::iterator it = options.begin(); it != options.end(); it++ )
	{
		LLRect button_rect;
		button_rect.setOriginAndSize( button_left, VPAD, button_width, BTN_HEIGHT );

		ButtonData& button_data = *it;

		LLButton* btn = new LLButton(
			button_data.mName, button_rect,
			"","", "", 
			NULL,
			font,
			button_data.mText, 
			button_data.mText);

		btn->setClickedCallback(boost::bind(&LLAlertDialog::onButtonPressed, this, _1, button_data.mUrl));

		addChild(btn);

		if(!mDefaultButton || button_data.mDefault)
		{
			mDefaultButton = btn;
		}

		button_left += button_width + BTN_HPAD;
	}

	llassert(mDefaultButton); //'options' map should never be empty, thus mDefaultButton should always get set in the above loop.
	mDefaultButton->setFocus(TRUE);


	// (Optional) Edit Box	
	if (!edit_text_name.empty())
	{
		S32 y = VPAD + BTN_HEIGHT + VPAD/2;
		mLineEditor = new LLLineEditor(edit_text_name,
			LLRect( HPAD, y+EDITOR_HEIGHT, dialog_width-HPAD, y),
			edit_text_contents,
			LLFontGL::getFontSansSerif(),
			STD_STRING_STR_LEN);

		// make sure all edit keys get handled properly (DEV-22396)
		mLineEditor->setHandleEditKeysDirectly(TRUE);

		addChild(mLineEditor);
	}
	
	if (mLineEditor)
	{
		mLineEditor->setDrawAsterixes(is_password);

		setEditTextArgs(notification->getSubstitutions());
	}

	std::string ignore_label;

	if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_DEFAULT_RESPONSE)
	{
		setCheckBox(LLNotificationTemplates::instance().getGlobalString("skipnexttime"), ignore_label);
	}
	else if (form->getIgnoreType() == LLNotificationForm::IGNORE_WITH_LAST_RESPONSE)
	{
		setCheckBox(LLNotificationTemplates::instance().getGlobalString("alwayschoose"), ignore_label);
	}
}
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;
}
Beispiel #12
0
BOOL LLThrottleGroup::dynamicAdjust()
{
	const F32Seconds DYNAMIC_ADJUST_TIME(1.0f);
	const F32 CURRENT_PERIOD_WEIGHT = .25f;		// how much weight to give to last period while determining BPS utilization
	const F32 BUSY_PERCENT = 0.75f;		// if use more than this fraction of BPS, you are busy
	const F32 IDLE_PERCENT = 0.70f;		// if use less than this fraction, you are "idle"
	const F32 TRANSFER_PERCENT = 0.90f;	// how much unused bandwidth to take away each adjustment
	const F32 RECOVER_PERCENT = 0.25f;	// how much to give back during recovery phase

	S32 i;

	F64Seconds mt_sec = LLMessageSystem::getMessageTimeSeconds();

	// Only dynamically adjust every few seconds
	if ((mt_sec - mDynamicAdjustTime) < DYNAMIC_ADJUST_TIME)
	{
		return FALSE;
	}
	mDynamicAdjustTime = mt_sec;

	S32 total = 0;
	// Update historical information
	for (i = 0; i < TC_EOF; i++)
	{
		if (mBitsSentHistory[i] == 0)
		{
			// first run, just copy current period
			mBitsSentHistory[i] = mBitsSentThisPeriod[i];
		}
		else
		{
			// have some history, so weight accordingly
			mBitsSentHistory[i] = (1.f - CURRENT_PERIOD_WEIGHT) * mBitsSentHistory[i] 
				+ CURRENT_PERIOD_WEIGHT * mBitsSentThisPeriod[i];
		}

		mBitsSentThisPeriod[i] = 0;
		total += ll_round(mBitsSentHistory[i]);
	}

	// Look for busy channels
	// TODO: Fold into loop above.
	BOOL channels_busy = FALSE;
	F32  busy_nominal_sum = 0;
	BOOL channel_busy[TC_EOF];
	BOOL channel_idle[TC_EOF];
	BOOL channel_over_nominal[TC_EOF];

	for (i = 0; i < TC_EOF; i++)
	{
		// Is this a busy channel?
		if (mBitsSentHistory[i] >= BUSY_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i])
		{
			// this channel is busy
			channels_busy = TRUE;
			busy_nominal_sum += mNominalBPS[i];		// use for allocation of pooled idle bandwidth
			channel_busy[i] = TRUE;
		}
		else
		{
			channel_busy[i] = FALSE;
		}

		// Is this an idle channel?
		if ((mBitsSentHistory[i] < IDLE_PERCENT * DYNAMIC_ADJUST_TIME.value() * mCurrentBPS[i]) &&
			(mBitsAvailable[i] > 0))
		{
			channel_idle[i] = TRUE;
		}
		else
		{
			channel_idle[i] = FALSE;
		}

		// Is this an overpumped channel?
		if (mCurrentBPS[i] > mNominalBPS[i])
		{
			channel_over_nominal[i] = TRUE;
		}
		else
		{
			channel_over_nominal[i] = FALSE;
		}

		//if (total)
		//{
		//	LL_INFOS() << i << ": B" << channel_busy[i] << " I" << channel_idle[i] << " N" << channel_over_nominal[i];
		//	LL_CONT << " Nom: " << mNominalBPS[i] << " Cur: " << mCurrentBPS[i] << " BS: " << mBitsSentHistory[i] << LL_ENDL;
		//}
	}

	if (channels_busy)
	{
		// Some channels are busy.  Let's see if we can get them some bandwidth.
		F32 used_bps;
		F32 avail_bps;
		F32 transfer_bps;

		F32 pool_bps = 0;

		for (i = 0; i < TC_EOF; i++)
		{
			if (channel_idle[i] || channel_over_nominal[i] )
			{
				// Either channel i is idle, or has been overpumped.
				// Therefore it's a candidate to give up some bandwidth.
				// Figure out how much bandwidth it has been using, and how
				// much is available to steal.
				used_bps = mBitsSentHistory[i] / DYNAMIC_ADJUST_TIME.value();

				// CRO make sure to keep a minimum amount of throttle available
				// CRO NB: channels set to < MINIMUM_BPS will never give up bps, 
				// which is correct I think
				if (used_bps < gThrottleMinimumBPS[i])
				{
					used_bps = gThrottleMinimumBPS[i];
				}

				if (channel_over_nominal[i])
				{
					F32 unused_current = mCurrentBPS[i] - used_bps;
					avail_bps = llmax(mCurrentBPS[i] - mNominalBPS[i], unused_current);
				}
				else
				{
					avail_bps = mCurrentBPS[i] - used_bps;
				}

				//LL_INFOS() << i << " avail " << avail_bps << LL_ENDL;

				// Historically, a channel could have used more than its current share,
				// even if it's idle right now.
				// Make sure we don't steal too much.
				if (avail_bps < 0)
				{
					continue;
				}

				// Transfer some bandwidth from this channel into the global pool.
				transfer_bps = avail_bps * TRANSFER_PERCENT;
				mCurrentBPS[i] -= transfer_bps;
				pool_bps += transfer_bps;
			}
		}

		//LL_INFOS() << "Pool BPS: " << pool_bps << LL_ENDL;
		// Now redistribute the bandwidth to busy channels.
		F32 unused_bps = 0.f;

		for (i = 0; i < TC_EOF; i++)
		{
			if (channel_busy[i])
			{
				F32 add_amount = pool_bps * (mNominalBPS[i] / busy_nominal_sum);
				//LL_INFOS() << "Busy " << i << " gets " << pool_bps << LL_ENDL;
				mCurrentBPS[i] += add_amount;

				// CRO: make sure this doesn't get too huge
				// JC - Actually, need to let mCurrentBPS go less than nominal, otherwise
				// you aren't allowing bandwidth to actually be moved from one channel
				// to another.  
				// *TODO: If clamping high end, would be good to re-
				// allocate to other channels in the above code.
				const F32 MAX_BPS = 4 * mNominalBPS[i];
				if (mCurrentBPS[i] > MAX_BPS)
				{
					F32 overage = mCurrentBPS[i] - MAX_BPS;
					mCurrentBPS[i] -= overage;
					unused_bps += overage;
				}

				// Paranoia
				if (mCurrentBPS[i] < gThrottleMinimumBPS[i])
				{
					mCurrentBPS[i] = gThrottleMinimumBPS[i];
				}
			}
		}

		// For fun, add the overage back in to objects
		if (unused_bps > 0.f)
		{
			mCurrentBPS[TC_TASK] += unused_bps;
		}
	}
	else
	{
		// No one is busy.
		// Make the channel allocations seek toward nominal.

		// Look for overpumped channels
		F32 starved_nominal_sum = 0;
		F32 avail_bps = 0;
		F32 transfer_bps = 0;
		F32 pool_bps = 0;
		for (i = 0; i < TC_EOF; i++)
		{
			if (mCurrentBPS[i] > mNominalBPS[i])
			{
				avail_bps = (mCurrentBPS[i] - mNominalBPS[i]);
				transfer_bps = avail_bps * RECOVER_PERCENT;

				mCurrentBPS[i] -= transfer_bps;
				pool_bps += transfer_bps;
			}
		}

		// Evenly distribute bandwidth to channels currently
		// using less than nominal.
		for (i = 0; i < TC_EOF; i++)
		{
			if (mCurrentBPS[i] < mNominalBPS[i])
			{
				// We're going to weight allocations by nominal BPS.
				starved_nominal_sum += mNominalBPS[i];
			}
		}

		for (i = 0; i < TC_EOF; i++)
		{
			if (mCurrentBPS[i] < mNominalBPS[i])
			{
				// Distribute bandwidth according to nominal allocation ratios.
				mCurrentBPS[i] += pool_bps * (mNominalBPS[i] / starved_nominal_sum);
			}
		}
	}
	return TRUE;
}
LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
:	LLComboBox(p),
	mIconHPad(p.icon_hpad),
	mAddLandmarkHPad(p.add_landmark_hpad),
	mLocationContextMenu(NULL),
	mAddLandmarkBtn(NULL),
	mForSaleBtn(NULL),
	mInfoBtn(NULL),
	mLandmarkImageOn(NULL),
	mLandmarkImageOff(NULL),
	mIconMaturityGeneral(NULL),
	mIconMaturityAdult(NULL)
{
	// Lets replace default LLLineEditor with LLLocationLineEditor
	// to make needed escaping while copying and cutting url
	this->removeChild(mTextEntry);
	delete mTextEntry;

	// Can't access old mTextEntry fields as they are protected, so lets build new params
	// That is C&P from LLComboBox::createLineEditor function
	static LLUICachedControl<S32> drop_shadow_button ("DropShadowButton", 0);
	S32 arrow_width = mArrowImage ? mArrowImage->getWidth() : 0;
	LLRect text_entry_rect(0, getRect().getHeight(), getRect().getWidth(), 0);
	text_entry_rect.mRight -= llmax(8,arrow_width) + 2 * drop_shadow_button;

	LLLineEditor::Params params = p.combo_editor;
	params.rect(text_entry_rect);
	params.default_text(LLStringUtil::null);
	params.max_length_bytes(p.max_chars);
	params.keystroke_callback(boost::bind(&LLComboBox::onTextEntry, this, _1));
	params.handle_edit_keys_directly(true);
	params.commit_on_focus_lost(false);
	params.follows.flags(FOLLOWS_ALL);
	mTextEntry = LLUICtrlFactory::create<LLURLLineEditor>(params);
	mTextEntry->setContextMenu(NULL);
	addChild(mTextEntry);
	// LLLineEditor is replaced with LLLocationLineEditor

	// "Place information" button.
	LLButton::Params info_params = p.info_button;
	mInfoBtn = LLUICtrlFactory::create<LLButton>(info_params);
	mInfoBtn->setClickedCallback(boost::bind(&LLLocationInputCtrl::onInfoButtonClicked, this));
	addChild(mInfoBtn);

	// "Add landmark" button.
	LLButton::Params al_params = p.add_landmark_button;

	// Image for unselected state will be set in updateAddLandmarkButton(),
	// it will be either mLandmarkOn or mLandmarkOff
	if (p.add_landmark_image_enabled())
	{
		mLandmarkImageOn = p.add_landmark_image_enabled;
	}
	if (p.add_landmark_image_disabled())
	{
		mLandmarkImageOff = p.add_landmark_image_disabled;
	}

	if(p.add_landmark_image_selected)
	{
		al_params.image_selected = p.add_landmark_image_selected;
	}
	if (p.add_landmark_image_hover())
	{
		al_params.image_hover_unselected = p.add_landmark_image_hover;
	}

	al_params.click_callback.function(boost::bind(&LLLocationInputCtrl::onAddLandmarkButtonClicked, this));
	mAddLandmarkBtn = LLUICtrlFactory::create<LLButton>(al_params);
	enableAddLandmarkButton(true);
	addChild(mAddLandmarkBtn);

	if (p.icon_maturity_general())
	{
		mIconMaturityGeneral = p.icon_maturity_general;
	}
	if (p.icon_maturity_adult())
	{
		mIconMaturityAdult = p.icon_maturity_adult;
	}

	LLIconCtrl::Params maturity_icon = p.maturity_icon;
	mMaturityIcon = LLUICtrlFactory::create<LLIconCtrl>(maturity_icon);
	addChild(mMaturityIcon);

	LLButton::Params for_sale_button = p.for_sale_button;
	for_sale_button.tool_tip = LLTrans::getString("LocationCtrlForSaleTooltip");
	for_sale_button.click_callback.function(
		boost::bind(&LLLocationInputCtrl::onForSaleButtonClicked, this));
	mForSaleBtn = LLUICtrlFactory::create<LLButton>( for_sale_button );
	addChild(mForSaleBtn);

	// Parcel property icons
	// Must be mouse-opaque so cursor stays as an arrow when hovering to
	// see tooltip.
	LLIconCtrl::Params voice_icon = p.voice_icon;
	voice_icon.tool_tip = LLTrans::getString("LocationCtrlVoiceTooltip");
	voice_icon.mouse_opaque = true;
	mParcelIcon[VOICE_ICON] = LLUICtrlFactory::create<LLIconCtrl>(voice_icon);
	mParcelIcon[VOICE_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, VOICE_ICON));
	addChild(mParcelIcon[VOICE_ICON]);

	LLIconCtrl::Params fly_icon = p.fly_icon;
	fly_icon.tool_tip = LLTrans::getString("LocationCtrlFlyTooltip");
	fly_icon.mouse_opaque = true;
	mParcelIcon[FLY_ICON] = LLUICtrlFactory::create<LLIconCtrl>(fly_icon);
	mParcelIcon[FLY_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, FLY_ICON));
	addChild(mParcelIcon[FLY_ICON]);

	LLIconCtrl::Params push_icon = p.push_icon;
	push_icon.tool_tip = LLTrans::getString("LocationCtrlPushTooltip");
	push_icon.mouse_opaque = true;
	mParcelIcon[PUSH_ICON] = LLUICtrlFactory::create<LLIconCtrl>(push_icon);
	mParcelIcon[PUSH_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, PUSH_ICON));
	addChild(mParcelIcon[PUSH_ICON]);

	LLIconCtrl::Params build_icon = p.build_icon;
	build_icon.tool_tip = LLTrans::getString("LocationCtrlBuildTooltip");
	build_icon.mouse_opaque = true;
	mParcelIcon[BUILD_ICON] = LLUICtrlFactory::create<LLIconCtrl>(build_icon);
	mParcelIcon[BUILD_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, BUILD_ICON));
	addChild(mParcelIcon[BUILD_ICON]);

	LLIconCtrl::Params scripts_icon = p.scripts_icon;
	scripts_icon.tool_tip = LLTrans::getString("LocationCtrlScriptsTooltip");
	scripts_icon.mouse_opaque = true;
	mParcelIcon[SCRIPTS_ICON] = LLUICtrlFactory::create<LLIconCtrl>(scripts_icon);
	mParcelIcon[SCRIPTS_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, SCRIPTS_ICON));
	addChild(mParcelIcon[SCRIPTS_ICON]);

	LLIconCtrl::Params damage_icon = p.damage_icon;
	damage_icon.tool_tip = LLTrans::getString("LocationCtrlDamageTooltip");
	damage_icon.mouse_opaque = true;
	mParcelIcon[DAMAGE_ICON] = LLUICtrlFactory::create<LLIconCtrl>(damage_icon);
	mParcelIcon[DAMAGE_ICON]->setMouseDownCallback(boost::bind(&LLLocationInputCtrl::onParcelIconClick, this, DAMAGE_ICON));
	addChild(mParcelIcon[DAMAGE_ICON]);
	
	LLTextBox::Params damage_text = p.damage_text;
	damage_text.tool_tip = LLTrans::getString("LocationCtrlDamageTooltip");
	damage_text.mouse_opaque = true;
	mDamageText = LLUICtrlFactory::create<LLTextBox>(damage_text);
	addChild(mDamageText);
	
	// Register callbacks and load the location field context menu (NB: the order matters).
	LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("Navbar.Action", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemClicked, this, _2));
	LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("Navbar.EnableMenuItem", boost::bind(&LLLocationInputCtrl::onLocationContextMenuItemEnabled, this, _2));
		
	setPrearrangeCallback(boost::bind(&LLLocationInputCtrl::onLocationPrearrange, this, _2));
	getTextEntry()->setMouseUpCallback(boost::bind(&LLLocationInputCtrl::changeLocationPresentation, this));

	// Load the location field context menu
	mLocationContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_navbar.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
	if (!mLocationContextMenu)
	{
		llwarns << "Error loading navigation bar context menu" << llendl;
		
	}
	getTextEntry()->setRightMouseUpCallback(boost::bind(&LLLocationInputCtrl::onTextEditorRightClicked,this,_2,_3,_4));
	updateWidgetlayout();

	// Connecting signal for updating location on "Show Coordinates" setting change.
	LLControlVariable* coordinates_control = gSavedSettings.getControl("NavBarShowCoordinates").get();
	if (coordinates_control)
	{
		mCoordinatesControlConnection = coordinates_control->getSignal()->connect(boost::bind(&LLLocationInputCtrl::refreshLocation, this));
	}

	// Connecting signal for updating parcel icons on "Show Parcel Properties" setting change.
	LLControlVariable* parcel_properties_control = gSavedSettings.getControl("NavBarShowParcelProperties").get();
	if (parcel_properties_control)
	{
		mParcelPropertiesControlConnection = parcel_properties_control->getSignal()->connect(boost::bind(&LLLocationInputCtrl::refreshParcelIcons, this));
	}

	// - Make the "Add landmark" button updated when either current parcel gets changed
	//   or a landmark gets created or removed from the inventory.
	// - Update the location string on parcel change.
	mParcelMgrConnection = LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(
		boost::bind(&LLLocationInputCtrl::onAgentParcelChange, this));
	// LLLocationHistory instance is being created before the location input control, so we have to update initial state of button manually.
	mButton->setEnabled(LLLocationHistory::instance().getItemCount() > 0);
	mLocationHistoryConnection = LLLocationHistory::getInstance()->setChangedCallback(
			boost::bind(&LLLocationInputCtrl::onLocationHistoryChanged, this,_1));

	mRemoveLandmarkObserver	= new LLRemoveLandmarkObserver(this);
	mAddLandmarkObserver	= new LLAddLandmarkObserver(this);
	gInventory.addObserver(mRemoveLandmarkObserver);
	gInventory.addObserver(mAddLandmarkObserver);

	mParcelChangeObserver = new LLParcelChangeObserver(this);
	LLViewerParcelMgr::getInstance()->addObserver(mParcelChangeObserver);

	mAddLandmarkTooltip = LLTrans::getString("LocationCtrlAddLandmarkTooltip");
	mEditLandmarkTooltip = LLTrans::getString("LocationCtrlEditLandmarkTooltip");
	getChild<LLView>("Location History")->setToolTip(LLTrans::getString("LocationCtrlComboBtnTooltip"));
	getChild<LLView>("Place Information")->setToolTip(LLTrans::getString("LocationCtrlInfoBtnTooltip"));
}
Beispiel #14
0
BOOL LLSurface::generateWaterTexture(const F32 x, const F32 y,
                                     const F32 width, const F32 height)
{
    if (!getWaterTexture())
    {
        return FALSE;
    }

    S32 tex_width = mWaterTexturep->getWidth();
    S32 tex_height = mWaterTexturep->getHeight();
    S32 tex_comps = mWaterTexturep->getComponents();
    S32 tex_stride = tex_width * tex_comps;
    LLPointer<LLImageRaw> raw = new LLImageRaw(tex_width, tex_height, tex_comps);
    U8 *rawp = raw->getData();

    F32 scale = 256.f * getMetersPerGrid() / (F32)tex_width;
    F32 scale_inv = 1.f / scale;

    S32 x_begin, y_begin, x_end, y_end;

    x_begin = llround(x * scale_inv);
    y_begin = llround(y * scale_inv);
    x_end = llround((x + width) * scale_inv);
    y_end = llround((y + width) * scale_inv);

    if (x_end > tex_width)
    {
        x_end = tex_width;
    }
    if (y_end > tex_width)
    {
        y_end = tex_width;
    }

    LLVector3d origin_global = from_region_handle(getRegion()->getHandle());

    // OK, for now, just have the composition value equal the height at the point.
    LLVector3 location;
    LLColor4U coloru;

    const F32 WATER_HEIGHT = getWaterHeight();

    S32 i, j, offset;
    for (j = y_begin; j < y_end; j++)
    {
        for (i = x_begin; i < x_end; i++)
        {
            //F32 nv[2];
            //nv[0] = i/256.f;
            //nv[1] = j/256.f;
            // const S32 modulation = noise2(nv)*40;
            offset = j*tex_stride + i*tex_comps;
            location.mV[VX] = i*scale;
            location.mV[VY] = j*scale;

            // Sample multiple points
            const F32 height = resolveHeightRegion(location);

            if (height > WATER_HEIGHT)
            {
                // Above water...
                coloru = MAX_WATER_COLOR;
                coloru.mV[3] = ABOVE_WATERLINE_ALPHA;
                *(rawp + offset++) = coloru.mV[0];
                *(rawp + offset++) = coloru.mV[1];
                *(rawp + offset++) = coloru.mV[2];
                *(rawp + offset++) = coloru.mV[3];
            }
            else
            {
                // Want non-linear curve for transparency gradient
                coloru = MAX_WATER_COLOR;
                const F32 frac = 1.f - 2.f/(2.f - (height - WATER_HEIGHT));
                S32 alpha = 64 + llround((255-64)*frac);

                alpha = llmin(llround((F32)MAX_WATER_COLOR.mV[3]), alpha);
                alpha = llmax(64, alpha);

                coloru.mV[3] = alpha;
                *(rawp + offset++) = coloru.mV[0];
                *(rawp + offset++) = coloru.mV[1];
                *(rawp + offset++) = coloru.mV[2];
                *(rawp + offset++) = coloru.mV[3];
            }
        }
    }

    if (!mWaterTexturep->hasGLTexture())
    {
        mWaterTexturep->createGLTexture(0, raw);
    }
    mWaterTexturep->setSubImage(raw, x_begin, y_begin, x_end - x_begin, y_end - y_begin);
    return TRUE;
}
//-----------------------------------------------------------------------------
// updateMotion()
//-----------------------------------------------------------------------------
void LLMotionController::updateMotions(bool force_update)
{
	BOOL use_quantum = (mTimeStep != 0.f);

	// Always update mPrevTimerElapsed
	F32 cur_time = mTimer.getElapsedTimeF32();
	F32 delta_time = cur_time - mPrevTimerElapsed;
	mPrevTimerElapsed = cur_time;
	mLastTime = mAnimTime;

	// Always cap the number of loaded motions
	purgeExcessMotions();
	
	// Update timing info for this time step.
	if (!mPaused)
	{
		F32 update_time = mAnimTime + delta_time * mTimeFactor;
		if (use_quantum)
		{
			F32 time_interval = fmodf(update_time, mTimeStep);

			// always animate *ahead* of actual time
			S32 quantum_count = llmax(0, llfloor((update_time - time_interval) / mTimeStep)) + 1;
			if (quantum_count == mTimeStepCount)
			{
				// we're still in same time quantum as before, so just interpolate and exit
				if (!mPaused)
				{
					F32 interp = time_interval / mTimeStep;
					mPoseBlender.interpolate(interp - mLastInterp);
					mLastInterp = interp;
				}

				updateLoadingMotions();

				return;
			}
			
			// is calculating a new keyframe pose, make sure the last one gets applied
			mPoseBlender.interpolate(1.f);
			clearBlenders();

			mTimeStepCount = quantum_count;
			mAnimTime = (F32)quantum_count * mTimeStep;
			mLastInterp = 0.f;
		}
		else
		{
			mAnimTime = update_time;
		}
	}

	updateLoadingMotions();

	resetJointSignatures();

	if (mPaused && !force_update)
	{
		updateIdleActiveMotions();
	}
	else
	{
		// update additive motions
		updateAdditiveMotions();
		resetJointSignatures();

		// update all regular motions
		updateRegularMotions();

		if (use_quantum)
		{
			mPoseBlender.blendAndCache(TRUE);
		}
		else
		{
			mPoseBlender.blendAndApply();
		}
	}

	mHasRunOnce = TRUE;
//	llinfos << "Motion controller time " << motionTimer.getElapsedTimeF32() << llendl;
}
S32	LLFontGL::firstDrawableChar(const LLWString& utf32text, F32 max_pixels, S32 start_pos, S32 max_chars) const
{
	const S32 max_index = llmin(llmax(max_chars, start_pos + max_chars), S32(utf32text.length()));
	if (max_index <= 0 || start_pos >= max_index || max_pixels <= 0.f || start_pos < 0)
		return 0;
	
	F32 total_width = 0.0;
	S32 drawable_chars = 0;

	F32 scaled_max_pixels =	max_pixels * sScaleX;

	S32 start = llmin(start_pos, max_index - 1);
	for (S32 i = start; i >= 0; i--)
	{
		llwchar wch = utf32text[i];

		const embedded_data_t* ext_data = getEmbeddedCharData(wch);
		F32 width = 0;
		
		if(ext_data)
		{
			width = getEmbeddedCharAdvance(ext_data);
		}
		else
		{
			const LLFontGlyphInfo* fgi= mFontFreetype->getGlyphInfo(wch);

			// last character uses character width, since the whole character needs to be visible
			// other characters just use advance
			width = (i == start) 
				? (F32)(fgi->mWidth + fgi->mXBearing)  	// use actual width for last character
				: fgi->mXAdvance;						// use advance for all other characters										
		}

		if( scaled_max_pixels < (total_width + width) )
		{
			break;
		}

		total_width += width;
		drawable_chars++;

		if( max_index >= 0 && drawable_chars >= max_index )
		{
			break;
		}

		if ( i > 0 )
		{
			// kerning
			total_width += ext_data ? (EXT_KERNING * sScaleX) : mFontFreetype->getXKerning(utf32text[i - 1], wch);
		}

		// Round after kerning.
		total_width = (F32)ll_round(total_width);
	}

	if (drawable_chars == 0)
	{
		return start_pos; // just draw last character
	}
	else
	{
		// if only 1 character is drawable, we want to return start_pos as the first character to draw
		// if 2 are drawable, return start_pos and character before start_pos, etc.
		return start_pos + 1 - drawable_chars;
	}
	
}
Beispiel #17
0
void LLMediaCtrl::draw()
{
	if ( gRestoreGL == 1 )
	{
		LLRect r = getRect();
		reshape( r.getWidth(), r.getHeight(), FALSE );
		return;
	}

	// NOTE: optimization needed here - probably only need to do this once
	// unless tearoffs change the parent which they probably do.
	const LLUICtrl* ptr = findRootMostFocusRoot();
	if ( ptr && ptr->hasFocus() )
	{
		setFrequentUpdates( true );
	}
	else
	{
		setFrequentUpdates( false );
	};

	// alpha off for this
	LLGLSUIDefault gls_ui;
	LLGLDisable gls_alphaTest( GL_ALPHA_TEST );

	bool draw_media = false;
	
	LLPluginClassMedia* media_plugin = NULL;
	LLViewerMediaTexture* media_texture = NULL;
	
	if(mMediaSource && mMediaSource->hasMedia())
	{
		media_plugin = mMediaSource->getMediaPlugin();

		if(media_plugin && (media_plugin->textureValid()))
		{
			media_texture = LLViewerTextureManager::findMediaTexture(mMediaTextureID);
			if(media_texture)
			{
				draw_media = true;
			}
		}
	}
	
	bool background_visible = isBackgroundVisible();
	bool background_opaque = isBackgroundOpaque();
	
	if(draw_media)
	{
		gGL.pushUIMatrix();
		{
			mMediaSource->setPageZoomFactor( LLUI::getScaleFactor().mV[ VX ] );

			// scale texture to fit the space using texture coords
			gGL.getTexUnit(0)->bind(media_texture);
			LLColor4 media_color = LLColor4::white;
			gGL.color4fv( media_color.mV );
			F32 max_u = ( F32 )media_plugin->getWidth() / ( F32 )media_plugin->getTextureWidth();
			F32 max_v = ( F32 )media_plugin->getHeight() / ( F32 )media_plugin->getTextureHeight();

			LLRect r = getRect();
			S32 width, height;
			S32 x_offset = 0;
			S32 y_offset = 0;
		
			if(mStretchToFill)
			{
				if(mMaintainAspectRatio)
				{
					F32 media_aspect = (F32)(media_plugin->getWidth()) / (F32)(media_plugin->getHeight());
					F32 view_aspect = (F32)(r.getWidth()) / (F32)(r.getHeight());
					if(media_aspect > view_aspect)
					{
						// max width, adjusted height
						width = r.getWidth();
						height = llmin(llmax(llround(width / media_aspect), 0), r.getHeight());
					}
					else
					{
						// max height, adjusted width
						height = r.getHeight();
						width = llmin(llmax(llround(height * media_aspect), 0), r.getWidth());
					}
				}
				else
				{
					width = r.getWidth();
					height = r.getHeight();
				}
			}
			else
			{
				width = llmin(media_plugin->getWidth(), r.getWidth());
				height = llmin(media_plugin->getHeight(), r.getHeight());
			}
			
			x_offset = (r.getWidth() - width) / 2;
			y_offset = (r.getHeight() - height) / 2;		

			/*if (mIgnoreUIScale)
			{
				x_offset = llround((F32)x_offset * LLUI::getScaleFactor().mV[VX]);
				y_offset = llround((F32)y_offset * LLUI::getScaleFactor().mV[VY]);
				width = llround((F32)width * LLUI::getScaleFactor().mV[VX]);
				height = llround((F32)height * LLUI::getScaleFactor().mV[VY]);
			}*/

			// draw the browser
			gGL.setSceneBlendType(LLRender::BT_REPLACE);
			gGL.begin( LLRender::QUADS );
			if (! media_plugin->getTextureCoordsOpenGL())
			{
				// render using web browser reported width and height, instead of trying to invert GL scale
				gGL.texCoord2f( max_u, 0.f );
				gGL.vertex2i( x_offset + width, y_offset + height );

				gGL.texCoord2f( 0.f, 0.f );
				gGL.vertex2i( x_offset, y_offset + height );

				gGL.texCoord2f( 0.f, max_v );
				gGL.vertex2i( x_offset, y_offset );

				gGL.texCoord2f( max_u, max_v );
				gGL.vertex2i( x_offset + width, y_offset );
			}
			else
			{
				// render using web browser reported width and height, instead of trying to invert GL scale
				gGL.texCoord2f( max_u, max_v );
				gGL.vertex2i( x_offset + width, y_offset + height );

				gGL.texCoord2f( 0.f, max_v );
				gGL.vertex2i( x_offset, y_offset + height );

				gGL.texCoord2f( 0.f, 0.f );
				gGL.vertex2i( x_offset, y_offset );

				gGL.texCoord2f( max_u, 0.f );
				gGL.vertex2i( x_offset + width, y_offset );
			}
			gGL.end();
			gGL.setSceneBlendType(LLRender::BT_ALPHA);
		}
		gGL.popUIMatrix();
	
	}
	else
	{
		// Setting these will make LLPanel::draw draw the opaque background color.
		setBackgroundVisible(true);
		setBackgroundOpaque(true);
	}
	
	// highlight if keyboard focus here. (TODO: this needs some work)
	if ( mBorder && mBorder->getVisible() )
		mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) );

	LLPanel::draw();

	// Restore the previous values
	setBackgroundVisible(background_visible);
	setBackgroundOpaque(background_opaque);
}
S32 LLFontGL::charFromPixelOffset(const LLWString& utf32text, const S32 begin_offset, F32 target_x, F32 max_pixels, S32 max_chars, BOOL round, BOOL use_embedded) const
{
	const S32 max_index = llmin(llmax(max_chars,begin_offset + max_chars), S32(utf32text.length()));
	if (max_index <= 0 || begin_offset >= max_index || max_pixels <= 0.f)
		return 0;
	
	F32 cur_x = 0;

	target_x *= sScaleX;

	F32 scaled_max_pixels =	max_pixels * sScaleX;
	
	const LLFontGlyphInfo* next_glyph = NULL;

	S32 pos;
	for (pos = begin_offset; pos < max_index; pos++)
	{
		llwchar wch = utf32text[pos];
		if (!wch)
		{
			break; // done
		}

		const embedded_data_t* ext_data = use_embedded ? getEmbeddedCharData(wch) : NULL;
		const LLFontGlyphInfo* glyph = next_glyph;
		next_glyph = NULL;
		if(!glyph && !ext_data)
		{
			glyph = mFontFreetype->getGlyphInfo(wch);
		}
		
		F32 char_width = ext_data ? getEmbeddedCharAdvance(ext_data) : mFontFreetype->getXAdvance(glyph);

		if (round)
		{
			// Note: if the mouse is on the left half of the character, the pick is to the character's left
			// If it's on the right half, the pick is to the right.
			if (target_x  < cur_x + char_width*0.5f)
			{
				break;
			}
		}
		else if (target_x  < cur_x + char_width)
		{
			break;
		}

		if (scaled_max_pixels < cur_x + char_width)
		{
			break;
		}

		cur_x += char_width;

		if ((pos + 1) < max_index)
		{
			
			if(ext_data)
			{
				cur_x += EXT_KERNING * sScaleX;
			}
			else
			{
				next_glyph = mFontFreetype->getGlyphInfo(utf32text[pos + 1]);
				cur_x += mFontFreetype->getXKerning(glyph, next_glyph);
			}
		}


		// Round after kerning.
		cur_x = (F32)ll_round(cur_x);
		
	}

	return pos - begin_offset;
}
Beispiel #19
0
BOOL LLVOPartGroup::updateGeometry(LLDrawable *drawable)
{
	LL_RECORD_BLOCK_TIME(FTM_UPDATE_PARTICLES);

	dirtySpatialGroup();
	
	S32 num_parts = mViewerPartGroupp->getCount();
	LLFace *facep;
	LLSpatialGroup* group = drawable->getSpatialGroup();
	if (!group && num_parts)
	{
		drawable->movePartition();
		group = drawable->getSpatialGroup();
	}

	if (group && group->isVisible())
	{
		dirtySpatialGroup(TRUE);
	}

	if (!num_parts)
	{
		if (group && drawable->getNumFaces())
		{
			group->setState(LLSpatialGroup::GEOM_DIRTY);
		}
		drawable->setNumFaces(0, NULL, getTEImage(0));
		LLPipeline::sCompiles++;
		return TRUE;
	}

 	if (!(gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_PARTICLES)))
	{
		return TRUE;
	}

	if (num_parts > drawable->getNumFaces())
	{
		drawable->setNumFacesFast(num_parts+num_parts/4, NULL, getTEImage(0));
	}

	F32 tot_area = 0;

	F32 max_area = LLViewerPartSim::getMaxPartCount() * MAX_PARTICLE_AREA_SCALE; 
	F32 pixel_meter_ratio = LLViewerCamera::getInstance()->getPixelMeterRatio();
	pixel_meter_ratio *= pixel_meter_ratio;

	LLViewerPartSim::checkParticleCount(mViewerPartGroupp->mParticles.size()) ;

	S32 count=0;
	mDepth = 0.f;
	S32 i = 0 ;
	LLVector3 camera_agent = getCameraPosition();
	
	F32 max_scale = 0.f;


	for (i = 0 ; i < (S32)mViewerPartGroupp->mParticles.size(); i++)
	{
		const LLViewerPart *part = mViewerPartGroupp->mParticles[i];


		//remember the largest particle
		max_scale = llmax(max_scale, part->mScale.mV[0], part->mScale.mV[1]);

		if (part->mFlags & LLPartData::LL_PART_RIBBON_MASK)
		{ //include ribbon segment length in scale
			const LLVector3* pos_agent = NULL;
			if (part->mParent)
			{
				pos_agent = &(part->mParent->mPosAgent);
			}
			else if (part->mPartSourcep.notNull())
			{
				pos_agent = &(part->mPartSourcep->mPosAgent);
			}

			if (pos_agent)
			{
				F32 dist = (*pos_agent-part->mPosAgent).length();

				max_scale = llmax(max_scale, dist);
			}
		}

		LLVector3 part_pos_agent(part->mPosAgent);
		LLVector3 at(part_pos_agent - camera_agent);

		
		F32 camera_dist_squared = at.lengthSquared();
		F32 inv_camera_dist_squared;
		if (camera_dist_squared > 1.f)
			inv_camera_dist_squared = 1.f / camera_dist_squared;
		else
			inv_camera_dist_squared = 1.f;

		llassert(llfinite(inv_camera_dist_squared));
		llassert(!llisnan(inv_camera_dist_squared));

		F32 area = part->mScale.mV[0] * part->mScale.mV[1] * inv_camera_dist_squared;
		tot_area = llmax(tot_area, area);
 		
		if (tot_area > max_area)
		{
			break;
		}
	
		count++;

		facep = drawable->getFace(i);
		if (!facep)
		{
			LL_WARNS() << "No face found for index " << i << "!" << LL_ENDL;
			continue;
		}

		facep->setTEOffset(i);
		const F32 NEAR_PART_DIST_SQ = 5.f*5.f;  // Only discard particles > 5 m from the camera
		const F32 MIN_PART_AREA = .005f*.005f;  // only less than 5 mm x 5 mm at 1 m from camera
		
		if (camera_dist_squared > NEAR_PART_DIST_SQ && area < MIN_PART_AREA)
		{
			facep->setSize(0, 0);
			continue;
		}

		facep->setSize(4, 6);
		
		facep->setViewerObject(this);

		if (part->mFlags & LLPartData::LL_PART_EMISSIVE_MASK)
		{
			facep->setState(LLFace::FULLBRIGHT);
		}
		else
		{
			facep->clearState(LLFace::FULLBRIGHT);
		}

		facep->mCenterLocal = part->mPosAgent;
		facep->setFaceColor(part->mColor);
		facep->setTexture(part->mImagep);
			
		//check if this particle texture is replaced by a parcel media texture.
		if(part->mImagep.notNull() && part->mImagep->hasParcelMedia()) 
		{
			part->mImagep->getParcelMedia()->addMediaToFace(facep) ;
		}

		mPixelArea = tot_area * pixel_meter_ratio;
		const F32 area_scale = 10.f; // scale area to increase priority a bit
		facep->setVirtualSize(mPixelArea*area_scale);
	}
	for (i = count; i < drawable->getNumFaces(); i++)
	{
		LLFace* facep = drawable->getFace(i);
		if (!facep)
		{
			LL_WARNS() << "No face found for index " << i << "!" << LL_ENDL;
			continue;
		}
		facep->setTEOffset(i);
		facep->setSize(0, 0);
	}

	//record max scale (used to stretch bounding box for visibility culling)
	
	mScale.set(max_scale, max_scale, max_scale);

	mDrawable->movePartition();
	LLPipeline::sCompiles++;
	return TRUE;
}
void	LLAccordionCtrl::arrangeSinge()
{
	S32 panel_left = BORDER_MARGIN;	  // Margin from left side of Splitter
	S32 panel_top = getRect().getHeight() - BORDER_MARGIN;		  // Top coordinate of the first panel
	S32 panel_width = getRect().getWidth() - 4;		  // Top coordinate of the first panel
	S32 panel_height;

	S32 collapsed_height = 0;

	for(size_t i=0;i<mAccordionTabs.size();++i)
	{
		LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
		
		if(accordion_tab->getVisible() == false) //skip hidden accordion tabs
			continue;
		if(!accordion_tab->isExpanded() )
		{
			collapsed_height+=mAccordionTabs[i]->getRect().getHeight();
		}
	}

	S32 expanded_height = getRect().getHeight() - BORDER_MARGIN - collapsed_height;
	
	for(size_t i=0;i<mAccordionTabs.size();++i)
	{
		LLAccordionCtrlTab* accordion_tab = dynamic_cast<LLAccordionCtrlTab*>(mAccordionTabs[i]);
		
		if(accordion_tab->getVisible() == false) //skip hidden accordion tabs
			continue;
		if(!accordion_tab->isExpanded() )
		{
			panel_height = accordion_tab->getRect().getHeight();
		}
		else
		{
			if(mFitParent)
			{
				panel_height = expanded_height;
			}
			else
			{
				if(accordion_tab->getAccordionView())
				{
					panel_height = accordion_tab->getAccordionView()->getRect().getHeight() + 
						accordion_tab->getHeaderHeight() + 2*BORDER_MARGIN;
				}
				else
				{
					panel_height = accordion_tab->getRect().getHeight();
				}
			}
		}

		// make sure at least header is shown
		panel_height = llmax(panel_height, accordion_tab->getHeaderHeight());

		ctrlSetLeftTopAndSize(mAccordionTabs[i], panel_left, panel_top, panel_width, panel_height);
		panel_top-=mAccordionTabs[i]->getRect().getHeight();
	}

	show_hide_scrollbar(getRect().getWidth(), getRect().getHeight());
	updateLayout(getRect().getWidth(), getRect().getHeight());
}
Beispiel #21
0
// True if you selected an object.
BOOL LLToolPie::pickLeftMouseDownCallback()
{
	S32 x = mPick.mMousePt.mX;
	S32 y = mPick.mMousePt.mY;
	MASK mask = mPick.mKeyMask;
	if (mPick.mPickType == LLPickInfo::PICK_PARCEL_WALL)
	{
		LLParcel* parcel = LLViewerParcelMgr::getInstance()->getCollisionParcel();
		if (parcel)
		{
			LLViewerParcelMgr::getInstance()->selectCollisionParcel();
			if (parcel->getParcelFlag(PF_USE_PASS_LIST) 
				&& !LLViewerParcelMgr::getInstance()->isCollisionBanned())
			{
				// if selling passes, just buy one
				void* deselect_when_done = (void*)TRUE;
				LLPanelLandGeneral::onClickBuyPass(deselect_when_done);
			}
			else
			{
				// not selling passes, get info
				LLFloaterReg::showInstance("about_land");
			}
		}

		gFocusMgr.setKeyboardFocus(NULL);
		return LLTool::handleMouseDown(x, y, mask);
	}

	// didn't click in any UI object, so must have clicked in the world
	LLViewerObject *object = mPick.getObject();
	LLViewerObject *parent = NULL;

	if (mPick.mPickType != LLPickInfo::PICK_LAND)
	{
		LLViewerParcelMgr::getInstance()->deselectLand();
	}
	
	if (object)
	{
		parent = object->getRootEdit();
	}

	if (handleMediaClick(mPick))
	{
		return TRUE;
	}

	// If it's a left-click, and we have a special action, do it.
	if (useClickAction(mask, object, parent))
	{
		mClickAction = 0;
		if (object && object->getClickAction()) 
		{
			mClickAction = object->getClickAction();
		}
		else if (parent && parent->getClickAction()) 
		{
			mClickAction = parent->getClickAction();
		}

		switch(mClickAction)
		{
		case CLICK_ACTION_TOUCH:
			// touch behavior down below...
			break;
		case CLICK_ACTION_SIT:
			{
				if (isAgentAvatarValid() && !gAgentAvatarp->isSitting()) // agent not already sitting
				{
					handle_object_sit_or_stand();
					// put focus in world when sitting on an object
					gFocusMgr.setKeyboardFocus(NULL);
					return TRUE;
				} // else nothing (fall through to touch)
			}
		case CLICK_ACTION_PAY:
			if ((object && object->flagTakesMoney())
				|| (parent && parent->flagTakesMoney()))
			{
				// pay event goes to object actually clicked on
				mClickActionObject = object;
				mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);
				if (LLSelectMgr::getInstance()->selectGetAllValid())
				{
					// call this right away, since we have all the info we need to continue the action
					selectionPropertiesReceived();
				}
				return TRUE;
			}
			break;
		case CLICK_ACTION_BUY:
			mClickActionObject = parent;
			mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE, TRUE);
			if (LLSelectMgr::getInstance()->selectGetAllValid())
			{
				// call this right away, since we have all the info we need to continue the action
				selectionPropertiesReceived();
			}
			return TRUE;
		case CLICK_ACTION_OPEN:
			if (parent && parent->allowOpen())
			{
				mClickActionObject = parent;
				mLeftClickSelection = LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE, TRUE);
				if (LLSelectMgr::getInstance()->selectGetAllValid())
				{
					// call this right away, since we have all the info we need to continue the action
					selectionPropertiesReceived();
				}
			}
			return TRUE;	
		case CLICK_ACTION_PLAY:
			handle_click_action_play();
			return TRUE;
		case CLICK_ACTION_OPEN_MEDIA:
			// mClickActionObject = object;
			handle_click_action_open_media(object);
			return TRUE;
		case CLICK_ACTION_ZOOM:
			{	
				const F32 PADDING_FACTOR = 2.f;
				LLViewerObject* object = gObjectList.findObject(mPick.mObjectID);
				
				if (object)
				{
					gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
					
					LLBBox bbox = object->getBoundingBoxAgent() ;
					F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView());
					F32 distance = bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view);
				
					LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - bbox.getCenterAgent();
					obj_to_cam.normVec();
					
					LLVector3d object_center_global = gAgent.getPosGlobalFromAgent(bbox.getCenterAgent());
					gAgentCamera.setCameraPosAndFocusGlobal(object_center_global + LLVector3d(obj_to_cam * distance), 
													  object_center_global, 
													  mPick.mObjectID );
				}
			}
			return TRUE;			
		default:
			// nothing
			break;
		}
	}

	// put focus back "in world"
	gFocusMgr.setKeyboardFocus(NULL);

	BOOL touchable = (object && object->flagHandleTouch()) 
					 || (parent && parent->flagHandleTouch());

	// Switch to grab tool if physical or triggerable
	if (object && 
		!object->isAvatar() && 
		((object->usePhysics() || (parent && !parent->isAvatar() && parent->usePhysics())) || touchable) 
		)
	{
		gGrabTransientTool = this;
		LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() );
		return LLToolGrab::getInstance()->handleObjectHit( mPick );
	}
	
	LLHUDIcon* last_hit_hud_icon = mPick.mHUDIcon;
	if (!object && last_hit_hud_icon && last_hit_hud_icon->getSourceObject())
	{
		LLFloaterScriptDebug::show(last_hit_hud_icon->getSourceObject()->getID());
	}

	// If left-click never selects or spawns a menu
	// Eat the event.
	if (!gSavedSettings.getBOOL("LeftClickShowMenu"))
	{
		// mouse already released
		if (!mGrabMouseButtonDown)
		{
			return TRUE;
		}

		while( object && object->isAttachment() && !object->flagHandleTouch())
		{
			// don't pick avatar through hud attachment
			if (object->isHUDAttachment())
			{
				break;
			}
			object = (LLViewerObject*)object->getParent();
		}
		if (object && object == gAgentAvatarp)
		{
			// we left clicked on avatar, switch to focus mode
			LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance());
			gViewerWindow->hideCursor();
			LLToolCamera::getInstance()->setMouseCapture(TRUE);
			LLToolCamera::getInstance()->pickCallback(mPick);
			gAgentCamera.setFocusOnAvatar(TRUE, TRUE);

			return TRUE;
		}
	//////////
	//	// Could be first left-click on nothing
	//	LLFirstUse::useLeftClickNoHit();
	/////////
		
		// Eat the event
		return LLTool::handleMouseDown(x, y, mask);
	}

	if (gAgent.leftButtonGrabbed())
	{
		// if the left button is grabbed, don't put up the pie menu
		return LLTool::handleMouseDown(x, y, mask);
	}

	// Can't ignore children here.
	LLToolSelect::handleObjectSelection(mPick, FALSE, TRUE);

	// Spawn pie menu
	LLTool::handleRightMouseDown(x, y, mask);
	return TRUE;
}
Beispiel #22
0
void LLUploadDialog::setMessage( const std::string& msg)
{
	const LLFontGL* font = gResMgr->getRes( LLFONT_SANSSERIF );

	const S32 VPAD = 16;
	const S32 HPAD = 25;

	// Make the text boxes a little wider than the text
	const S32 TEXT_PAD = 8;

	// Split message into lines, separated by '\n'
	S32 max_msg_width = 0;
	LLDoubleLinkedList<LLString> msg_lines;

	S32 size = msg.size() + 1;// + strlen("Uploading...\n\n");
	char* temp_msg = new char[size];
	
	//strcpy(temp_msg,"Uploading...\n\n");
	if (temp_msg == NULL)
	{
		llerrs << "Memory Allocation Failed" << llendl;
		return;
	}
	
	strcpy( temp_msg, msg.c_str());		/* Flawfinder: ignore */
	char* token = strtok( temp_msg, "\n" );
	while( token )
	{
		S32 cur_width = S32(font->getWidth(token) + 0.99f) + TEXT_PAD;
		max_msg_width = llmax( max_msg_width, cur_width );
		msg_lines.addDataAtEnd( new LLString( token ) );
		token = strtok( NULL, "\n" );
	}
	delete[] temp_msg;


	S32 line_height = S32( font->getLineHeight() + 0.99f );
	S32 dialog_width = max_msg_width + 2 * HPAD;
	S32 dialog_height = line_height * msg_lines.getLength() + 2 * VPAD;

	reshape( dialog_width, dialog_height, FALSE );

	// Message
	S32 msg_x = (mRect.getWidth() - max_msg_width) / 2;
	S32 msg_y = mRect.getHeight() - VPAD - line_height;
	int line_num;
	for (line_num=0; line_num<16; ++line_num)
	{
		mLabelBox[line_num]->setVisible(FALSE);
	}
	line_num = 0;
	for( LLString* cur_line = msg_lines.getFirstData(); cur_line; cur_line = msg_lines.getNextData() )
	{
		LLRect msg_rect;
		msg_rect.setOriginAndSize( msg_x, msg_y, max_msg_width, line_height );
		mLabelBox[line_num]->setRect(msg_rect);
		mLabelBox[line_num]->setText(*cur_line);
		mLabelBox[line_num]->setColor( gColors.getColor( "LabelTextColor" ) );
		mLabelBox[line_num]->setVisible(TRUE);
		msg_y -= line_height;
		++line_num;
	}
	msg_lines.deleteAllData();

	centerDialog();
}
Beispiel #23
0
void LLComboBox::onTextEntry(LLLineEditor* line_editor)
{
	if (mTextEntryCallback != NULL)
	{
		(mTextEntryCallback)(line_editor, LLSD());
	}

	KEY key = gKeyboard->currentKey();
	if (key == KEY_BACKSPACE || 
		key == KEY_DELETE)
	{
		if (mList->selectItemByLabel(line_editor->getText(), FALSE))
		{
			line_editor->setTentative(FALSE);
			mLastSelectedIndex = mList->getFirstSelectedIndex();
		}
		else
		{
			line_editor->setTentative(mTextEntryTentative);
			mList->deselectAllItems();
			mLastSelectedIndex = -1;
		}
		return;
	}

	if (key == KEY_LEFT || 
		key == KEY_RIGHT)
	{
		return;
	}

	if (key == KEY_DOWN)
	{
		setCurrentByIndex(llmin(getItemCount() - 1, getCurrentIndex() + 1));
		if (!mList->getVisible())
		{
			prearrangeList();

			if (mList->getItemCount() != 0)
			{
				showList();
			}
		}
		line_editor->selectAll();
		line_editor->setTentative(FALSE);
	}
	else if (key == KEY_UP)
	{
		setCurrentByIndex(llmax(0, getCurrentIndex() - 1));
		if (!mList->getVisible())
		{
			prearrangeList();

			if (mList->getItemCount() != 0)
			{
				showList();
			}
		}
		line_editor->selectAll();
		line_editor->setTentative(FALSE);
	}
	else
	{
		// RN: presumably text entry
		updateSelection();
	}
}
Beispiel #24
0
LLSpinCtrl::LLSpinCtrl(const LLSpinCtrl::Params& p)
:	LLF32UICtrl(p),
	mLabelBox(NULL),
	mbHasBeenSet( FALSE ),
	mPrecision(p.decimal_digits),
	mTextEnabledColor(p.text_enabled_color()),
	mTextDisabledColor(p.text_disabled_color())
{
	static LLUICachedControl<S32> spinctrl_spacing ("UISpinctrlSpacing", 0);
	static LLUICachedControl<S32> spinctrl_btn_width ("UISpinctrlBtnWidth", 0);
	static LLUICachedControl<S32> spinctrl_btn_height ("UISpinctrlBtnHeight", 0);
	S32 centered_top = getRect().getHeight();
	S32 centered_bottom = getRect().getHeight() - 2 * spinctrl_btn_height;
	S32 btn_left = 0;
	// reserve space for spinner
	S32 label_width = llclamp(p.label_width(), 0, llmax(0, getRect().getWidth() - 40));

	// Label
	if( !p.label().empty() )
	{
		LLRect label_rect( 0, centered_top, label_width, centered_bottom );
		LLTextBox::Params params;
		params.wrap(p.label_wrap);
		params.name("SpinCtrl Label");
		params.rect(label_rect);
		params.initial_value(p.label());
		if (p.font.isProvided())
		{
			params.font(p.font);
		}
		mLabelBox = LLUICtrlFactory::create<LLTextBox> (params);
		addChild(mLabelBox);

		btn_left += label_rect.mRight + spinctrl_spacing;
	}

	S32 btn_right = btn_left + spinctrl_btn_width;
	
	// Spin buttons
	LLButton::Params up_button_params(p.up_button);
	up_button_params.rect = LLRect(btn_left, getRect().getHeight(), btn_right, getRect().getHeight() - spinctrl_btn_height);
	up_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));
	up_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onUpBtn, this, _2));

	mUpBtn = LLUICtrlFactory::create<LLButton>(up_button_params);
	addChild(mUpBtn);

	LLButton::Params down_button_params(p.down_button);
	down_button_params.rect = LLRect(btn_left, getRect().getHeight() - spinctrl_btn_height, btn_right, getRect().getHeight() - 2 * spinctrl_btn_height);
	down_button_params.click_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
	down_button_params.mouse_held_callback.function(boost::bind(&LLSpinCtrl::onDownBtn, this, _2));
	mDownBtn = LLUICtrlFactory::create<LLButton>(down_button_params);
	addChild(mDownBtn);

	LLRect editor_rect( btn_right + 1, centered_top, getRect().getWidth(), centered_bottom );
	LLLineEditor::Params params;
	params.name("SpinCtrl Editor");
	params.rect(editor_rect);
	if (p.font.isProvided())
	{
		params.font(p.font);
	}
	params.max_length.bytes(MAX_STRING_LENGTH);
	params.commit_callback.function((boost::bind(&LLSpinCtrl::onEditorCommit, this, _2)));
	
	//*NOTE: allow entering of any chars for LLCalc, proper input will be evaluated on commit
	
	params.follows.flags(FOLLOWS_LEFT | FOLLOWS_BOTTOM);
	mEditor = LLUICtrlFactory::create<LLLineEditor> (params);
	mEditor->setFocusReceivedCallback( boost::bind(&LLSpinCtrl::onEditorGainFocus, _1, this ));
	//RN: this seems to be a BAD IDEA, as it makes the editor behavior different when it has focus
	// than when it doesn't.  Instead, if you always have to double click to select all the text, 
	// it's easier to understand
	//mEditor->setSelectAllonFocusReceived(TRUE);
	mEditor->setSelectAllonCommit(FALSE);
	addChild(mEditor);

	updateEditor();
	setUseBoundingRect( TRUE );
}
 static U16 min(AIHTTPTimeoutPolicy const* policy) { return llmax(ABS_min_transaction, (U16)(policy->mMaximumConnectTime + policy->mMaximumReplyDelay + 4 * policy->mLowSpeedTime)); }
//-----------------------------------------------------------------------------
// LLEyeMotion::onUpdate()
//-----------------------------------------------------------------------------
BOOL LLEyeMotion::onUpdate(F32 time, U8* joint_mask)
{
	// Compute eye rotation.
	LLQuaternion	target_eye_rot;
	LLVector3		eye_look_at;
	F32				vergence;

	//calculate jitter
	if (mEyeJitterTimer.getElapsedTimeF32() > mEyeJitterTime)
	{
		mEyeJitterTime = EYE_JITTER_MIN_TIME + ll_frand(EYE_JITTER_MAX_TIME - EYE_JITTER_MIN_TIME);
		mEyeJitterYaw = (ll_frand(2.f) - 1.f) * EYE_JITTER_MAX_YAW;
		mEyeJitterPitch = (ll_frand(2.f) - 1.f) * EYE_JITTER_MAX_PITCH;
		// make sure lookaway time count gets updated, because we're resetting the timer
		mEyeLookAwayTime -= llmax(0.f, mEyeJitterTimer.getElapsedTimeF32());
		mEyeJitterTimer.reset();
	} 
	else if (mEyeJitterTimer.getElapsedTimeF32() > mEyeLookAwayTime)
	{
		if (ll_frand() > 0.1f)
		{
			// blink while moving eyes some percentage of the time
			mEyeBlinkTime = mEyeBlinkTimer.getElapsedTimeF32();
		}
		if (mEyeLookAwayYaw == 0.f && mEyeLookAwayPitch == 0.f)
		{
			mEyeLookAwayYaw = (ll_frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_YAW;
			mEyeLookAwayPitch = (ll_frand(2.f) - 1.f) * EYE_LOOK_AWAY_MAX_PITCH;
			mEyeLookAwayTime = EYE_LOOK_BACK_MIN_TIME + ll_frand(EYE_LOOK_BACK_MAX_TIME - EYE_LOOK_BACK_MIN_TIME);
		}
		else
		{
			mEyeLookAwayYaw = 0.f;
			mEyeLookAwayPitch = 0.f;
			mEyeLookAwayTime = EYE_LOOK_AWAY_MIN_TIME + ll_frand(EYE_LOOK_AWAY_MAX_TIME - EYE_LOOK_AWAY_MIN_TIME);
		}
	}

	// do blinking
	if (!mEyesClosed && mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime)
	{
		F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime;
		F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA;

		leftEyeBlinkMorph = llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
		rightEyeBlinkMorph = llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
		mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph);
		mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph);
		mCharacter->updateVisualParams();

		if (rightEyeBlinkMorph == 1.f)
		{
			mEyesClosed = TRUE;
			mEyeBlinkTime = EYE_BLINK_CLOSE_TIME;
			mEyeBlinkTimer.reset();
		}
	}
	else if (mEyesClosed)
	{
		if (mEyeBlinkTimer.getElapsedTimeF32() >= mEyeBlinkTime)
		{
			F32 leftEyeBlinkMorph = mEyeBlinkTimer.getElapsedTimeF32() - mEyeBlinkTime;
			F32 rightEyeBlinkMorph = leftEyeBlinkMorph - EYE_BLINK_TIME_DELTA;

			leftEyeBlinkMorph = 1.f - llclamp(leftEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
			rightEyeBlinkMorph = 1.f - llclamp(rightEyeBlinkMorph / EYE_BLINK_SPEED, 0.f, 1.f);
			mCharacter->setVisualParamWeight("Blink_Left", leftEyeBlinkMorph);
			mCharacter->setVisualParamWeight("Blink_Right", rightEyeBlinkMorph);
			mCharacter->updateVisualParams();

			if (rightEyeBlinkMorph == 0.f)
			{
				mEyesClosed = FALSE;
				mEyeBlinkTime = EYE_BLINK_MIN_TIME + ll_frand(EYE_BLINK_MAX_TIME - EYE_BLINK_MIN_TIME);
				mEyeBlinkTimer.reset();
			}
		}
	}

	BOOL has_eye_target = FALSE;
	LLVector3* targetPos = (LLVector3*)mCharacter->getAnimationData("LookAtPoint");

	if (targetPos)
	{
		LLVector3		skyward(0.f, 0.f, 1.f);
		LLVector3		left;
		LLVector3		up;

		eye_look_at = *targetPos;
		has_eye_target = TRUE;
		F32 lookAtDistance = eye_look_at.normVec();

		left.setVec(skyward % eye_look_at);
		up.setVec(eye_look_at % left);

		target_eye_rot = LLQuaternion(eye_look_at, left, up);
		// convert target rotation to head-local coordinates
		target_eye_rot *= ~mHeadJoint->getWorldRotation();
		// eliminate any Euler roll - we're lucky that roll is applied last.
		F32 roll, pitch, yaw;
		target_eye_rot.getEulerAngles(&roll, &pitch, &yaw);
		target_eye_rot.setQuat(0.0f, pitch, yaw);
		// constrain target orientation to be in front of avatar's face
		target_eye_rot.constrain(EYE_ROT_LIMIT_ANGLE);

		// calculate vergence
		F32 interocular_dist = (mLeftEyeState->getJoint()->getWorldPosition() - mRightEyeState->getJoint()->getWorldPosition()).magVec();
		vergence = -atan2((interocular_dist / 2.f), lookAtDistance);
		llclamp(vergence, -F_PI_BY_TWO, 0.f);
	}
	else
	{
		target_eye_rot = LLQuaternion::DEFAULT;
		vergence = 0.f;
	}

	//RN: subtract 4 degrees to account for foveal angular offset relative to pupil
	vergence += 4.f * DEG_TO_RAD;

	// calculate eye jitter
	LLQuaternion eye_jitter_rot;

	// vergence not too high...
	if (vergence > -0.05f)
	{
		//...go ahead and jitter
		eye_jitter_rot.setQuat(0.f, mEyeJitterPitch + mEyeLookAwayPitch, mEyeJitterYaw + mEyeLookAwayYaw);
	}
	else
	{
		//...or don't
		eye_jitter_rot.loadIdentity();
	}

	// calculate vergence of eyes as an object gets closer to the avatar's head
	LLQuaternion vergence_quat;
		
	if (has_eye_target)
	{
		vergence_quat.setQuat(vergence, LLVector3(0.f, 0.f, 1.f));
	}
	else
	{
		vergence_quat.loadIdentity();
	}

	// calculate eye rotations
	LLQuaternion left_eye_rot = target_eye_rot;
	left_eye_rot = vergence_quat * eye_jitter_rot * left_eye_rot;

	LLQuaternion right_eye_rot = target_eye_rot;
	vergence_quat.transQuat();
	right_eye_rot = vergence_quat * eye_jitter_rot * right_eye_rot;

	//if in appearance, set the eyes straight forward
	if(mCharacter->getAppearanceFlag()) // no idea why this variable is reversed
	{
		LLVector3		forward(1.f, 0.0, 0.0);
		LLVector3		left;
		LLVector3		up;
		left.setVec(forward % forward);
		up.setVec(forward % left);
		target_eye_rot = LLQuaternion(forward, left, up);
		mLeftEyeState->setRotation( target_eye_rot );
		mRightEyeState->setRotation( target_eye_rot );
		return TRUE;
	}

	mLeftEyeState->setRotation( left_eye_rot );
	mRightEyeState->setRotation( right_eye_rot );

	return TRUE;
}
void LLMediaCtrl::draw()
{
	if ( ! mWebBrowserImage || mWebBrowserImage->getNeedsUpdate())
		return;

	if ( gRestoreGL == 1 )
	{
		LLRect r = getRect();
		reshape( r.getWidth(), r.getHeight(), FALSE );
		return;
	};

	// NOTE: optimization needed here - probably only need to do this once
	// unless tearoffs change the parent which they probably do.
	const LLUICtrl* ptr = findRootMostFocusRoot();
	if ( ptr && ptr->hasFocus() )
	{
		setFrequentUpdates( true );
	}
	else
	{
		setFrequentUpdates( false );
	};

	// alpha off for this
	LLGLSUIDefault gls_ui;
	LLGLDisable gls_alphaTest( GL_ALPHA_TEST );

	bool draw_media = false;
	
	LLPluginClassMedia* media_plugin = NULL;
	LLWebBrowserTexture* media_texture =  mWebBrowserImage;
	
	if(mMediaSource && mMediaSource->hasMedia())
	{
		media_plugin = mMediaSource->getMediaPlugin();

		if(media_plugin && (media_plugin->textureValid()))
		{
			media_texture = mWebBrowserImage;
			if(media_texture)
			{
				draw_media = true;
			}
		}
	}
	if(draw_media)
	{
		gGL.pushMatrix();
		{
			if (mIgnoreUIScale)
			{
				gGL.loadIdentity();
				// font system stores true screen origin, need to scale this by UI scale factor
				// to get render origin for this view (with unit scale)
				gGL.translatef(floorf(LLFontGL::sCurOrigin.mX * LLUI::sGLScaleFactor.mV[VX]), 
							floorf(LLFontGL::sCurOrigin.mY * LLUI::sGLScaleFactor.mV[VY]), 
							LLFontGL::sCurDepth);
			}

			// scale texture to fit the space using texture coords
			gGL.getTexUnit(0)->bind(media_texture);
			LLColor4 media_color = LLColor4::white;
			gGL.color4fv( media_color.mV );
			F32 max_u = ( F32 )media_plugin->getWidth() / ( F32 )media_plugin->getTextureWidth();
			F32 max_v = ( F32 )media_plugin->getHeight() / ( F32 )media_plugin->getTextureHeight();

			LLRect r = getRect();
			S32 width, height;
			S32 x_offset = 0;
			S32 y_offset = 0;
		
			if(mStretchToFill)
			{
				if(mMaintainAspectRatio)
				{
					F32 media_aspect = (F32)(media_plugin->getWidth()) / (F32)(media_plugin->getHeight());
					F32 view_aspect = (F32)(r.getWidth()) / (F32)(r.getHeight());
					if(media_aspect > view_aspect)
					{
						// max width, adjusted height
						width = r.getWidth();
						height = llmin(llmax(llround(width / media_aspect), 0), r.getHeight());
					}
					else
					{
						// max height, adjusted width
						height = r.getHeight();
						width = llmin(llmax(llround(height * media_aspect), 0), r.getWidth());
					}
				}
				else
				{
					width = r.getWidth();
					height = r.getHeight();
				}
			}
			else
			{
				width = llmin(media_plugin->getWidth(), r.getWidth());
				height = llmin(media_plugin->getHeight(), r.getHeight());
			}
			
			x_offset = (r.getWidth() - width) / 2;
			y_offset = (r.getHeight() - height) / 2;		

			if (mIgnoreUIScale)
			{
				x_offset = llround((F32)x_offset * LLUI::sGLScaleFactor.mV[VX]);
				y_offset = llround((F32)y_offset * LLUI::sGLScaleFactor.mV[VY]);
				width = llround((F32)width * LLUI::sGLScaleFactor.mV[VX]);
				height = llround((F32)height * LLUI::sGLScaleFactor.mV[VY]);
			}

			// draw the browser
			gGL.setSceneBlendType(LLRender::BT_REPLACE);
			gGL.begin( LLRender::QUADS );
			if (! media_plugin->getTextureCoordsOpenGL())
			{
				// render using web browser reported width and height, instead of trying to invert GL scale
				gGL.texCoord2f( max_u, 0.f );
				gGL.vertex2i( x_offset + width, y_offset + height );

				gGL.texCoord2f( 0.f, 0.f );
				gGL.vertex2i( x_offset, y_offset + height );

				gGL.texCoord2f( 0.f, max_v );
				gGL.vertex2i( x_offset, y_offset );

				gGL.texCoord2f( max_u, max_v );
				gGL.vertex2i( x_offset + width, y_offset );
			}
			else
			{
				// render using web browser reported width and height, instead of trying to invert GL scale
				gGL.texCoord2f( max_u, max_v );
				gGL.vertex2i( x_offset + width, y_offset + height );

				gGL.texCoord2f( 0.f, max_v );
				gGL.vertex2i( x_offset, y_offset + height );

				gGL.texCoord2f( 0.f, 0.f );
				gGL.vertex2i( x_offset, y_offset );

				gGL.texCoord2f( max_u, 0.f );
				gGL.vertex2i( x_offset + width, y_offset );
			}
			gGL.end();
			gGL.setSceneBlendType(LLRender::BT_ALPHA);
		}
		gGL.popMatrix();
	}
	// highlight if keyboard focus here. (TODO: this needs some work)
	if ( mBorder && mBorder->getVisible() )
		mBorder->setKeyboardFocusHighlight( gFocusMgr.childHasKeyboardFocus( this ) );

	
	LLUICtrl::draw();
}
void LLWaterParamManager::update(LLViewerCamera * cam)
{
	LLFastTimer ftm(LLFastTimer::FTM_UPDATE_WLPARAM);
	
	// update the shaders and the menu
	propagateParameters();
	
	// sync menus if they exist
	if(LLFloaterWater::isOpen()) 
	{
		LLFloaterWater::instance()->syncMenu();
	}

	stop_glerror();

	// only do this if we're dealing with shaders
	if(gPipeline.canUseVertexShaders()) 
	{
		//transform water plane to eye space
		glh::vec3f norm(0.f, 0.f, 1.f);
		glh::vec3f p(0.f, 0.f, gAgent.getRegion()->getWaterHeight()+0.1f);
		
		F32 modelView[16];
		for (U32 i = 0; i < 16; i++)
		{
			modelView[i] = (F32) gGLModelView[i];
		}

		glh::matrix4f mat(modelView);
		glh::matrix4f invtrans = mat.inverse().transpose();
		glh::vec3f enorm;
		glh::vec3f ep;
		invtrans.mult_matrix_vec(norm, enorm);
		enorm.normalize();
		mat.mult_matrix_vec(p, ep);

		mWaterPlane = LLVector4(enorm.v[0], enorm.v[1], enorm.v[2], -ep.dot(enorm));

		LLVector3 sunMoonDir;
		if (gSky.getSunDirection().mV[2] > NIGHTTIME_ELEVATION_COS) 	 
		{ 	 
			sunMoonDir = gSky.getSunDirection(); 	 
		} 	 
		else  	 
		{ 	 
			sunMoonDir = gSky.getMoonDirection(); 	 
		}
		sunMoonDir.normVec();
		mWaterFogKS = 1.f/llmax(sunMoonDir.mV[2], WATER_FOG_LIGHT_CLAMP);

		LLViewerShaderMgr::shader_iter shaders_iter, end_shaders;
		end_shaders = LLViewerShaderMgr::instance()->endShaders();
		for(shaders_iter = LLViewerShaderMgr::instance()->beginShaders(); shaders_iter != end_shaders; ++shaders_iter)
		{
			if (shaders_iter->mProgramObject != 0
				&& shaders_iter->mShaderGroup == LLGLSLShader::SG_WATER)
			{
				shaders_iter->mUniformsDirty = TRUE;
			}
		}
	}
}
Beispiel #29
0
void LLUploadDialog::setMessage( const std::string& msg)
{
	const LLFontGL* font = LLResMgr::getInstance()->getRes( LLFONT_SANSSERIF );

	const S32 VPAD = 16;
	const S32 HPAD = 25;

	// Make the text boxes a little wider than the text
	const S32 TEXT_PAD = 8;

	// Split message into lines, separated by '\n'
	S32 max_msg_width = 0;
	std::list<std::string> msg_lines;

	S32 size = msg.size() + 1;// + strlen("Uploading...\n\n");
	char* temp_msg = new char[size];
	
	//strcpy(temp_msg,"Uploading...\n\n");
	if (temp_msg == NULL)
	{
		llerrs << "Memory Allocation Failed" << llendl;
		return;
	}
	
	strcpy( temp_msg, msg.c_str());		/* Flawfinder: ignore */
	char* token = strtok( temp_msg, "\n" );
	while( token )
	{
		std::string tokstr(token);
		S32 cur_width = S32(font->getWidth(tokstr) + 0.99f) + TEXT_PAD;
		max_msg_width = llmax( max_msg_width, cur_width );
		msg_lines.push_back( tokstr );
		token = strtok( NULL, "\n" );
	}
	delete[] temp_msg;


	S32 line_height = S32( font->getLineHeight() + 0.99f );
	S32 dialog_width = max_msg_width + 2 * HPAD;
	S32 dialog_height = line_height * msg_lines.size() + 2 * VPAD;

	reshape( dialog_width, dialog_height, FALSE );

	// Message
	S32 msg_x = (getRect().getWidth() - max_msg_width) / 2;
	S32 msg_y = getRect().getHeight() - VPAD - line_height;
	int line_num;
	for (line_num=0; line_num<16; ++line_num)
	{
		mLabelBox[line_num]->setVisible(FALSE);
	}
	line_num = 0;
	for (std::list<std::string>::iterator iter = msg_lines.begin();
		 iter != msg_lines.end(); ++iter)
	{
		std::string& cur_line = *iter;
		LLRect msg_rect;
		msg_rect.setOriginAndSize( msg_x, msg_y, max_msg_width, line_height );
		mLabelBox[line_num]->setRect(msg_rect);
		mLabelBox[line_num]->setText(cur_line);
		mLabelBox[line_num]->setColor( gColors.getColor( "LabelTextColor" ) );
		mLabelBox[line_num]->setVisible(TRUE);
		msg_y -= line_height;
		++line_num;
	}

	centerWithin(gViewerWindow->getRootView()->getRect());
}
/*virtual*/
void LLPanelPrimMediaControls::draw()
{
	LLViewerMediaImpl* impl = getTargetMediaImpl();
	if (impl)
	{
		LLNotificationPtr notification = impl->getCurrentNotification();
		if (notification != mActiveNotification)
		{
			mActiveNotification = notification;
			if (notification)
			{
				showNotification(notification);
			}
			else
			{
				hideNotification();
			}
		}
	}

	F32 alpha = getDrawContext().mAlpha;
	if(mHideImmediately)
	{
		//hide this panel
		clearFaceOnFade();

		mHideImmediately = false;
	}
	else if(mFadeTimer.getStarted())
	{
		F32 time = mFadeTimer.getElapsedTimeF32();
		alpha *= llmax(lerp(1.0, 0.0, time / mControlFadeTime), 0.0f);

		if(time >= mControlFadeTime)
		{
			//hide this panel
			clearFaceOnFade();
		}
	}
	
	// Build rect for icon area in coord system of this panel
	// Assumes layout_stack is a direct child of this panel
	mMediaControlsStack->updateLayout();
	
	// adjust for layout stack spacing
	S32 space = mMediaControlsStack->getPanelSpacing() + 2;
	LLRect controls_bg_area = mMediaControlsStack->getRect();
	
	controls_bg_area.mTop += space + 2;
	
	// adjust to ignore space from volume slider
	controls_bg_area.mBottom += mVolumeSliderCtrl->getRect().getHeight();
	
	// adjust to ignore space from left bookend padding
	controls_bg_area.mLeft += mLeftBookend->getRect().getWidth() - space;
	
	// ignore space from right bookend padding
	controls_bg_area.mRight -= mRightBookend->getRect().getWidth() - space - 2;
		
	// draw control background UI image
	mBackgroundImage->draw( controls_bg_area, UI_VERTEX_COLOR % alpha);
	
	// draw volume slider background UI image
	if (mVolumeSliderCtrl->getVisible())
	{
		LLRect volume_slider_rect;
		screenRectToLocal(mVolumeSliderCtrl->calcScreenRect(), &volume_slider_rect);
		mVolumeSliderBackgroundImage->draw(volume_slider_rect, UI_VERTEX_COLOR % alpha);
	}
	
	{
		LLViewDrawContext context(alpha);
		LLPanel::draw();
	}
}