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)); }
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); }
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; } }
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; }
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")); }
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; } }
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; }
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()); }
// 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; }
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(); }
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(); } }
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; } } } }
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(); } }