summaryrefslogtreecommitdiff
path: root/indra/newview
diff options
context:
space:
mode:
Diffstat (limited to 'indra/newview')
-rw-r--r--indra/newview/CMakeLists.txt13
-rw-r--r--indra/newview/app_settings/CA.pem19
-rw-r--r--indra/newview/app_settings/cmd_line.xml18
-rw-r--r--indra/newview/app_settings/settings.xml237
-rw-r--r--indra/newview/app_settings/settings_files.xml212
-rw-r--r--indra/newview/app_settings/settings_minimal.xml406
-rw-r--r--indra/newview/llappearancemgr.cpp3
-rw-r--r--indra/newview/llappviewer.cpp10175
-rw-r--r--indra/newview/llappviewer.h2
-rwxr-xr-xindra/newview/llavataractions.cpp21
-rw-r--r--indra/newview/llavataractions.h2
-rw-r--r--indra/newview/llbottomtray.cpp3683
-rw-r--r--indra/newview/llchathistory.cpp43
-rw-r--r--indra/newview/llchathistory.h2
-rwxr-xr-xindra/newview/llcommandhandler.cpp2
-rw-r--r--indra/newview/llfirstuse.cpp65
-rw-r--r--indra/newview/llfirstuse.h10
-rw-r--r--indra/newview/llfloatermap.cpp12
-rw-r--r--indra/newview/llfloatersidetraytab.cpp6
-rw-r--r--indra/newview/llfloatersidetraytab.h2
-rwxr-xr-xindra/newview/llfloaterworldmap.cpp12
-rw-r--r--indra/newview/llgroupactions.cpp6
-rw-r--r--indra/newview/llhudeffectblob.cpp78
-rw-r--r--indra/newview/llhudeffectblob.h50
-rw-r--r--indra/newview/llhudobject.cpp4
-rw-r--r--indra/newview/llhudobject.h3
-rw-r--r--indra/newview/llinventorymodelbackgroundfetch.cpp2
-rw-r--r--indra/newview/lllocationinputctrl.cpp1
-rw-r--r--indra/newview/llnavigationbar.cpp19
-rw-r--r--indra/newview/llnearbychatbar.cpp11
-rw-r--r--indra/newview/llnearbychatbar.h2
-rw-r--r--indra/newview/llnetmap.cpp24
-rw-r--r--indra/newview/llnotificationscripthandler.cpp2
-rw-r--r--indra/newview/llpanellogin.cpp2376
-rw-r--r--indra/newview/llpanellogin.h2
-rwxr-xr-xindra/newview/llpanelpicks.cpp13
-rwxr-xr-xindra/newview/llpanelprofile.cpp19
-rw-r--r--indra/newview/llshareavatarhandler.cpp8
-rw-r--r--indra/newview/llsidetray.cpp100
-rw-r--r--indra/newview/llsidetray.h6
-rw-r--r--indra/newview/llstartup.cpp6460
-rw-r--r--indra/newview/lltexturecache.cpp19
-rw-r--r--indra/newview/lltoast.cpp7
-rw-r--r--indra/newview/lltoolpie.cpp301
-rw-r--r--indra/newview/lltoolpie.h24
-rw-r--r--indra/newview/llurldispatcher.cpp2
-rw-r--r--indra/newview/llviewermedia.cpp69
-rw-r--r--indra/newview/llviewermenu.cpp16278
-rw-r--r--indra/newview/llviewermenu.h2
-rw-r--r--indra/newview/llviewermessage.cpp29
-rw-r--r--indra/newview/llviewernetwork.cpp4
-rw-r--r--indra/newview/llviewerobjectlist.cpp2
-rw-r--r--indra/newview/llviewerregion.cpp14
-rw-r--r--indra/newview/llviewerstats.cpp2
-rw-r--r--indra/newview/llviewerwindow.cpp10070
-rw-r--r--indra/newview/llvoicecallhandler.cpp8
-rw-r--r--indra/newview/pipeline.cpp18049
-rw-r--r--indra/newview/skins/default/xui/en/main_view.xml7
-rw-r--r--indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml240
-rw-r--r--indra/newview/skins/default/xui/en/notifications.xml777
-rw-r--r--indra/newview/skins/default/xui/en/panel_login.xml41
-rw-r--r--indra/newview/skins/minimal/colors.xml6
-rw-r--r--indra/newview/skins/minimal/textures/arrow_keys.pngbin0 -> 6558 bytes
-rw-r--r--indra/newview/skins/minimal/textures/bottomtray/button_separator.pngbin0 -> 153 bytes
-rw-r--r--indra/newview/skins/minimal/textures/bottomtray/close_off.pngbin0 -> 3184 bytes
-rw-r--r--indra/newview/skins/minimal/textures/bottomtray/close_over.pngbin0 -> 3173 bytes
-rw-r--r--indra/newview/skins/minimal/textures/bottomtray/close_press.pngbin0 -> 3259 bytes
-rw-r--r--indra/newview/skins/minimal/textures/textures.xml8
-rw-r--r--indra/newview/skins/minimal/xui/de/floater_camera.xml65
-rw-r--r--indra/newview/skins/minimal/xui/de/floater_help_browser.xml9
-rw-r--r--indra/newview/skins/minimal/xui/de/floater_nearby_chat.xml4
-rw-r--r--indra/newview/skins/minimal/xui/de/inspect_avatar.xml25
-rw-r--r--indra/newview/skins/minimal/xui/de/inspect_object.xml48
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_add_wearable_gear.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_attachment_other.xml17
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_attachment_self.xml16
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_avatar_icon.xml7
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_avatar_other.xml16
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_avatar_self.xml31
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_bottomtray.xml17
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_cof_attachment.xml4
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_cof_body_part.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_cof_clothing.xml8
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_cof_gear.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_edit.xml12
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_favorites.xml10
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_gesture_gear.xml10
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_group_plus.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_hide_navbar.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_im_well_button.xml4
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_imchiclet_adhoc.xml4
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_imchiclet_group.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_imchiclet_p2p.xml7
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_inspect_avatar_gear.xml17
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_inspect_object_gear.xml18
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml10
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_inventory.xml86
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_inventory_add.xml33
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_inventory_gear_default.xml16
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_land.xml9
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_landmark.xml7
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_login.xml25
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_mini_map.xml11
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_navbar.xml11
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_nearby_chat.xml9
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_object.xml29
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_object_icon.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_outfit_gear.xml27
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_outfit_tab.xml9
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_participant_list.xml21
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_people_friends_view_sort.xml8
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_people_groups.xml8
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_people_groups_view_sort.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_people_nearby.xml13
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_people_nearby_multiselect.xml10
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_people_nearby_view_sort.xml8
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_people_recent_view_sort.xml7
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_picks.xml8
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_picks_plus.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_place.xml7
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_place_add_button.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_places_gear_folder.xml15
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_places_gear_landmark.xml18
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_profile_overflow.xml12
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_slurl.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_teleport_history_gear.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_teleport_history_item.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_teleport_history_tab.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_text_editor.xml8
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_topinfobar.xml7
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_url_agent.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_url_group.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_url_http.xml7
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_url_inventory.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_url_map.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_url_objectim.xml8
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_url_parcel.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_url_slapp.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_url_slurl.xml7
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_url_teleport.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_viewer.xml14
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_wearable_list_item.xml14
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_wearing_gear.xml5
-rw-r--r--indra/newview/skins/minimal/xui/de/menu_wearing_tab.xml6
-rw-r--r--indra/newview/skins/minimal/xui/de/panel_bottomtray.xml39
-rw-r--r--indra/newview/skins/minimal/xui/de/panel_im_control_panel.xml30
-rw-r--r--indra/newview/skins/minimal/xui/de/panel_login.xml40
-rw-r--r--indra/newview/skins/minimal/xui/de/panel_navigation_bar.xml18
-rw-r--r--indra/newview/skins/minimal/xui/de/panel_people.xml70
-rw-r--r--indra/newview/skins/minimal/xui/de/panel_side_tray_tab_caption.xml7
-rw-r--r--indra/newview/skins/minimal/xui/de/panel_status_bar.xml33
-rw-r--r--indra/newview/skins/minimal/xui/en/floater_camera.xml284
-rw-r--r--indra/newview/skins/minimal/xui/en/floater_help_browser.xml52
-rw-r--r--indra/newview/skins/minimal/xui/en/floater_media_browser.xml242
-rw-r--r--indra/newview/skins/minimal/xui/en/floater_nearby_chat.xml52
-rw-r--r--indra/newview/skins/minimal/xui/en/floater_side_bar_tab.xml10
-rw-r--r--indra/newview/skins/minimal/xui/en/floater_web_content.xml189
-rw-r--r--indra/newview/skins/minimal/xui/en/inspect_avatar.xml206
-rw-r--r--indra/newview/skins/minimal/xui/en/inspect_object.xml144
-rw-r--r--indra/newview/skins/minimal/xui/en/main_view.xml268
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_add_wearable_gear.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_attachment_other.xml76
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_attachment_self.xml26
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_avatar_icon.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_avatar_other.xml75
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_avatar_self.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_bottomtray.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_cof_attachment.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_cof_body_part.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_cof_clothing.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_cof_gear.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_edit.xml90
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_favorites.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_gesture_gear.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_group_plus.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_hide_navbar.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_im_well_button.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_imchiclet_adhoc.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_imchiclet_group.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_imchiclet_p2p.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inspect_avatar_gear.xml116
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inspect_object_gear.xml50
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inspect_self_gear.xml49
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inv_offer_chiclet.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inventory.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inventory_add.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_inventory_gear_default.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_land.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_landmark.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_login.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_mini_map.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_navbar.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_nearby_chat.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_notification_well_button.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_object.xml40
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_object_icon.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_outfit_gear.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_outfit_tab.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_participant_list.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_people_friends_view_sort.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_people_groups.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_people_groups_view_sort.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_people_nearby.xml61
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_people_nearby_multiselect.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_people_nearby_view_sort.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_people_recent_view_sort.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_picks.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_picks_plus.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_place.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_place_add_button.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_places_gear_folder.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_places_gear_landmark.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_profile_overflow.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_save_outfit.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_script_chiclet.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_slurl.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_teleport_history_gear.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_teleport_history_item.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_teleport_history_tab.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_text_editor.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_topinfobar.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_url_agent.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_url_group.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_url_http.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_url_inventory.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_url_map.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_url_objectim.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_url_parcel.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_url_slapp.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_url_slurl.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_url_teleport.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_viewer.xml71
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_wearable_list_item.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_wearing_gear.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/menu_wearing_tab.xml2
-rw-r--r--indra/newview/skins/minimal/xui/en/notification_visibility.xml29
-rw-r--r--indra/newview/skins/minimal/xui/en/notifications.xml44
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_adhoc_control_panel.xml46
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_bottomtray.xml483
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_group_control_panel.xml79
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_im_control_panel.xml27
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_login.xml206
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml76
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_people.xml550
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_side_tray_tab_caption.xml11
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_status_bar.xml62
-rw-r--r--indra/newview/skins/minimal/xui/en/panel_volume_pulldown.xml34
-rw-r--r--indra/newview/skins/minimal/xui/en/widgets/location_input.xml131
-rw-r--r--indra/newview/skins/minimal/xui/es/floater_camera.xml65
-rw-r--r--indra/newview/skins/minimal/xui/es/floater_help_browser.xml9
-rw-r--r--indra/newview/skins/minimal/xui/es/floater_nearby_chat.xml4
-rw-r--r--indra/newview/skins/minimal/xui/es/inspect_avatar.xml24
-rw-r--r--indra/newview/skins/minimal/xui/es/inspect_object.xml41
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_add_wearable_gear.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_attachment_other.xml17
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_attachment_self.xml16
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_avatar_icon.xml7
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_avatar_other.xml16
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_avatar_self.xml31
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_bottomtray.xml17
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_cof_attachment.xml4
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_cof_body_part.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_cof_clothing.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_cof_gear.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_edit.xml12
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_favorites.xml10
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_gesture_gear.xml10
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_group_plus.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_hide_navbar.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_im_well_button.xml4
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_imchiclet_adhoc.xml4
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_imchiclet_group.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_imchiclet_p2p.xml7
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_inspect_avatar_gear.xml17
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_inspect_object_gear.xml18
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml10
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_inventory.xml86
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_inventory_add.xml33
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_inventory_gear_default.xml16
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_land.xml9
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_landmark.xml7
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_login.xml24
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_mini_map.xml11
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_navbar.xml11
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_nearby_chat.xml9
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_object.xml29
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_object_icon.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_outfit_gear.xml27
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_outfit_tab.xml9
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_participant_list.xml21
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_people_friends_view_sort.xml8
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_people_groups.xml8
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_people_groups_view_sort.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_people_nearby.xml13
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_people_nearby_multiselect.xml10
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_people_nearby_view_sort.xml8
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_people_recent_view_sort.xml7
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_picks.xml8
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_picks_plus.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_place.xml7
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_place_add_button.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_places_gear_folder.xml15
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_places_gear_landmark.xml18
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_profile_overflow.xml12
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_slurl.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_teleport_history_gear.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_teleport_history_item.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_teleport_history_tab.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_text_editor.xml8
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_topinfobar.xml7
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_url_agent.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_url_group.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_url_http.xml7
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_url_inventory.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_url_map.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_url_objectim.xml8
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_url_parcel.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_url_slapp.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_url_slurl.xml7
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_url_teleport.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_viewer.xml14
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_wearable_list_item.xml14
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_wearing_gear.xml5
-rw-r--r--indra/newview/skins/minimal/xui/es/menu_wearing_tab.xml6
-rw-r--r--indra/newview/skins/minimal/xui/es/panel_bottomtray.xml39
-rw-r--r--indra/newview/skins/minimal/xui/es/panel_im_control_panel.xml29
-rw-r--r--indra/newview/skins/minimal/xui/es/panel_login.xml40
-rw-r--r--indra/newview/skins/minimal/xui/es/panel_navigation_bar.xml18
-rw-r--r--indra/newview/skins/minimal/xui/es/panel_people.xml71
-rw-r--r--indra/newview/skins/minimal/xui/es/panel_side_tray_tab_caption.xml7
-rw-r--r--indra/newview/skins/minimal/xui/es/panel_status_bar.xml33
-rw-r--r--indra/newview/skins/minimal/xui/fr/floater_camera.xml65
-rw-r--r--indra/newview/skins/minimal/xui/fr/floater_help_browser.xml9
-rw-r--r--indra/newview/skins/minimal/xui/fr/floater_nearby_chat.xml4
-rw-r--r--indra/newview/skins/minimal/xui/fr/inspect_avatar.xml25
-rw-r--r--indra/newview/skins/minimal/xui/fr/inspect_object.xml48
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_add_wearable_gear.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_attachment_other.xml17
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_attachment_self.xml16
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_avatar_icon.xml7
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_avatar_other.xml16
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_avatar_self.xml31
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_bottomtray.xml17
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_cof_attachment.xml4
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_cof_body_part.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_cof_clothing.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_cof_gear.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_edit.xml12
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_favorites.xml10
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_gesture_gear.xml10
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_group_plus.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_hide_navbar.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_im_well_button.xml4
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_imchiclet_adhoc.xml4
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_imchiclet_group.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_imchiclet_p2p.xml7
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_inspect_avatar_gear.xml17
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_inspect_object_gear.xml18
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml10
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_inventory.xml86
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_inventory_add.xml33
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_inventory_gear_default.xml16
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_land.xml9
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_landmark.xml7
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_login.xml25
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_mini_map.xml11
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_navbar.xml11
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_nearby_chat.xml9
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_object.xml29
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_object_icon.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_outfit_gear.xml27
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_outfit_tab.xml9
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_participant_list.xml21
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_people_friends_view_sort.xml8
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_people_groups.xml8
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_people_groups_view_sort.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_people_nearby.xml13
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_people_nearby_multiselect.xml10
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_people_nearby_view_sort.xml8
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_people_recent_view_sort.xml7
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_picks.xml8
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_picks_plus.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_place.xml7
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_place_add_button.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_places_gear_folder.xml15
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_places_gear_landmark.xml18
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_profile_overflow.xml12
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_slurl.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_teleport_history_gear.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_teleport_history_item.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_teleport_history_tab.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_text_editor.xml8
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_topinfobar.xml7
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_url_agent.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_url_group.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_url_http.xml7
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_url_inventory.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_url_map.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_url_objectim.xml8
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_url_parcel.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_url_slapp.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_url_slurl.xml7
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_url_teleport.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_viewer.xml14
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_wearable_list_item.xml14
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_wearing_gear.xml5
-rw-r--r--indra/newview/skins/minimal/xui/fr/menu_wearing_tab.xml6
-rw-r--r--indra/newview/skins/minimal/xui/fr/panel_bottomtray.xml39
-rw-r--r--indra/newview/skins/minimal/xui/fr/panel_im_control_panel.xml30
-rw-r--r--indra/newview/skins/minimal/xui/fr/panel_login.xml40
-rw-r--r--indra/newview/skins/minimal/xui/fr/panel_navigation_bar.xml18
-rw-r--r--indra/newview/skins/minimal/xui/fr/panel_people.xml71
-rw-r--r--indra/newview/skins/minimal/xui/fr/panel_side_tray_tab_caption.xml7
-rw-r--r--indra/newview/skins/minimal/xui/fr/panel_status_bar.xml33
-rw-r--r--indra/newview/skins/minimal/xui/pt/floater_camera.xml65
-rw-r--r--indra/newview/skins/minimal/xui/pt/floater_help_browser.xml9
-rw-r--r--indra/newview/skins/minimal/xui/pt/floater_nearby_chat.xml4
-rw-r--r--indra/newview/skins/minimal/xui/pt/inspect_avatar.xml24
-rw-r--r--indra/newview/skins/minimal/xui/pt/inspect_object.xml41
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_add_wearable_gear.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_attachment_other.xml17
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_attachment_self.xml16
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_avatar_icon.xml7
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_avatar_other.xml16
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_avatar_self.xml31
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_bottomtray.xml17
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_cof_attachment.xml4
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_cof_body_part.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_cof_clothing.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_cof_gear.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_edit.xml12
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_favorites.xml10
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_gesture_gear.xml10
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_group_plus.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_hide_navbar.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_im_well_button.xml4
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_imchiclet_adhoc.xml4
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_imchiclet_group.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_imchiclet_p2p.xml7
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_inspect_avatar_gear.xml17
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_inspect_object_gear.xml18
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml10
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_inv_offer_chiclet.xml4
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_inventory.xml86
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_inventory_add.xml33
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_inventory_gear_default.xml16
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_land.xml9
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_landmark.xml7
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_login.xml24
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_mini_map.xml11
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_navbar.xml11
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_nearby_chat.xml9
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_notification_well_button.xml4
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_object.xml29
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_object_icon.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_outfit_gear.xml27
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_outfit_tab.xml9
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_participant_list.xml21
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_people_friends_view_sort.xml8
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_people_groups.xml8
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_people_groups_view_sort.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_people_nearby.xml13
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_people_nearby_multiselect.xml10
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_people_nearby_view_sort.xml8
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_people_recent_view_sort.xml7
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_picks.xml8
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_picks_plus.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_place.xml7
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_place_add_button.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_places_gear_folder.xml15
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_places_gear_landmark.xml18
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_profile_overflow.xml12
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_save_outfit.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_script_chiclet.xml4
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_slurl.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_teleport_history_gear.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_teleport_history_item.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_teleport_history_tab.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_text_editor.xml8
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_topinfobar.xml7
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_url_agent.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_url_group.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_url_http.xml7
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_url_inventory.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_url_map.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_url_objectim.xml8
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_url_parcel.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_url_slapp.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_url_slurl.xml7
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_url_teleport.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_viewer.xml14
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_wearable_list_item.xml14
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_wearing_gear.xml5
-rw-r--r--indra/newview/skins/minimal/xui/pt/menu_wearing_tab.xml6
-rw-r--r--indra/newview/skins/minimal/xui/pt/panel_adhoc_control_panel.xml14
-rw-r--r--indra/newview/skins/minimal/xui/pt/panel_bottomtray.xml39
-rw-r--r--indra/newview/skins/minimal/xui/pt/panel_im_control_panel.xml29
-rw-r--r--indra/newview/skins/minimal/xui/pt/panel_login.xml40
-rw-r--r--indra/newview/skins/minimal/xui/pt/panel_navigation_bar.xml18
-rw-r--r--indra/newview/skins/minimal/xui/pt/panel_people.xml71
-rw-r--r--indra/newview/skins/minimal/xui/pt/panel_side_tray_tab_caption.xml7
-rw-r--r--indra/newview/skins/minimal/xui/pt/panel_status_bar.xml33
-rw-r--r--indra/newview/viewer_manifest.py1950
515 files changed, 45910 insertions, 34982 deletions
diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt
index af6beacdfa..66869288b6 100644
--- a/indra/newview/CMakeLists.txt
+++ b/indra/newview/CMakeLists.txt
@@ -246,6 +246,7 @@ set(viewer_SOURCE_FILES
llhudeffectlookat.cpp
llhudeffectpointat.cpp
llhudeffecttrail.cpp
+ llhudeffectblob.cpp
llhudicon.cpp
llhudmanager.cpp
llhudnametag.cpp
@@ -786,6 +787,7 @@ set(viewer_HEADER_FILES
llhudeffectlookat.h
llhudeffectpointat.h
llhudeffecttrail.h
+ llhudeffectblob.h
llhudicon.h
llhudmanager.h
llhudnametag.h
@@ -1298,22 +1300,20 @@ endif (WINDOWS)
set(viewer_XUI_FILES
skins/default/colors.xml
skins/default/textures/textures.xml
+ skins/minimal/colors.xml
+ skins/minimal/textures/textures.xml
)
file(GLOB DEFAULT_XUI_FILE_GLOB_LIST
- ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui/en/*.xml)
+ ${CMAKE_CURRENT_SOURCE_DIR}/skins/*/xui/en/*.xml)
list(APPEND viewer_XUI_FILES ${DEFAULT_XUI_FILE_GLOB_LIST})
file(GLOB DEFAULT_WIDGET_FILE_GLOB_LIST
- ${CMAKE_CURRENT_SOURCE_DIR}/skins/default/xui/en/widgets/*.xml)
+ ${CMAKE_CURRENT_SOURCE_DIR}/skins/*/xui/en/widgets/*.xml)
list(APPEND viewer_XUI_FILES ${DEFAULT_WIDGET_FILE_GLOB_LIST})
-file(GLOB SILVER_XUI_FILE_GLOB_LIST
- ${CMAKE_CURRENT_SOURCE_DIR}/skins/silver/xui/en-us/*.xml)
-list(APPEND viewer_XUI_FILES ${SILVER_XUI_FILE_GLOB_LIST})
-
# Cannot append empty lists in CMake, wait until we have files here.
#file(GLOB SILVER_WIDGET_FILE_GLOB_LIST
# ${CMAKE_CURRENT_SOURCE_DIR}/skins/silver/xui/en-us/widgets/*.xml)
@@ -1343,6 +1343,7 @@ set(viewer_APPSETTINGS_FILES
app_settings/settings_crash_behavior.xml
app_settings/settings_files.xml
app_settings/settings_per_account.xml
+ app_settings/settings_minimal.xml
app_settings/std_bump.ini
app_settings/trees.xml
app_settings/ultra_graphics.xml
diff --git a/indra/newview/app_settings/CA.pem b/indra/newview/app_settings/CA.pem
index 11825bf906..7cebbf48b2 100644
--- a/indra/newview/app_settings/CA.pem
+++ b/indra/newview/app_settings/CA.pem
@@ -3895,3 +3895,22 @@ xA39CIJ65Zozs28Eg1aV9/Y+Of7TnWhW+U3J3/wD/GghaAGiKK6vMn9gJBIdBX/9
e6ef37VGyiOEFFjnUIbuk0RWty0orN76q/lI/xjCi15XSA/VSq2j4vmnwfZcPTDu
glmQ1A==
-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDIDCCAomgAwIBAgIENd70zzANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJV
+UzEQMA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2Vy
+dGlmaWNhdGUgQXV0aG9yaXR5MB4XDTk4MDgyMjE2NDE1MVoXDTE4MDgyMjE2NDE1
+MVowTjELMAkGA1UEBhMCVVMxEDAOBgNVBAoTB0VxdWlmYXgxLTArBgNVBAsTJEVx
+dWlmYXggU2VjdXJlIENlcnRpZmljYXRlIEF1dGhvcml0eTCBnzANBgkqhkiG9w0B
+AQEFAAOBjQAwgYkCgYEAwV2xWGcIYu6gmi0fCG2RFGiYCh7+2gRvE4RiIcPRfM6f
+BeC4AfBONOziipUEZKzxa1NfBbPLZ4C/QgKO/t0BCezhABRP/PvwDN1Dulsr4R+A
+cJkVV5MW8Q+XarfCaCMczE1ZMKxRHjuvK9buY0V7xdlfUNLjUA86iOe/FP3gx7kC
+AwEAAaOCAQkwggEFMHAGA1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEQ
+MA4GA1UEChMHRXF1aWZheDEtMCsGA1UECxMkRXF1aWZheCBTZWN1cmUgQ2VydGlm
+aWNhdGUgQXV0aG9yaXR5MQ0wCwYDVQQDEwRDUkwxMBoGA1UdEAQTMBGBDzIwMTgw
+ODIyMTY0MTUxWjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUSOZo+SvSspXXR9gj
+IBBPM5iQn9QwHQYDVR0OBBYEFEjmaPkr0rKV10fYIyAQTzOYkJ/UMAwGA1UdEwQF
+MAMBAf8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUA
+A4GBAFjOKer89961zgK5F7WF0bnj4JXMJTENAKaSbn+2kmOeUJXRmm/kEd5jhW6Y
+7qj/WsjTVbJmcVfewCHrPSqnI0kBBIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh
+1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee9570+sB3c4
+-----END CERTIFICATE-----
diff --git a/indra/newview/app_settings/cmd_line.xml b/indra/newview/app_settings/cmd_line.xml
index e4ac455e7c..89e5949fbe 100644
--- a/indra/newview/app_settings/cmd_line.xml
+++ b/indra/newview/app_settings/cmd_line.xml
@@ -261,6 +261,24 @@
<!-- Special case. Mapped to settings procedurally. -->
</map>
+ <key>sessionsettings</key>
+ <map>
+ <key>desc</key>
+ <string>Specify the filename of a configuration file that contains temporary per-session configuration overrides.</string>
+ <key>count</key>
+ <integer>1</integer>
+ <!-- Special case. Mapped to settings procedurally. -->
+ </map>
+
+ <key>usersessionsettings</key>
+ <map>
+ <key>desc</key>
+ <string>Specify the filename of a configuration file that contains temporary per-session configuration user overrides.</string>
+ <key>count</key>
+ <integer>1</integer>
+ <!-- Special case. Mapped to settings procedurally. -->
+ </map>
+
<key>login</key>
<map>
<key>desc</key>
diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml
index a010524091..6a89f5681d 100644
--- a/indra/newview/app_settings/settings.xml
+++ b/indra/newview/app_settings/settings.xml
@@ -617,7 +617,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
- <string>http://interest.secondlife.com/viewer/avatar</string>
+ <string></string>
</map>
<key>AvatarBakedTextureUploadTimeout</key>
<map>
@@ -2566,7 +2566,7 @@
<key>Type</key>
<string>String</string>
<key>Value</key>
- <string>http://www.secondlife.com</string>
+ <string></string>
</map>
<key>DisableCameraConstraints</key>
<map>
@@ -2810,6 +2810,17 @@
<key>Value</key>
<integer>0</integer>
</map>
+ <key>DoubleClickShowWorldMap</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable double-click to show world map from mini map</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
<key>DragAndDropToolTipDelay</key>
<map>
<key>Comment</key>
@@ -3888,6 +3899,17 @@
<key>Value</key>
<string>https://my.secondlife.com/[AGENT_NAME]</string>
</map>
+ <key>WebProfileNonProductionURL</key>
+ <map>
+ <key>Comment</key>
+ <string>URL for Web Profiles on Non-Production grids</string>
+ <key>Persist</key>
+ <integer>0</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>https://my-demo.secondlife.com/[AGENT_NAME]</string>
+ </map>
<key>HighResSnapshot</key>
<map>
<key>Comment</key>
@@ -11484,7 +11506,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <integer>3.0</integer>
+ <integer>3</integer>
</map>
<key>InterpolationPhaseOut</key>
<map>
@@ -11495,7 +11517,7 @@
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <integer>1.0</integer>
+ <integer>1</integer>
</map>
<key>VerboseLogs</key>
<map>
@@ -12344,38 +12366,225 @@
<key>Value</key>
<real>1200.0</real>
</map>
- <key>AvatarPickerHintTimeout</key>
+ <key>SidePanelHintTimeout</key>
<map>
<key>Comment</key>
- <string>Number of seconds to wait before telling resident about avatar picker.</string>
+ <string>Number of seconds to wait before telling resident about side panel.</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>F32</string>
<key>Value</key>
- <real>600.0</real>
+ <real>300.0</real>
+ </map>
+ <key>GroupMembersSortOrder</key>
+ <map>
+ <key>Comment</key>
+ <string>The order by which group members will be sorted (name|donated|online)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>name</string>
</map>
- <key>SidePanelHintTimeout</key>
+ <key>SessionSettingsFile</key>
<map>
<key>Comment</key>
- <string>Number of seconds to wait before telling resident about side panel.</string>
+ <string>Settings that are a applied per session (not saved).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
- <string>F32</string>
+ <string>String</string>
<key>Value</key>
- <real>300.0</real>
+ <string></string>
</map>
- <key>GroupMembersSortOrder</key>
+ <key>UserSessionSettingsFile</key>
<map>
<key>Comment</key>
- <string>The order by which group members will be sorted (name|donated|online)</string>
+ <string>User settings that are a applied per session (not saved).</string>
<key>Persist</key>
<integer>1</integer>
<key>Type</key>
<string>String</string>
<key>Value</key>
- <string>name</string>
+ <string />
+ </map>
+ <key>OpenSidePanelsInFloaters</key>
+ <map>
+ <key>Comment</key>
+ <string>If true, will always open side panel contents in a floater.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>AvatarInspectorTooltipDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds before displaying avatar inspector tooltip</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.35</real>
+ </map>
+ <key>ObjectInspectorTooltipDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds before displaying object inspector tooltip</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.35</real>
+ </map>
+ <key>SLURLTeleportDirectly</key>
+ <map>
+ <key>Comment</key>
+ <string>Clicking on a slurl will teleport you directly instead of opening places panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableClassifieds</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable creation of new classified ads from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableGroupInfo</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable viewing and editing of group info from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnablePicks</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable editing of picks from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableWorldMap</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable opening world map from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableAvatarPay</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable paying other avatars from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableVoiceCall</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable voice calls from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableAvatarShare</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable sharing from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>SearchFromAddressBar</key>
+ <map>
+ <key>Comment</key>
+ <string>Can enter search queries into navigation address bar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>LogInventoryDecline</key>
+ <map>
+ <key>Comment</key>
+ <string>Log in system chat whenever an inventory offer is declined</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>UseHTTPInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow use of http inventory transfers instead of UDP</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ClickToWalk</key>
+ <map>
+ <key>Comment</key>
+ <string>Click in world to walk to location</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowOfferedInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Show inventory window with last inventory offer selected when receiving inventory from other users.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
</map>
</map>
</llsd>
diff --git a/indra/newview/app_settings/settings_files.xml b/indra/newview/app_settings/settings_files.xml
index aa5b301959..079a54f957 100644
--- a/indra/newview/app_settings/settings_files.xml
+++ b/indra/newview/app_settings/settings_files.xml
@@ -1,148 +1,64 @@
-<llsd>
- <map>
- <key>Locations</key>
- <map>
- <!--
- The Locations LLSD block specifies the usage pattern of
- the settings file types
- Each location is represented by a LLSD containing the following values:
- PathIndex = hard coded path indicies.
- Files = map of files to load
- Each file can have:
- Requirement = level of necessity for loading.
- 0 ( or Req. no key) = do not load
- 1 = required, fail if not found
- NameFromSetting = Use the given setting to specify the name. Not valid for
- "Default"
- -->
- <key>Comment</key>
- <string>List location from which to load files, and the rules about loading those files.</string>
- <key>Persist</key>
- <integer>0</integer>
- <key>Type</key>
- <string>LLSD</string>
- <key>Value</key>
- <map>
- <key>Default</key>
- <map>
- <key>PathIndex</key>
- <integer>2</integer>
- <key>Files</key>
- <map>
- <key>Global</key>
- <map>
- <key>Name</key>
- <string>settings.xml</string>
- <key>Requirement</key>
- <integer>1</integer>
- </map>
- <key>PerAccount</key>
- <map>
- <key>Name</key>
- <string>settings_per_account.xml</string>
- <key>Requirement</key>
- <integer>1</integer>
- </map>
- <key>CrashSettings</key>
- <map>
- <key>Name</key>
- <string>settings_crash_behavior.xml</string>
- <key>Requirement</key>
- <integer>1</integer>
- </map>
- <key>Warnings</key>
- <map>
- <key>Name</key>
- <string>ignorable_dialogs.xml</string>
- <key>Requirement</key>
- <integer>1</integer>
- </map>
- </map>
- </map>
- <key>User</key>
- <map>
- <key>PathIndex</key>
- <integer>1</integer>
- <key>Files</key>
- <map>
- <key>Global</key>
- <map>
- <key>Name</key>
- <string>settings.xml</string>
- <key>NameFromSetting</key>
- <string>ClientSettingsFile</string>
- </map>
- <key>CrashSettings</key>
- <map>
- <key>Name</key>
- <string>settings_crash_behavior.xml</string>
- </map>
- <key>Warnings</key>
- <map>
- <key>Name</key>
- <string>ignorable_dialogs.xml</string>
- <key>NameFromSetting</key>
- <string>WarningSettingsFile</string>
- </map>
- </map>
- </map>
- <key>Account</key>
- <map>
- <key>PathIndex</key>
- <integer>3</integer>
- <key>Files</key>
- <map>
- <key>PerAccount</key>
- <map>
- <key>Name</key>
- <string>settings_per_account.xml</string>
- <key>NameFromSetting</key>
- <string>PerAccountSettingsFile</string>
- </map>
- </map>
- </map>
- <key>DefaultSkin</key>
- <map>
- <key>PathIndex</key>
- <integer>17</integer>
- <key>Files</key>
- <map>
- <key>Skinning</key>
- <map>
- <key>Name</key>
- <string>colors.xml</string>
- </map>
- </map>
- </map>
- <key>CurrentSkin</key>
- <map>
- <key>PathIndex</key>
- <integer>10</integer>
- <key>Files</key>
- <map>
- <key>Skinning</key>
- <map>
- <key>Name</key>
- <string>colors.xml</string>
- </map>
- </map>
- </map>
- <key>UserSkin</key>
- <map>
- <key>PathIndex</key>
- <integer>14</integer>
- <key>Files</key>
- <map>
- <key>Skinning</key>
- <map>
- <key>Name</key>
- <string>colors.xml</string>
- <key>NameFromSetting</key>
- <string>SkinningSettingsFile</string>
- </map>
- </map>
- </map>
- </map>
- </map>
- </map>
-</llsd>
+<settings_files>
+ <group name="Default"
+ path_index="2">
+ <file name="Global"
+ file_name="settings.xml"
+ required="true"/>
+ <file name="PerAccount"
+ file_name="settings_per_account.xml"
+ required="true"/>
+ <file name="CrashSettings"
+ file_name="settings_crash_behavior.xml"
+ required="true"/>
+ <file name="Warnings"
+ file_name="ignorable_dialogs.xml"
+ required="true"/>
+ </group>
+ <group name="User"
+ path_index="1">
+ <file name="Global"
+ file_name="settings.xml"
+ file_name_setting="ClientSettingsFile"/>
+ <file name="CrashSettings"
+ file_name="settings_crash_behavior"/>
+ <file name="Warnings"
+ file_name="ignorable_dialogs.xml"
+ file_name_setting="WarningSettingsFile"/>
+ </group>
+ <group name="Account"
+ path_index="3">
+ <file name="PerAccount"
+ file_name="settings_per_account.xml"
+ file_name_setting="PerAccountSettingsFile"/>
+ </group>
+ <group name="Session"
+ path_index="2">
+ <file name="Global"
+ file_name="session.xml"
+ file_name_setting="SessionSettingsFile"
+ persistent="false"/>
+ </group>
+ <group name="UserSession"
+ path_index="1">
+ <file name="Global"
+ file_name="session.xml"
+ file_name_setting="UserSessionSettingsFile"
+ persistent="false"/>
+ </group>
+ <group name="DefaultSkin"
+ path_index="17">
+ <file name="Skinning"
+ file_name="colors.xml"/>
+ </group>
+ <group name="CurrentSkin"
+ path_index="10">
+ <file name="Skinning"
+ file_name="colors.xml"/>
+ </group>
+ <group name="UserSkin"
+ path_index="14">
+ <file name="Skinning"
+ file_name="colors.xml"
+ file_name_setting="SkinningSettingsFile"/>
+ </group>
+</settings_files> \ No newline at end of file
diff --git a/indra/newview/app_settings/settings_minimal.xml b/indra/newview/app_settings/settings_minimal.xml
new file mode 100644
index 0000000000..03656f2a53
--- /dev/null
+++ b/indra/newview/app_settings/settings_minimal.xml
@@ -0,0 +1,406 @@
+<llsd>
+ <map>
+ <key>ChannelBottomPanelMargin</key>
+ <map>
+ <key>Comment</key>
+ <string>Space from a lower toast to the Bottom Tray</string>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>2</integer>
+ </map>
+ <key>ClickActionBuyEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable click to buy actions in tool pie menu</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ClickActionPayEnabled</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable click to pay actions in tool pie menu</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableGrab</key>
+ <map>
+ <key>Comment</key>
+ <string>Use Ctrl+mouse to grab and manipulate objects</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableMouselook</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow first person perspective and mouse control of camera</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableVoiceChat</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable talking to other residents with a microphone</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>HelpURLFormat</key>
+ <map>
+ <key>Comment</key>
+ <string>URL pattern for help page; arguments will be encoded; see llviewerhelp.cpp:buildHelpURL for arguments</string>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/damballah/howto/index.html?topic=[TOPIC]</string>
+ </map>
+ <key>PreferredMaturity</key>
+ <map>
+ <key>Comment</key>
+ <string>Setting for the user&apos;s preferred maturity level (consts in indra_constants.h)</string>
+ <key>Type</key>
+ <string>U32</string>
+ <key>Value</key>
+ <integer>21</integer>
+ </map>
+ <key>RenderTrackerBeacon</key>
+ <map>
+ <key>Comment</key>
+ <string>Display tracking arrow and beacon to target avatar, teleport destination</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowScriptErrors</key>
+ <map>
+ <key>Comment</key>
+ <string>Show script errors</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ShowScriptErrorsLocation</key>
+ <map>
+ <key>Comment</key>
+ <string>Show script error in chat or window</string>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SkinCurrent</key>
+ <map>
+ <key>Comment</key>
+ <string>The currently selected skin.</string>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>minimal</string>
+ </map>
+ <key>UseExternalBrowser</key>
+ <map>
+ <key>Comment</key>
+ <string>Use default browser when opening web pages instead of in-world browser.</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>VoiceCallsRejectAll</key>
+ <map>
+ <key>Comment</key>
+ <string>Silently reject all incoming voice calls.</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>VoiceDisableMic</key>
+ <map>
+ <key>Comment</key>
+ <string>Completely disable the ability to open the mic.</string>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ScriptsCanShowUI</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow LSL calls (such as LLMapDestination) to spawn viewer UI</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ChatFontSize</key>
+ <map>
+ <key>Comment</key>
+ <string>Size of chat text in chat console (0 = small, 1 = big, 2 = extra large)</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AvatarPickerHintTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>Number of seconds to wait before telling resident about avatar picker.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.0</real>
+ </map>
+ <key>RenderShowGroupTitleAll</key>
+ <map>
+ <key>Comment</key>
+ <string>Show group titles in name labels</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>OpenSidePanelsInFloaters</key>
+ <map>
+ <key>Comment</key>
+ <string>If true, will always open side panel contents in a floater.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>AvatarInspectorTooltipDelay</key>
+ <map>
+ <key>Comment</key>
+ <string>Seconds before displaying avatar inspector tooltip</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>F32</string>
+ <key>Value</key>
+ <real>0.1</real>
+ </map>
+ <key>AFKTimeout</key>
+ <map>
+ <key>Comment</key>
+ <string>
+ Time before automatically setting AFK (away from keyboard) mode (seconds, 0=never).
+ Valid values are: 0, 120, 300, 600, 1800
+ </string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>S32</string>
+ <key>Value</key>
+ <real>0</real>
+ </map>
+ <key>SLURLTeleportDirectly</key>
+ <map>
+ <key>Comment</key>
+ <string>Clicking on a slurl will teleport you directly instead of opening places panel</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>EnableClassifieds</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable creation of new classified ads</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableGroupInfo</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable viewing and editing of group info.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnablePicks</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable editing of picks</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableWorldMap</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable opening world map from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableAvatarPay</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable paying other avatars from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableVoiceCall</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable voice calls from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableAvatarShare</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable sharing from web link</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DoubleClickShowWorldMap</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable double-click to show world map from mini map</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>EnableGroupChatPopups</key>
+ <map>
+ <key>Comment</key>
+ <string>Enable Incoming Group Chat Popups</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>SearchFromAddressBar</key>
+ <map>
+ <key>Comment</key>
+ <string>Can enter search queries into navigation address bar</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>DestinationGuideURL</key>
+ <map>
+ <key>Comment</key>
+ <string>Destination guide contents</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/damballah/guide.html</string>
+ </map>
+ <key>AvatarPickerURL</key>
+ <map>
+ <key>Comment</key>
+ <string>Avatar picker contents</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>String</string>
+ <key>Value</key>
+ <string>http://common-flash-secondlife-com.s3.amazonaws.com/viewer/v2.6/damballah/avatars.html</string>
+ </map>
+ <key>LogInventoryDecline</key>
+ <map>
+ <key>Comment</key>
+ <string>Log in system chat whenever an inventory offer is declined</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>UseHTTPInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Allow use of http inventory transfers instead of UDP</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ <key>ClickToWalk</key>
+ <map>
+ <key>Comment</key>
+ <string>Click in world to walk to location</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>1</integer>
+ </map>
+ <key>ShowOfferedInventory</key>
+ <map>
+ <key>Comment</key>
+ <string>Show inventory window with last inventory offer selected when receiving inventory from other users.</string>
+ <key>Persist</key>
+ <integer>1</integer>
+ <key>Type</key>
+ <string>Boolean</string>
+ <key>Value</key>
+ <integer>0</integer>
+ </map>
+ </map>
+</llsd>
diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp
index f40fed5ad3..1cf552e42c 100644
--- a/indra/newview/llappearancemgr.cpp
+++ b/indra/newview/llappearancemgr.cpp
@@ -2979,6 +2979,9 @@ public:
gAgent.setGenderChosen(TRUE);
}
+ // release avatar picker keyboard focus
+ gFocusMgr.setKeyboardFocus( NULL );
+
return true;
}
};
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 327a5ad698..6d61be84ef 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -1,5038 +1,5137 @@
-/**
- * @file llappviewer.cpp
- * @brief The LLAppViewer class definitions
- *
- * $LicenseInfo:firstyear=2007&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llappviewer.h"
-
-// Viewer includes
-#include "llversioninfo.h"
-#include "llversionviewer.h"
-#include "llfeaturemanager.h"
-#include "lluictrlfactory.h"
-#include "lltexteditor.h"
-#include "llerrorcontrol.h"
-#include "lleventtimer.h"
-#include "llviewertexturelist.h"
-#include "llgroupmgr.h"
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llagentlanguage.h"
-#include "llagentwearables.h"
-#include "llwindow.h"
-#include "llviewerstats.h"
-#include "llviewerstatsrecorder.h"
-#include "llmd5.h"
-#include "llpumpio.h"
-#include "llmimetypes.h"
-#include "llslurl.h"
-#include "llstartup.h"
-#include "llfocusmgr.h"
-#include "llviewerjoystick.h"
-#include "llallocator.h"
-#include "llares.h"
-#include "llcurl.h"
-#include "lltexturestats.h"
-#include "lltexturestats.h"
-#include "llviewerwindow.h"
-#include "llviewerdisplay.h"
-#include "llviewermedia.h"
-#include "llviewerparcelmedia.h"
-#include "llviewermediafocus.h"
-#include "llviewermessage.h"
-#include "llviewerobjectlist.h"
-#include "llworldmap.h"
-#include "llmutelist.h"
-#include "llviewerhelp.h"
-#include "lluicolortable.h"
-#include "llurldispatcher.h"
-#include "llurlhistory.h"
-//#include "llfirstuse.h"
-#include "llrender.h"
-#include "llteleporthistory.h"
-#include "lllocationhistory.h"
-#include "llfasttimerview.h"
-#include "llvoicechannel.h"
-#include "llvoavatarself.h"
-#include "llsidetray.h"
-#include "llfeaturemanager.h"
-#include "llurlmatch.h"
-#include "lltextutil.h"
-#include "lllogininstance.h"
-#include "llprogressview.h"
-
-#include "llweb.h"
-#include "llsecondlifeurls.h"
-#include "llupdaterservice.h"
-
-// Linden library includes
-#include "llavatarnamecache.h"
-#include "llimagej2c.h"
-#include "llmemory.h"
-#include "llprimitive.h"
-#include "llurlaction.h"
-#include "llurlentry.h"
-#include "llvfile.h"
-#include "llvfsthread.h"
-#include "llvolumemgr.h"
-#include "llxfermanager.h"
-
-#include "llnotificationmanager.h"
-#include "llnotifications.h"
-#include "llnotificationsutil.h"
-
-// Third party library includes
-#include <boost/bind.hpp>
-
-
-#if LL_WINDOWS
-# include <share.h> // For _SH_DENYWR in initMarkerFile
-#else
-# include <sys/file.h> // For initMarkerFile support
-#endif
-
-#include "llapr.h"
-#include "apr_dso.h"
-#include <boost/lexical_cast.hpp>
-
-#include "llviewerkeyboard.h"
-#include "lllfsthread.h"
-#include "llworkerthread.h"
-#include "lltexturecache.h"
-#include "lltexturefetch.h"
-#include "llimageworker.h"
-#include "llevents.h"
-
-// The files below handle dependencies from cleanup.
-#include "llkeyframemotion.h"
-#include "llworldmap.h"
-#include "llhudmanager.h"
-#include "lltoolmgr.h"
-#include "llassetstorage.h"
-#include "llpolymesh.h"
-#include "llcachename.h"
-#include "llaudioengine.h"
-#include "llstreamingaudio.h"
-#include "llviewermenu.h"
-#include "llselectmgr.h"
-#include "lltrans.h"
-#include "lltransutil.h"
-#include "lltracker.h"
-#include "llviewerparcelmgr.h"
-#include "llworldmapview.h"
-#include "llpostprocess.h"
-#include "llwlparammanager.h"
-#include "llwaterparammanager.h"
-
-#include "lldebugview.h"
-#include "llconsole.h"
-#include "llcontainerview.h"
-#include "lltooltip.h"
-
-#include "llsdserialize.h"
-
-#include "llworld.h"
-#include "llhudeffecttrail.h"
-#include "llvectorperfoptions.h"
-#include "llslurl.h"
-#include "llwatchdog.h"
-
-// Included so that constants/settings might be initialized
-// in save_settings_to_globals()
-#include "llbutton.h"
-#include "llstatusbar.h"
-#include "llsurface.h"
-#include "llvosky.h"
-#include "llvotree.h"
-#include "llvoavatar.h"
-#include "llfolderview.h"
-#include "llagentpilot.h"
-#include "llvovolume.h"
-#include "llflexibleobject.h"
-#include "llvosurfacepatch.h"
-#include "llviewerfloaterreg.h"
-#include "llcommandlineparser.h"
-#include "llfloatermemleak.h"
-#include "llfloaterreg.h"
-#include "llfloatersnapshot.h"
-#include "llfloaterinventory.h"
-
-// includes for idle() idleShutdown()
-#include "llviewercontrol.h"
-#include "lleventnotifier.h"
-#include "llcallbacklist.h"
-#include "pipeline.h"
-#include "llgesturemgr.h"
-#include "llsky.h"
-#include "llvlmanager.h"
-#include "llviewercamera.h"
-#include "lldrawpoolbump.h"
-#include "llvieweraudio.h"
-#include "llimview.h"
-#include "llviewerthrottle.h"
-#include "llparcel.h"
-#include "llavatariconctrl.h"
-#include "llgroupiconctrl.h"
-#include "llviewerassetstats.h"
-
-// Include for security api initialization
-#include "llsecapi.h"
-#include "llmachineid.h"
-
-#include "llmainlooprepeater.h"
-
-// *FIX: These extern globals should be cleaned up.
-// The globals either represent state/config/resource-storage of either
-// this app, or another 'component' of the viewer. App globals should be
-// moved into the app class, where as the other globals should be
-// moved out of here.
-// If a global symbol reference seems valid, it will be included
-// via header files above.
-
-//----------------------------------------------------------------------------
-// llviewernetwork.h
-#include "llviewernetwork.h"
-// define a self-registering event API object
-#include "llappviewerlistener.h"
-
-#if (LL_LINUX || LL_SOLARIS) && LL_GTK
-#include "glib.h"
-#endif // (LL_LINUX || LL_SOLARIS) && LL_GTK
-
-#if LL_MSVC
-// disable boost::lexical_cast warning
-#pragma warning (disable:4702)
-#endif
-
-static LLAppViewerListener sAppViewerListener(LLAppViewer::instance);
-
-////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor
-//
-//----------------------------------------------------------------------------
-// viewer.cpp - these are only used in viewer, should be easily moved.
-
-#if LL_DARWIN
-extern void init_apple_menu(const char* product);
-#endif // LL_DARWIN
-
-extern BOOL gRandomizeFramerate;
-extern BOOL gPeriodicSlowFrame;
-extern BOOL gDebugGL;
-
-////////////////////////////////////////////////////////////
-// All from the last globals push...
-const F32 DEFAULT_AFK_TIMEOUT = 5.f * 60.f; // time with no input before user flagged as Away From Keyboard
-
-F32 gSimLastTime; // Used in LLAppViewer::init and send_stats()
-F32 gSimFrames;
-
-BOOL gShowObjectUpdates = FALSE;
-BOOL gUseQuickTime = TRUE;
-
-eLastExecEvent gLastExecEvent = LAST_EXEC_NORMAL;
-
-LLSD gDebugInfo;
-
-U32 gFrameCount = 0;
-U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground
-LLPumpIO* gServicePump = NULL;
-
-U64 gFrameTime = 0;
-F32 gFrameTimeSeconds = 0.f;
-F32 gFrameIntervalSeconds = 0.f;
-F32 gFPSClamped = 10.f; // Pretend we start at target rate.
-F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets
-U64 gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds
-U32 gFrameStalls = 0;
-const F64 FRAME_STALL_THRESHOLD = 1.0;
-
-LLTimer gRenderStartTime;
-LLFrameTimer gForegroundTime;
-LLFrameTimer gLoggedInTime;
-LLTimer gLogoutTimer;
-static const F32 LOGOUT_REQUEST_TIME = 6.f; // this will be cut short by the LogoutReply msg.
-F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME;
-
-BOOL gDisconnected = FALSE;
-
-// used to restore texture state after a mode switch
-LLFrameTimer gRestoreGLTimer;
-BOOL gRestoreGL = FALSE;
-BOOL gUseWireframe = FALSE;
-
-// VFS globals - see llappviewer.h
-LLVFS* gStaticVFS = NULL;
-
-LLMemoryInfo gSysMemory;
-U64 gMemoryAllocated = 0; // updated in display_stats() in llviewerdisplay.cpp
-
-std::string gLastVersionChannel;
-
-LLVector3 gWindVec(3.0, 3.0, 0.0);
-LLVector3 gRelativeWindVec(0.0, 0.0, 0.0);
-
-U32 gPacketsIn = 0;
-
-BOOL gPrintMessagesThisFrame = FALSE;
-
-BOOL gRandomizeFramerate = FALSE;
-BOOL gPeriodicSlowFrame = FALSE;
-
-BOOL gCrashOnStartup = FALSE;
-BOOL gLLErrorActivated = FALSE;
-BOOL gLogoutInProgress = FALSE;
-
-////////////////////////////////////////////////////////////
-// Internal globals... that should be removed.
-static std::string gArgs;
-
-const std::string MARKER_FILE_NAME("SecondLife.exec_marker");
-const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker");
-const std::string LLERROR_MARKER_FILE_NAME("SecondLife.llerror_marker");
-const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker");
-static BOOL gDoDisconnect = FALSE;
-static std::string gLaunchFileOnQuit;
-
-// Used on Win32 for other apps to identify our window (eg, win_setup)
-const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
-
-//----------------------------------------------------------------------------
-
-// List of entries from strings.xml to always replace
-static std::set<std::string> default_trans_args;
-void init_default_trans_args()
-{
- default_trans_args.insert("SECOND_LIFE"); // World
- default_trans_args.insert("APP_NAME");
- default_trans_args.insert("CAPITALIZED_APP_NAME");
- default_trans_args.insert("SECOND_LIFE_GRID");
- default_trans_args.insert("SUPPORT_SITE");
-}
-
-//----------------------------------------------------------------------------
-// File scope definitons
-const char *VFS_DATA_FILE_BASE = "data.db2.x.";
-const char *VFS_INDEX_FILE_BASE = "index.db2.x.";
-
-static std::string gWindowTitle;
-
-LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
-
-//----------------------------------------------------------------------------
-// Metrics logging control constants
-//----------------------------------------------------------------------------
-static const F32 METRICS_INTERVAL_DEFAULT = 600.0;
-static const F32 METRICS_INTERVAL_QA = 30.0;
-static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT;
-static bool app_metrics_qa_mode = false;
-
-void idle_afk_check()
-{
- // check idle timers
- if (gSavedSettings.getS32("AFKTimeout") && (gAwayTriggerTimer.getElapsedTimeF32() > gSavedSettings.getS32("AFKTimeout")))
- {
- gAgent.setAFK();
- }
-}
-
-// A callback set in LLAppViewer::init()
-static void ui_audio_callback(const LLUUID& uuid)
-{
- if (gAudiop)
- {
- gAudiop->triggerSound(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
- }
-}
-
-bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base)
-{
- if(!match || !base || base->getPlainText())
- return false;
-
- LLUUID match_id = match->getID();
-
- LLIconCtrl* icon;
-
- if(gAgent.isInGroup(match_id, TRUE))
- {
- LLGroupIconCtrl::Params icon_params;
- icon_params.group_id = match_id;
- icon_params.rect = LLRect(0, 16, 16, 0);
- icon_params.visible = true;
- icon = LLUICtrlFactory::instance().create<LLGroupIconCtrl>(icon_params);
- }
- else
- {
- LLAvatarIconCtrl::Params icon_params;
- icon_params.avatar_id = match_id;
- icon_params.rect = LLRect(0, 16, 16, 0);
- icon_params.visible = true;
- icon = LLUICtrlFactory::instance().create<LLAvatarIconCtrl>(icon_params);
- }
-
- LLInlineViewSegment::Params params;
- params.force_newline = false;
- params.view = icon;
- params.left_pad = 4;
- params.right_pad = 4;
- params.top_pad = -2;
- params.bottom_pad = 2;
-
- base->appendWidget(params," ",false);
-
- return true;
-}
-
-void request_initial_instant_messages()
-{
- static BOOL requested = FALSE;
- if (!requested
- && gMessageSystem
- && LLMuteList::getInstance()->isLoaded()
- && isAgentAvatarValid())
- {
- // Auto-accepted inventory items may require the avatar object
- // to build a correct name. Likewise, inventory offers from
- // muted avatars require the mute list to properly mute.
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_RetrieveInstantMessages);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gAgent.sendReliableMessage();
- requested = TRUE;
- }
-}
-
-// A settings system callback for CrashSubmitBehavior
-bool handleCrashSubmitBehaviorChanged(const LLSD& newvalue)
-{
- S32 cb = newvalue.asInteger();
- const S32 NEVER_SUBMIT_REPORT = 2;
- if(cb == NEVER_SUBMIT_REPORT)
- {
- LLAppViewer::instance()->destroyMainloopTimeout();
- }
- return true;
-}
-
-// Use these strictly for things that are constructed at startup,
-// or for things that are performance critical. JC
-static void settings_to_globals()
-{
- LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad");
- BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall");
- BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight");
-
- MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight");
- MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth");
-
- LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
-
- LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
- LLVOVolume::sLODFactor = gSavedSettings.getF32("RenderVolumeLODFactor");
- LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f;
- LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
- LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor");
- LLVOAvatar::sLODFactor = gSavedSettings.getF32("RenderAvatarLODFactor");
- LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible");
- LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible");
- // clamp auto-open time to some minimum usable value
- LLFolderView::sAutoOpenTime = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay"));
- LLSelectMgr::sRectSelectInclusive = gSavedSettings.getBOOL("RectangleSelectInclusive");
- LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections");
- LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius");
-
- gAgentPilot.mNumRuns = gSavedSettings.getS32("StatsNumRuns");
- gAgentPilot.mQuitAfterRuns = gSavedSettings.getBOOL("StatsQuitAfterRuns");
- gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle"));
-
- gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
- gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
- LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale");
-}
-
-static void settings_modify()
-{
- LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderUseFBO");
- LLVOAvatar::sUseImpostors = gSavedSettings.getBOOL("RenderUseImpostors");
- LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor");
- LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
- gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession;
- gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
- gAuditTexture = gSavedSettings.getBOOL("AuditTexture");
-#if LL_VECTORIZE
- if (gSysCPU.hasAltivec())
- {
- gSavedSettings.setBOOL("VectorizeEnable", TRUE );
- gSavedSettings.setU32("VectorizeProcessor", 0 );
- }
- else
- if (gSysCPU.hasSSE2())
- {
- gSavedSettings.setBOOL("VectorizeEnable", TRUE );
- gSavedSettings.setU32("VectorizeProcessor", 2 );
- }
- else
- if (gSysCPU.hasSSE())
- {
- gSavedSettings.setBOOL("VectorizeEnable", TRUE );
- gSavedSettings.setU32("VectorizeProcessor", 1 );
- }
- else
- {
- // Don't bother testing or running if CPU doesn't support it. JC
- gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
- gSavedSettings.setBOOL("VectorizeEnable", FALSE );
- gSavedSettings.setU32("VectorizeProcessor", 0 );
- gSavedSettings.setBOOL("VectorizeSkin", FALSE);
- }
-#else
- // This build target doesn't support SSE, don't test/run.
- gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
- gSavedSettings.setBOOL("VectorizeEnable", FALSE );
- gSavedSettings.setU32("VectorizeProcessor", 0 );
- gSavedSettings.setBOOL("VectorizeSkin", FALSE);
-
- // disable fullscreen mode, unsupported
- gSavedSettings.setBOOL("WindowFullScreen", FALSE);
-#endif
-}
-
-class LLFastTimerLogThread : public LLThread
-{
-public:
- std::string mFile;
-
- LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log")
- {
- std::string file_name = test_name + std::string(".slp");
- mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name);
- }
-
- void run()
- {
- std::ofstream os(mFile.c_str());
-
- while (!LLAppViewer::instance()->isQuitting())
- {
- LLFastTimer::writeLog(os);
- os.flush();
- ms_sleep(32);
- }
-
- os.close();
- }
-
-};
-
-//virtual
-bool LLAppViewer::initSLURLHandler()
-{
- // does nothing unless subclassed
- return false;
-}
-
-//virtual
-bool LLAppViewer::sendURLToOtherInstance(const std::string& url)
-{
- // does nothing unless subclassed
- return false;
-}
-
-//----------------------------------------------------------------------------
-// LLAppViewer definition
-
-// Static members.
-// The single viewer app.
-LLAppViewer* LLAppViewer::sInstance = NULL;
-
-const std::string LLAppViewer::sGlobalSettingsName = "Global";
-
-LLTextureCache* LLAppViewer::sTextureCache = NULL;
-LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL;
-LLTextureFetch* LLAppViewer::sTextureFetch = NULL;
-
-LLAppViewer::LLAppViewer() :
- mMarkerFile(),
- mLogoutMarkerFile(NULL),
- mReportedCrash(false),
- mNumSessions(0),
- mPurgeCache(false),
- mPurgeOnExit(false),
- mSecondInstance(false),
- mSavedFinalSnapshot(false),
- mForceGraphicsDetail(false),
- mQuitRequested(false),
- mLogoutRequestSent(false),
- mYieldTime(-1),
- mMainloopTimeout(NULL),
- mAgentRegionLastAlive(false),
- mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)),
- mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)),
- mFastTimerLogThread(NULL),
- mUpdater(new LLUpdaterService())
-{
- if(NULL != sInstance)
- {
- llerrs << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << llendl;
- }
-
- setupErrorHandling();
- sInstance = this;
- gLoggedInTime.stop();
-
- LLLoginInstance::instance().setUpdaterService(mUpdater.get());
-}
-
-LLAppViewer::~LLAppViewer()
-{
- LLLoginInstance::instance().setUpdaterService(0);
-
- destroyMainloopTimeout();
-
- // If we got to this destructor somehow, the app didn't hang.
- removeMarkerFile();
-}
-
-bool LLAppViewer::init()
-{
- //
- // Start of the application
- //
- // IMPORTANT! Do NOT put anything that will write
- // into the log files during normal startup until AFTER
- // we run the "program crashed last time" error handler below.
- //
- LLFastTimer::reset();
-
- // Need to do this initialization before we do anything else, since anything
- // that touches files should really go through the lldir API
- gDirUtilp->initAppDirs("SecondLife");
- // set skin search path to default, will be overridden later
- // this allows simple skinned file lookups to work
- gDirUtilp->setSkinFolder("default");
-
- initLogging();
-
- //
- // OK to write stuff to logs now, we've now crash reported if necessary
- //
-
- init_default_trans_args();
-
- if (!initConfiguration())
- return false;
-
- // write Google Breakpad minidump files to our log directory
- std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
- logdir += gDirUtilp->getDirDelimiter();
- setMiniDumpDir(logdir);
-
- // Although initLogging() is the right place to mess with
- // setFatalFunction(), we can't query gSavedSettings until after
- // initConfiguration().
- S32 rc(gSavedSettings.getS32("QAModeTermCode"));
- if (rc >= 0)
- {
- // QAModeTermCode set, terminate with that rc on LL_ERRS. Use _exit()
- // rather than exit() because normal cleanup depends too much on
- // successful startup!
- LLError::setFatalFunction(boost::bind(_exit, rc));
- }
-
- mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
-
-#if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::initClass();
-#endif
-
- // *NOTE:Mani - LLCurl::initClass is not thread safe.
- // Called before threads are created.
- LLCurl::initClass();
- LLMachineID::init();
-
- {
- // Viewer metrics initialization
- static LLCachedControl<bool> metrics_submode(gSavedSettings,
- "QAModeMetrics",
- false,
- "Enables QA features (logging, faster cycling) for metrics collector");
-
- if (metrics_submode)
- {
- app_metrics_qa_mode = true;
- app_metrics_interval = METRICS_INTERVAL_QA;
- }
- LLViewerAssetStatsFF::init();
- }
-
- initThreads();
- writeSystemInfo();
-
- // Initialize updater service (now that we have an io pump)
- initUpdater();
- if(isQuitting())
- {
- // Early out here because updater set the quitting flag.
- return true;
- }
-
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- //////////////////////////////////////////////////////////////////////////////
- // *FIX: The following code isn't grouped into functions yet.
-
- // Statistics / debug timer initialization
- init_statistics();
-
- //
- // Various introspection concerning the libs we're using - particularly
- // the libs involved in getting to a full login screen.
- //
- LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL;
- LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL;
-
- // Get the single value from the crash settings file, if it exists
- std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
- gCrashSettings.loadFromFile(crash_settings_filename);
- if(gSavedSettings.getBOOL("IgnoreAllNotifications"))
- {
- gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ALWAYS_SEND);
- gCrashSettings.saveToFile(crash_settings_filename, FALSE);
- }
-
- /////////////////////////////////////////////////
- // OS-specific login dialogs
- /////////////////////////////////////////////////
-
- //test_cached_control();
-
- // track number of times that app has run
- mNumSessions = gSavedSettings.getS32("NumSessions");
- mNumSessions++;
- gSavedSettings.setS32("NumSessions", mNumSessions);
-
- if (gSavedSettings.getBOOL("VerboseLogs"))
- {
- LLError::setPrintLocation(true);
- }
-
- // Widget construction depends on LLUI being initialized
- LLUI::settings_map_t settings_map;
- settings_map["config"] = &gSavedSettings;
- settings_map["ignores"] = &gWarningSettings;
- settings_map["floater"] = &gSavedSettings; // *TODO: New settings file
- settings_map["account"] = &gSavedPerAccountSettings;
-
- LLUI::initClass(settings_map,
- LLUIImageList::getInstance(),
- ui_audio_callback,
- &LLUI::sGLScaleFactor);
-
- // Setup paths and LLTrans after LLUI::initClass has been called
- LLUI::setupPaths();
- LLTransUtil::parseStrings("strings.xml", default_trans_args);
- LLTransUtil::parseLanguageStrings("language_settings.xml");
-
- // LLKeyboard relies on LLUI to know what some accelerator keys are called.
- LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString );
-
- LLWeb::initClass(); // do this after LLUI
-
- // Provide the text fields with callbacks for opening Urls
- LLUrlAction::setOpenURLCallback(&LLWeb::loadURL);
- LLUrlAction::setOpenURLInternalCallback(&LLWeb::loadURLInternal);
- LLUrlAction::setOpenURLExternalCallback(&LLWeb::loadURLExternal);
- LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor);
-
- // Let code in llui access the viewer help floater
- LLUI::sHelpImpl = LLViewerHelp::getInstance();
-
- // Load translations for tooltips
- LLFloater::initClass();
-
- /////////////////////////////////////////////////
-
- LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated
-
- LLViewerFloaterReg::registerFloaters();
-
- /////////////////////////////////////////////////
- //
- // Load settings files
- //
- //
- LLGroupMgr::parseRoleActions("role_actions.xml");
-
- LLAgent::parseTeleportMessages("teleport_strings.xml");
-
- LLViewerJointMesh::updateVectorize();
-
- // load MIME type -> media impl mappings
- std::string mime_types_name;
-#if LL_DARWIN
- mime_types_name = "mime_types_mac.xml";
-#elif LL_LINUX
- mime_types_name = "mime_types_linux.xml";
-#else
- mime_types_name = "mime_types.xml";
-#endif
- LLMIMETypes::parseMIMETypes( mime_types_name );
-
- // Copy settings to globals. *TODO: Remove or move to appropriage class initializers
- settings_to_globals();
- // Setup settings listeners
- settings_setup_listeners();
- // Modify settings based on system configuration and compile options
- settings_modify();
-
- // Find partition serial number (Windows) or hardware serial (Mac)
- mSerialNumber = generateSerialNumber();
-
- // do any necessary set-up for accepting incoming SLURLs from apps
- initSLURLHandler();
-
- if(false == initHardwareTest())
- {
- // Early out from user choice.
- return false;
- }
-
- // Prepare for out-of-memory situations, during which we will crash on
- // purpose and save a dump.
-#if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
- MemSetErrorHandler(first_mem_error_handler);
-#endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
-
- // *Note: this is where gViewerStats used to be created.
-
- //
- // Initialize the VFS, and gracefully handle initialization errors
- //
-
- if (!initCache())
- {
- std::ostringstream msg;
- msg << LLTrans::getString("MBUnableToAccessFile");
- OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
- return 1;
- }
-
- // Initialize the repeater service.
- LLMainLoopRepeater::instance().start();
-
- //
- // Initialize the window
- //
- gGLActive = TRUE;
- initWindow();
-
- // initWindow also initializes the Feature List, so now we can initialize this global.
- LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
-
- // call all self-registered classes
- LLInitClassList::instance().fireCallbacks();
-
- LLFolderViewItem::initClass(); // SJB: Needs to happen after initWindow(), not sure why but related to fonts
-
- gGLManager.getGLInfo(gDebugInfo);
- gGLManager.printGLInfoString();
-
- // Load Default bindings
- std::string key_bindings_file = gDirUtilp->findFile("keys.xml",
- gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
- gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
-
-
- if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
- {
- std::string key_bindings_file = gDirUtilp->findFile("keys.ini",
- gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
- gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- if (!gViewerKeyboard.loadBindings(key_bindings_file))
- {
- LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
- }
- }
-
- // If we don't have the right GL requirements, exit.
- if (!gGLManager.mHasRequirements && !gNoRender)
- {
- // can't use an alert here since we're exiting and
- // all hell breaks lose.
- OSMessageBox(
- LLNotifications::instance().getGlobalString("UnsupportedGLRequirements"),
- LLStringUtil::null,
- OSMB_OK);
- return 0;
- }
-
- // alert the user if they are using unsupported hardware
- if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware"))
- {
- bool unsupported = false;
- LLSD args;
- std::string minSpecs;
-
- // get cpu data from xml
- std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount"));
- S32 minCPU = 0;
- minCPUString >> minCPU;
-
- // get RAM data from XML
- std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount"));
- U64 minRAM = 0;
- minRAMString >> minRAM;
- minRAM = minRAM * 1024 * 1024;
-
- if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN)
- {
- minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU");
- minSpecs += "\n";
- unsupported = true;
- }
- if(gSysCPU.getMHz() < minCPU)
- {
- minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU");
- minSpecs += "\n";
- unsupported = true;
- }
- if(gSysMemory.getPhysicalMemoryClamped() < minRAM)
- {
- minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM");
- minSpecs += "\n";
- unsupported = true;
- }
-
- if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN)
- {
- LLNotificationsUtil::add("UnknownGPU");
- }
-
- if(unsupported)
- {
- if(!gSavedSettings.controlExists("WarnUnsupportedHardware")
- || gSavedSettings.getBOOL("WarnUnsupportedHardware"))
- {
- args["MINSPECS"] = minSpecs;
- LLNotificationsUtil::add("UnsupportedHardware", args );
- }
-
- }
- }
-
-
- // save the graphics card
- gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString();
-
- // Save the current version to the prefs file
- gSavedSettings.setString("LastRunVersion",
- LLVersionInfo::getChannelAndVersion());
-
- gSimLastTime = gRenderStartTime.getElapsedTimeF32();
- gSimFrames = (F32)gFrameCount;
-
- LLViewerJoystick::getInstance()->init(false);
-
- try {
- initializeSecHandler();
- }
- catch (LLProtectedDataException ex)
- {
- LLNotificationsUtil::add("CorruptedProtectedDataStore");
- }
- LLHTTPClient::setCertVerifyCallback(secapiSSLCertVerifyCallback);
-
-
- gGLActive = FALSE;
- if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0)
- {
- loadEventHostModule(gSavedSettings.getS32("QAModeEventHostPort"));
- }
-
- LLViewerMedia::initClass();
- LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match;
-
- //EXT-7013 - On windows for some locale (Japanese) standard
- //datetime formatting functions didn't support some parameters such as "weekday".
- //Names for days and months localized in xml are also useful for Polish locale(STORM-107).
- std::string language = LLControlGroup::getInstance(sGlobalSettingsName)->getString("Language");
- if(language == "ja" || language == "pl")
- {
- LLStringOps::setupWeekDaysNames(LLTrans::getString("dateTimeWeekdaysNames"));
- LLStringOps::setupWeekDaysShortNames(LLTrans::getString("dateTimeWeekdaysShortNames"));
- LLStringOps::setupMonthNames(LLTrans::getString("dateTimeMonthNames"));
- LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames"));
- LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat"));
-
- LLStringOps::sAM = LLTrans::getString("dateTimeAM");
- LLStringOps::sPM = LLTrans::getString("dateTimePM");
- }
-
- LLAgentLanguage::init();
-
-
-
- return true;
-}
-
-static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages");
-static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep");
-static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache");
-static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode");
-static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread");
-static LLFastTimer::DeclareTimer FTM_LFS("LFS Thread");
-static LLFastTimer::DeclareTimer FTM_PAUSE_THREADS("Pause Threads");
-static LLFastTimer::DeclareTimer FTM_IDLE("Idle");
-static LLFastTimer::DeclareTimer FTM_PUMP("Pump");
-static LLFastTimer::DeclareTimer FTM_PUMP_ARES("Ares");
-static LLFastTimer::DeclareTimer FTM_PUMP_SERVICE("Service");
-static LLFastTimer::DeclareTimer FTM_SERVICE_CALLBACK("Callback");
-static LLFastTimer::DeclareTimer FTM_AGENT_AUTOPILOT("Autopilot");
-static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE("Update");
-
-bool LLAppViewer::mainLoop()
-{
- LLMemType mt1(LLMemType::MTYPE_MAIN);
- mMainloopTimeout = new LLWatchdogTimeout();
-
- //-------------------------------------------
- // Run main loop until time to quit
- //-------------------------------------------
-
- // Create IO Pump to use for HTTP Requests.
- gServicePump = new LLPumpIO(gAPRPoolp);
- LLHTTPClient::setPump(*gServicePump);
- LLCurl::setCAFile(gDirUtilp->getCAFile());
-
- // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
-
- LLVoiceChannel::initClass();
- LLVoiceClient::getInstance()->init(gServicePump);
- LLTimer frameTimer,idleTimer;
- LLTimer debugTime;
- LLFrameTimer memCheckTimer;
- LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
- joystick->setNeedsReset(true);
-
- LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
- // As we do not (yet) send data on the mainloop LLEventPump that varies
- // with each frame, no need to instantiate a new LLSD event object each
- // time. Obviously, if that changes, just instantiate the LLSD at the
- // point of posting.
- LLSD newFrame;
-
- const F32 memory_check_interval = 1.0f ; //second
-
- // Handle messages
- while (!LLApp::isExiting())
- {
- LLFastTimer::nextFrame(); // Should be outside of any timer instances
-
- //clear call stack records
- llclearcallstacks;
-
- //check memory availability information
- {
- if(memory_check_interval < memCheckTimer.getElapsedTimeF32())
- {
- memCheckTimer.reset() ;
-
- //update the availability of memory
- LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ;
- }
- llcallstacks << "Available physical mem(KB): " << mAvailPhysicalMemInKB << llcallstacksendl ;
- llcallstacks << "Available virtual mem(KB): " << mAvailVirtualMemInKB << llcallstacksendl ;
- }
-
- try
- {
- pingMainloopTimeout("Main:MiscNativeWindowEvents");
-
- if (gViewerWindow)
- {
- LLFastTimer t2(FTM_MESSAGES);
- gViewerWindow->mWindow->processMiscNativeEvents();
- }
-
- pingMainloopTimeout("Main:GatherInput");
-
- if (gViewerWindow)
- {
- LLFastTimer t2(FTM_MESSAGES);
- if (!restoreErrorTrap())
- {
- llwarns << " Someone took over my signal/exception handler (post messagehandling)!" << llendl;
- }
-
- gViewerWindow->mWindow->gatherInput();
- }
-
-#if 1 && !LL_RELEASE_FOR_DOWNLOAD
- // once per second debug info
- if (debugTime.getElapsedTimeF32() > 1.f)
- {
- debugTime.reset();
- }
-
-#endif
- //memory leaking simulation
- LLFloaterMemLeak* mem_leak_instance =
- LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
- if(mem_leak_instance)
- {
- mem_leak_instance->idle() ;
- }
-
- // canonical per-frame event
- mainloop.post(newFrame);
-
- if (!LLApp::isExiting())
- {
- pingMainloopTimeout("Main:JoystickKeyboard");
-
- // Scan keyboard for movement keys. Command keys and typing
- // are handled by windows callbacks. Don't do this until we're
- // done initializing. JC
- if (gViewerWindow->mWindow->getVisible()
- && gViewerWindow->getActive()
- && !gViewerWindow->mWindow->getMinimized()
- && LLStartUp::getStartupState() == STATE_STARTED
- && !gViewerWindow->getShowProgress()
- && !gFocusMgr.focusLocked())
- {
- LLMemType mjk(LLMemType::MTYPE_JOY_KEY);
- joystick->scanJoystick();
- gKeyboard->scanKeyboard();
- }
-
- // Update state based on messages, user input, object idle.
- {
- pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
-
- LLFastTimer t3(FTM_IDLE);
- idle();
-
- if (gAres != NULL && gAres->isInitialized())
- {
- LLMemType mt_ip(LLMemType::MTYPE_IDLE_PUMP);
- pingMainloopTimeout("Main:ServicePump");
- LLFastTimer t4(FTM_PUMP);
- {
- LLFastTimer t(FTM_PUMP_ARES);
- gAres->process();
- }
- {
- LLFastTimer t(FTM_PUMP_SERVICE);
- // this pump is necessary to make the login screen show up
- gServicePump->pump();
-
- {
- LLFastTimer t(FTM_SERVICE_CALLBACK);
- gServicePump->callback();
- }
- }
- }
-
- resumeMainloopTimeout();
- }
-
- if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
- {
- pauseMainloopTimeout();
- saveFinalSnapshot();
- disconnectViewer();
- resumeMainloopTimeout();
- }
-
- // Render scene.
- if (!LLApp::isExiting())
- {
- pingMainloopTimeout("Main:Display");
- gGLActive = TRUE;
- display();
- pingMainloopTimeout("Main:Snapshot");
- LLFloaterSnapshot::update(); // take snapshots
- gGLActive = FALSE;
- }
-
- }
-
- pingMainloopTimeout("Main:Sleep");
-
- pauseMainloopTimeout();
-
- // Sleep and run background threads
- {
- LLMemType mt_sleep(LLMemType::MTYPE_SLEEP);
- LLFastTimer t2(FTM_SLEEP);
-
- // yield some time to the os based on command line option
- if(mYieldTime >= 0)
- {
- ms_sleep(mYieldTime);
- }
-
- // yield cooperatively when not running as foreground window
- if ( gNoRender
- || (gViewerWindow && !gViewerWindow->mWindow->getVisible())
- || !gFocusMgr.getAppHasFocus())
- {
- // Sleep if we're not rendering, or the window is minimized.
- S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000);
- // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
- // of equal priority on Windows
- if (milliseconds_to_sleep > 0)
- {
- ms_sleep(milliseconds_to_sleep);
- // also pause worker threads during this wait period
- LLAppViewer::getTextureCache()->pause();
- LLAppViewer::getImageDecodeThread()->pause();
- }
- }
-
- if (mRandomizeFramerate)
- {
- ms_sleep(rand() % 200);
- }
-
- if (mPeriodicSlowFrame
- && (gFrameCount % 10 == 0))
- {
- llinfos << "Periodic slow frame - sleeping 500 ms" << llendl;
- ms_sleep(500);
- }
-
- static const F64 FRAME_SLOW_THRESHOLD = 0.5; //2 frames per seconds
- const F64 max_idle_time = llmin(.005*10.0*gFrameTimeSeconds, 0.005); // 5 ms a second
- idleTimer.reset();
- bool is_slow = (frameTimer.getElapsedTimeF64() > FRAME_SLOW_THRESHOLD) ;
- S32 total_work_pending = 0;
- S32 total_io_pending = 0;
- while(!is_slow)//do not unpause threads if the frame rates are very low.
- {
- S32 work_pending = 0;
- S32 io_pending = 0;
- {
- LLFastTimer ftm(FTM_TEXTURE_CACHE);
- work_pending += LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
- }
- {
- LLFastTimer ftm(FTM_DECODE);
- work_pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
- }
- {
- LLFastTimer ftm(FTM_DECODE);
- work_pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
- }
-
- {
- LLFastTimer ftm(FTM_VFS);
- io_pending += LLVFSThread::updateClass(1);
- }
- {
- LLFastTimer ftm(FTM_LFS);
- io_pending += LLLFSThread::updateClass(1);
- }
-
- if (io_pending > 1000)
- {
- ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
- }
-
- total_work_pending += work_pending ;
- total_io_pending += io_pending ;
-
- if (!work_pending || idleTimer.getElapsedTimeF64() >= max_idle_time)
- {
- break;
- }
- }
-
- if(!total_work_pending) //pause texture fetching threads if nothing to process.
- {
- LLAppViewer::getTextureCache()->pause();
- LLAppViewer::getImageDecodeThread()->pause();
- LLAppViewer::getTextureFetch()->pause();
- }
- if(!total_io_pending) //pause file threads if nothing to process.
- {
- LLVFSThread::sLocal->pause();
- LLLFSThread::sLocal->pause();
- }
-
- if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
- (frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
- {
- gFrameStalls++;
- }
- frameTimer.reset();
-
- resumeMainloopTimeout();
-
- pingMainloopTimeout("Main:End");
- }
- }
- catch(std::bad_alloc)
- {
- {
- llinfos << "Availabe physical memory(KB) at the beginning of the frame: " << mAvailPhysicalMemInKB << llendl ;
- llinfos << "Availabe virtual memory(KB) at the beginning of the frame: " << mAvailVirtualMemInKB << llendl ;
-
- LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ;
-
- llinfos << "Current availabe physical memory(KB): " << mAvailPhysicalMemInKB << llendl ;
- llinfos << "Current availabe virtual memory(KB): " << mAvailVirtualMemInKB << llendl ;
- }
-
- //stop memory leaking simulation
- LLFloaterMemLeak* mem_leak_instance =
- LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
- if(mem_leak_instance)
- {
- mem_leak_instance->stop() ;
- llwarns << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ;
- }
- else
- {
- //output possible call stacks to log file.
- LLError::LLCallStacks::print() ;
-
- llerrs << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ;
- }
- }
- }
-
- // Save snapshot for next time, if we made it through initialization
- if (STATE_STARTED == LLStartUp::getStartupState())
- {
- try
- {
- saveFinalSnapshot();
- }
- catch(std::bad_alloc)
- {
- llwarns << "Bad memory allocation when saveFinalSnapshot() is called!" << llendl ;
-
- //stop memory leaking simulation
- LLFloaterMemLeak* mem_leak_instance =
- LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
- if(mem_leak_instance)
- {
- mem_leak_instance->stop() ;
- }
- }
- }
-
- delete gServicePump;
-
- destroyMainloopTimeout();
-
- llinfos << "Exiting main_loop" << llendflush;
-
- return true;
-}
-
-void LLAppViewer::flushVFSIO()
-{
- while (1)
- {
- S32 pending = LLVFSThread::updateClass(0);
- pending += LLLFSThread::updateClass(0);
- if (!pending)
- {
- break;
- }
- llinfos << "Waiting for pending IO to finish: " << pending << llendflush;
- ms_sleep(100);
- }
-}
-
-bool LLAppViewer::cleanup()
-{
- // workaround for DEV-35406 crash on shutdown
- LLEventPumps::instance().reset();
-
- // remove any old breakpad minidump files from the log directory
- if (! isError())
- {
- std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
- logdir += gDirUtilp->getDirDelimiter();
- gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp");
- }
-
- // *TODO - generalize this and move DSO wrangling to a helper class -brad
- std::set<struct apr_dso_handle_t *>::const_iterator i;
- for(i = mPlugins.begin(); i != mPlugins.end(); ++i)
- {
- int (*ll_plugin_stop_func)(void) = NULL;
- apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, *i, "ll_plugin_stop");
- ll_plugin_stop_func();
-
- rv = apr_dso_unload(*i);
- }
- mPlugins.clear();
-
- //flag all elements as needing to be destroyed immediately
- // to ensure shutdown order
- LLMortician::setZealous(TRUE);
-
- LLVoiceClient::getInstance()->terminate();
-
- disconnectViewer();
-
- llinfos << "Viewer disconnected" << llendflush;
-
- display_cleanup();
-
- release_start_screen(); // just in case
-
- LLError::logToFixedBuffer(NULL);
-
- llinfos << "Cleaning Up" << llendflush;
-
- // Must clean up texture references before viewer window is destroyed.
- if(LLHUDManager::instanceExists())
- {
- LLHUDManager::getInstance()->updateEffects();
- LLHUDObject::updateAll();
- LLHUDManager::getInstance()->cleanupEffects();
- LLHUDObject::cleanupHUDObjects();
- llinfos << "HUD Objects cleaned up" << llendflush;
- }
-
- LLKeyframeDataCache::clear();
-
- // End TransferManager before deleting systems it depends on (Audio, VFS, AssetStorage)
-#if 0 // this seems to get us stuck in an infinite loop...
- gTransferManager.cleanup();
-#endif
-
- // Note: this is where gWorldMap used to be deleted.
-
- // Note: this is where gHUDManager used to be deleted.
- if(LLHUDManager::instanceExists())
- {
- LLHUDManager::getInstance()->shutdownClass();
- }
-
- delete gAssetStorage;
- gAssetStorage = NULL;
-
- LLPolyMesh::freeAllMeshes();
-
- LLStartUp::cleanupNameCache();
-
- // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted.
-
- LLWorldMap::getInstance()->reset(); // release any images
-
- llinfos << "Global stuff deleted" << llendflush;
-
- if (gAudiop)
- {
- // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem.
-
- LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl();
- delete sai;
- gAudiop->setStreamingAudioImpl(NULL);
-
- // shut down the audio subsystem
-
- bool want_longname = false;
- if (gAudiop->getDriverName(want_longname) == "FMOD")
- {
- // This hack exists because fmod likes to occasionally
- // crash or hang forever when shutting down, for no
- // apparent reason.
- llwarns << "Hack, skipping FMOD audio engine cleanup" << llendflush;
- }
- else
- {
- gAudiop->shutdown();
- }
-
- delete gAudiop;
- gAudiop = NULL;
- }
-
- // Note: this is where LLFeatureManager::getInstance()-> used to be deleted.
-
- // Patch up settings for next time
- // Must do this before we delete the viewer window,
- // such that we can suck rectangle information out of
- // it.
- cleanupSavedSettings();
- llinfos << "Settings patched up" << llendflush;
-
- // delete some of the files left around in the cache.
- removeCacheFiles("*.wav");
- removeCacheFiles("*.tmp");
- removeCacheFiles("*.lso");
- removeCacheFiles("*.out");
- removeCacheFiles("*.dsf");
- removeCacheFiles("*.bodypart");
- removeCacheFiles("*.clothing");
-
- llinfos << "Cache files removed" << llendflush;
-
- // Wait for any pending VFS IO
- flushVFSIO();
- llinfos << "Shutting down Views" << llendflush;
-
- // Destroy the UI
- if( gViewerWindow)
- gViewerWindow->shutdownViews();
-
- llinfos << "Cleaning up Inventory" << llendflush;
-
- // Cleanup Inventory after the UI since it will delete any remaining observers
- // (Deleted observers should have already removed themselves)
- gInventory.cleanupInventory();
-
- llinfos << "Cleaning up Selections" << llendflush;
-
- // Clean up selection managers after UI is destroyed, as UI may be observing them.
- // Clean up before GL is shut down because we might be holding on to objects with texture references
- LLSelectMgr::cleanupGlobals();
-
- llinfos << "Shutting down OpenGL" << llendflush;
-
- // Shut down OpenGL
- if( gViewerWindow)
- {
- gViewerWindow->shutdownGL();
-
- // Destroy window, and make sure we're not fullscreen
- // This may generate window reshape and activation events.
- // Therefore must do this before destroying the message system.
- delete gViewerWindow;
- gViewerWindow = NULL;
- llinfos << "ViewerWindow deleted" << llendflush;
- }
-
- llinfos << "Cleaning up Keyboard & Joystick" << llendflush;
-
- // viewer UI relies on keyboard so keep it aound until viewer UI isa gone
- delete gKeyboard;
- gKeyboard = NULL;
-
- // Turn off Space Navigator and similar devices
- LLViewerJoystick::getInstance()->terminate();
-
- llinfos << "Cleaning up Objects" << llendflush;
-
- LLViewerObject::cleanupVOClasses();
-
- LLWaterParamManager::cleanupClass();
- LLWLParamManager::cleanupClass();
- LLPostProcess::cleanupClass();
-
- LLTracker::cleanupInstance();
-
- // *FIX: This is handled in LLAppViewerWin32::cleanup().
- // I'm keeping the comment to remember its order in cleanup,
- // in case of unforseen dependency.
- //#if LL_WINDOWS
- // gDXHardware.cleanup();
- //#endif // LL_WINDOWS
-
- LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager();
- if (!volume_manager->cleanup())
- {
- llwarns << "Remaining references in the volume manager!" << llendflush;
- }
- LLPrimitive::cleanupVolumeManager();
-
- llinfos << "Additional Cleanup..." << llendflush;
-
- LLViewerParcelMgr::cleanupGlobals();
-
- // *Note: this is where gViewerStats used to be deleted.
-
- //end_messaging_system();
-
- LLFollowCamMgr::cleanupClass();
- //LLVolumeMgr::cleanupClass();
- LLPrimitive::cleanupVolumeManager();
- LLWorldMapView::cleanupClass();
- LLFolderViewItem::cleanupClass();
- LLUI::cleanupClass();
-
- //
- // Shut down the VFS's AFTER the decode manager cleans up (since it cleans up vfiles).
- // Also after viewerwindow is deleted, since it may have image pointers (which have vfiles)
- // Also after shutting down the messaging system since it has VFS dependencies
-
- //
- llinfos << "Cleaning up VFS" << llendflush;
- LLVFile::cleanupClass();
-
- llinfos << "Saving Data" << llendflush;
-
- // Store the time of our current logoff
- gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
-
- // Must do this after all panels have been deleted because panels that have persistent rects
- // save their rects on delete.
- gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);
-
- LLUIColorTable::instance().saveUserSettings();
-
- // PerAccountSettingsFile should be empty if no user has been logged on.
- // *FIX:Mani This should get really saved in a "logoff" mode.
- if (gSavedSettings.getString("PerAccountSettingsFile").empty())
- {
- llinfos << "Not saving per-account settings; don't know the account name yet." << llendl;
- }
- else
- {
- gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
- llinfos << "Saved settings" << llendflush;
- }
-
- std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
- // save all settings, even if equals defaults
- gCrashSettings.saveToFile(crash_settings_filename, FALSE);
-
- std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings"));
- gWarningSettings.saveToFile(warnings_settings_filename, TRUE);
-
- // Save URL history file
- LLURLHistory::saveFile("url_history.xml");
-
- // save mute list. gMuteList used to also be deleted here too.
- LLMuteList::getInstance()->cache(gAgent.getID());
-
- if (mPurgeOnExit)
- {
- llinfos << "Purging all cache files on exit" << llendflush;
- std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
- gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
- }
-
- removeMarkerFile(); // Any crashes from here on we'll just have to ignore
-
- writeDebugInfo();
-
- LLLocationHistory::getInstance()->save();
-
- LLAvatarIconIDCache::getInstance()->save();
-
- LLViewerMedia::saveCookieFile();
-
- // Stop the plugin read thread if it's running.
- LLPluginProcessParent::setUseReadThread(false);
-
- llinfos << "Shutting down Threads" << llendflush;
-
- // Let threads finish
- LLTimer idleTimer;
- idleTimer.reset();
- const F64 max_idle_time = 5.f; // 5 seconds
- while(1)
- {
- S32 pending = 0;
- pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread
- pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
- pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
- pending += LLVFSThread::updateClass(0);
- pending += LLLFSThread::updateClass(0);
- F64 idle_time = idleTimer.getElapsedTimeF64();
- if(!pending)
- {
- break ; //done
- }
- else if(idle_time >= max_idle_time)
- {
- llwarns << "Quitting with pending background tasks." << llendl;
- break;
- }
- }
-
- // Delete workers first
- // shotdown all worker threads before deleting them in case of co-dependencies
- sTextureFetch->shutdown();
- sTextureCache->shutdown();
- sImageDecodeThread->shutdown();
-
- sTextureFetch->shutDownTextureCacheThread() ;
- sTextureFetch->shutDownImageDecodeThread() ;
-
- delete sTextureCache;
- sTextureCache = NULL;
- delete sTextureFetch;
- sTextureFetch = NULL;
- delete sImageDecodeThread;
- sImageDecodeThread = NULL;
- delete mFastTimerLogThread;
- mFastTimerLogThread = NULL;
-
- if (LLFastTimerView::sAnalyzePerformance)
- {
- llinfos << "Analyzing performance" << llendl;
-
- std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
- std::string current_name = LLFastTimer::sLogName + ".slp";
- std::string report_name = LLFastTimer::sLogName + "_report.csv";
-
- LLFastTimerView::doAnalysis(
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name),
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name),
- gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name));
- }
- LLMetricPerformanceTesterBasic::cleanClass() ;
-
-#if LL_RECORD_VIEWER_STATS
- LLViewerStatsRecorder::cleanupClass();
-#endif
-
- llinfos << "Cleaning up Media and Textures" << llendflush;
-
- //Note:
- //LLViewerMedia::cleanupClass() has to be put before gTextureList.shutdown()
- //because some new image might be generated during cleaning up media. --bao
- LLViewerMedia::cleanupClass();
- LLViewerParcelMedia::cleanupClass();
- gTextureList.shutdown(); // shutdown again in case a callback added something
- LLUIImageList::getInstance()->cleanUp();
-
- // This should eventually be done in LLAppViewer
- LLImage::cleanupClass();
- LLVFSThread::cleanupClass();
- LLLFSThread::cleanupClass();
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- llinfos << "Auditing VFS" << llendl;
- if(gVFS)
- {
- gVFS->audit();
- }
-#endif
-
- llinfos << "Misc Cleanup" << llendflush;
-
- // For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up.
- // (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve
- delete gStaticVFS;
- gStaticVFS = NULL;
- delete gVFS;
- gVFS = NULL;
-
- gSavedSettings.cleanup();
- LLUIColorTable::instance().clear();
- gCrashSettings.cleanup();
-
- LLWatchdog::getInstance()->cleanup();
-
- LLViewerAssetStatsFF::cleanup();
-
- llinfos << "Shutting down message system" << llendflush;
- end_messaging_system();
-
- // *NOTE:Mani - The following call is not thread safe.
- LLCurl::cleanupClass();
-
- // If we're exiting to launch an URL, do that here so the screen
- // is at the right resolution before we launch IE.
- if (!gLaunchFileOnQuit.empty())
- {
- llinfos << "Launch file on quit." << llendflush;
-#if LL_WINDOWS
- // Indicate an application is starting.
- SetCursor(LoadCursor(NULL, IDC_WAIT));
-#endif
-
- // HACK: Attempt to wait until the screen res. switch is complete.
- ms_sleep(1000);
-
- LLWeb::loadURLExternal( gLaunchFileOnQuit, false );
- llinfos << "File launched." << llendflush;
- }
-
- LLMainLoopRepeater::instance().stop();
-
- ll_close_fail_log();
-
- MEM_TRACK_RELEASE
-
- llinfos << "Goodbye!" << llendflush;
-
- // return 0;
- return true;
-}
-
-// A callback for llerrs to call during the watchdog error.
-void watchdog_llerrs_callback(const std::string &error_string)
-{
- gLLErrorActivated = true;
-
-#ifdef LL_WINDOWS
- RaiseException(0,0,0,0);
-#else
- raise(SIGQUIT);
-#endif
-}
-
-// A callback for the watchdog to call.
-void watchdog_killer_callback()
-{
- LLError::setFatalFunction(watchdog_llerrs_callback);
- llerrs << "Watchdog killer event" << llendl;
-}
-
-bool LLAppViewer::initThreads()
-{
-#if MEM_TRACK_MEM
- static const bool enable_threads = false;
-#else
- static const bool enable_threads = true;
-#endif
-
- LLVFSThread::initClass(enable_threads && false);
- LLLFSThread::initClass(enable_threads && false);
-
- // Image decoding
- LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
- LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
- LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(),
- sImageDecodeThread,
- enable_threads && true,
- app_metrics_qa_mode);
- LLImage::initClass();
-
- if (LLFastTimer::sLog || LLFastTimer::sMetricLog)
- {
- LLFastTimer::sLogLock = new LLMutex(NULL);
- mFastTimerLogThread = new LLFastTimerLogThread(LLFastTimer::sLogName);
- mFastTimerLogThread->start();
- }
-
- // *FIX: no error handling here!
- return true;
-}
-
-void errorCallback(const std::string &error_string)
-{
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK);
-#endif
-
- //Set the ErrorActivated global so we know to create a marker file
- gLLErrorActivated = true;
-
- LLError::crashAndLoop(error_string);
-}
-
-bool LLAppViewer::initLogging()
-{
- //
- // Set up logging defaults for the viewer
- //
- LLError::initForApplication(
- gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- LLError::setFatalFunction(errorCallback);
-
- // Remove the last ".old" log file.
- std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
- "SecondLife.old");
- LLFile::remove(old_log_file);
-
- // Rename current log file to ".old"
- std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
- "SecondLife.log");
- LLFile::rename(log_file, old_log_file);
-
- // Set the log file to SecondLife.log
-
- LLError::logToFile(log_file);
-
- // *FIX:Mani no error handling here!
- return true;
-}
-
-bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
- bool set_defaults)
-{
- // Find and vet the location key.
- if(!mSettingsLocationList.has(location_key))
- {
- llerrs << "Requested unknown location: " << location_key << llendl;
- return false;
- }
-
- LLSD location = mSettingsLocationList.get(location_key);
-
- if(!location.has("PathIndex"))
- {
- llerrs << "Settings location is missing PathIndex value. Settings cannot be loaded." << llendl;
- return false;
- }
- ELLPath path_index = (ELLPath)(location.get("PathIndex").asInteger());
- if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST)
- {
- llerrs << "Out of range path index in app_settings/settings_files.xml" << llendl;
- return false;
- }
-
- // Iterate through the locations list of files.
- LLSD files = location.get("Files");
- for(LLSD::map_iterator itr = files.beginMap(); itr != files.endMap(); ++itr)
- {
- std::string settings_group = (*itr).first;
- llinfos << "Attempting to load settings for the group " << settings_group
- << " - from location " << location_key << llendl;
-
- if(!LLControlGroup::getInstance(settings_group))
- {
- llwarns << "No matching settings group for name " << settings_group << llendl;
- continue;
- }
-
- LLSD file = (*itr).second;
-
- std::string full_settings_path;
- if(file.has("NameFromSetting"))
- {
- std::string custom_name_setting = file.get("NameFromSetting");
- // *NOTE: Regardless of the group currently being lodaed,
- // this setting is always read from the Global settings.
- if(LLControlGroup::getInstance(sGlobalSettingsName)->controlExists(custom_name_setting))
- {
- std::string file_name =
- LLControlGroup::getInstance(sGlobalSettingsName)->getString(custom_name_setting);
- full_settings_path = file_name;
- }
- }
-
- if(full_settings_path.empty())
- {
- std::string file_name = file.get("Name");
- full_settings_path = gDirUtilp->getExpandedFilename(path_index, file_name);
- }
-
- int requirement = 0;
- if(file.has("Requirement"))
- {
- requirement = file.get("Requirement").asInteger();
- }
-
- if(!LLControlGroup::getInstance(settings_group)->loadFromFile(full_settings_path, set_defaults))
- {
- if(requirement == 1)
- {
- llwarns << "Error: Cannot load required settings file from: "
- << full_settings_path << llendl;
- return false;
- }
- else
- {
- llinfos << "Cannot load " << full_settings_path << " - No settings found." << llendl;
- }
- }
- else
- {
- llinfos << "Loaded settings file " << full_settings_path << llendl;
- }
- }
-
- return true;
-}
-
-std::string LLAppViewer::getSettingsFilename(const std::string& location_key,
- const std::string& file)
-{
- if(mSettingsLocationList.has(location_key))
- {
- LLSD location = mSettingsLocationList.get(location_key);
- if(location.has("Files"))
- {
- LLSD files = location.get("Files");
- if(files.has(file) && files[file].has("Name"))
- {
- return files.get(file).get("Name").asString();
- }
- }
- }
- return std::string();
-}
-
-void LLAppViewer::loadColorSettings()
-{
- LLUIColorTable::instance().loadFromSettings();
-}
-
-bool LLAppViewer::initConfiguration()
-{
- //Load settings files list
- std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml");
- LLControlGroup settings_control("SettingsFiles");
- llinfos << "Loading settings file list " << settings_file_list << llendl;
- if (0 == settings_control.loadFromFile(settings_file_list))
- {
- llerrs << "Cannot load default configuration file " << settings_file_list << llendl;
- }
-
- mSettingsLocationList = settings_control.getLLSD("Locations");
-
- // The settings and command line parsing have a fragile
- // order-of-operation:
- // - load defaults from app_settings
- // - set procedural settings values
- // - read command line settings
- // - selectively apply settings needed to load user settings.
- // - load overrides from user_settings
- // - apply command line settings (to override the overrides)
- // - load per account settings (happens in llstartup
-
- // - load defaults
- bool set_defaults = true;
- if(!loadSettingsFromDirectory("Default", set_defaults))
- {
- std::ostringstream msg;
- msg << "Unable to load default settings file. The installation may be corrupted.";
- OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
- return false;
- }
-
- LLUI::setupPaths(); // setup paths for LLTrans based on settings files only
- LLTransUtil::parseStrings("strings.xml", default_trans_args);
- LLTransUtil::parseLanguageStrings("language_settings.xml");
- // - set procedural settings
- // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet
- gSavedSettings.setString("ClientSettingsFile",
- gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global")));
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- // provide developer build only overrides for these control variables that are not
- // persisted to settings.xml
- LLControlVariable* c = gSavedSettings.getControl("ShowConsoleWindow");
- if (c)
- {
- c->setValue(true, false);
- }
- c = gSavedSettings.getControl("AllowMultipleViewers");
- if (c)
- {
- c->setValue(true, false);
- }
-#endif
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- gSavedSettings.setBOOL("QAMode", TRUE );
- gSavedSettings.setS32("WatchdogEnabled", 0);
-#endif
-
- gCrashSettings.getControl(CRASH_BEHAVIOR_SETTING)->getSignal()->connect(boost::bind(&handleCrashSubmitBehaviorChanged, _2));
-
- // These are warnings that appear on the first experience of that condition.
- // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse
- // for disable/reset ability
-// LLFirstUse::addConfigVariable("FirstBalanceIncrease");
-// LLFirstUse::addConfigVariable("FirstBalanceDecrease");
-// LLFirstUse::addConfigVariable("FirstSit");
-// LLFirstUse::addConfigVariable("FirstMap");
-// LLFirstUse::addConfigVariable("FirstGoTo");
-// LLFirstUse::addConfigVariable("FirstBuild");
-// LLFirstUse::addConfigVariable("FirstLeftClickNoHit");
-// LLFirstUse::addConfigVariable("FirstTeleport");
-// LLFirstUse::addConfigVariable("FirstOverrideKeys");
-// LLFirstUse::addConfigVariable("FirstAttach");
-// LLFirstUse::addConfigVariable("FirstAppearance");
-// LLFirstUse::addConfigVariable("FirstInventory");
-// LLFirstUse::addConfigVariable("FirstSandbox");
-// LLFirstUse::addConfigVariable("FirstFlexible");
-// LLFirstUse::addConfigVariable("FirstDebugMenus");
-// LLFirstUse::addConfigVariable("FirstSculptedPrim");
-// LLFirstUse::addConfigVariable("FirstVoice");
-// LLFirstUse::addConfigVariable("FirstMedia");
-
- // - read command line settings.
- LLControlGroupCLP clp;
- std::string cmd_line_config = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,
- "cmd_line.xml");
-
- clp.configure(cmd_line_config, &gSavedSettings);
-
- if(!initParseCommandLine(clp))
- {
- llwarns << "Error parsing command line options. Command Line options ignored." << llendl;
-
- llinfos << "Command line usage:\n" << clp << llendl;
-
- std::ostringstream msg;
- msg << LLTrans::getString("MBCmdLineError") << clp.getErrorMessage();
- OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
- return false;
- }
-
- // - selectively apply settings
-
- // If the user has specified a alternate settings file name.
- // Load it now before loading the user_settings/settings.xml
- if(clp.hasOption("settings"))
- {
- std::string user_settings_filename =
- gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
- clp.getOption("settings")[0]);
- gSavedSettings.setString("ClientSettingsFile", user_settings_filename);
- llinfos << "Using command line specified settings filename: "
- << user_settings_filename << llendl;
- }
-
- // - load overrides from user_settings
- loadSettingsFromDirectory("User");
- // - apply command line settings
- clp.notify();
-
- // Register the core crash option as soon as we can
- // if we want gdb post-mortem on cores we need to be up and running
- // ASAP or we might miss init issue etc.
- if(clp.hasOption("disablecrashlogger"))
- {
- llwarns << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" << llendl;
- LLAppViewer::instance()->disableCrashlogger();
- }
-
- // Handle initialization from settings.
- // Start up the debugging console before handling other options.
- if (gSavedSettings.getBOOL("ShowConsoleWindow"))
- {
- initConsole();
- }
-
- if(clp.hasOption("help"))
- {
- std::ostringstream msg;
- msg << LLTrans::getString("MBCmdLineUsg") << "\n" << clp;
- llinfos << msg.str() << llendl;
-
- OSMessageBox(
- msg.str().c_str(),
- LLStringUtil::null,
- OSMB_OK);
-
- return false;
- }
-
- if(clp.hasOption("set"))
- {
- const LLCommandLineParser::token_vector_t& set_values = clp.getOption("set");
- if(0x1 & set_values.size())
- {
- llwarns << "Invalid '--set' parameter count." << llendl;
- }
- else
- {
- LLCommandLineParser::token_vector_t::const_iterator itr = set_values.begin();
- for(; itr != set_values.end(); ++itr)
- {
- const std::string& name = *itr;
- const std::string& value = *(++itr);
- LLControlVariable* c = LLControlGroup::getInstance(sGlobalSettingsName)->getControl(name);
- if(c)
- {
- c->setValue(value, false);
- }
- else
- {
- llwarns << "'--set' specified with unknown setting: '"
- << name << "'." << llendl;
- }
- }
- }
- }
-
- if(clp.hasOption("channel"))
- {
- LLVersionInfo::resetChannel(clp.getOption("channel")[0]);
- }
-
-
- // If we have specified crash on startup, set the global so we'll trigger the crash at the right time
- if(clp.hasOption("crashonstartup"))
- {
- gCrashOnStartup = TRUE;
- }
-
- if (clp.hasOption("logperformance"))
- {
- LLFastTimer::sLog = TRUE;
- LLFastTimer::sLogName = std::string("performance");
- }
-
- if (clp.hasOption("logmetrics"))
- {
- LLFastTimer::sMetricLog = TRUE ;
- // '--logmetrics' can be specified with a named test metric argument so the data gathering is done only on that test
- // In the absence of argument, every metric is gathered (makes for a rather slow run and hard to decipher report...)
- std::string test_name = clp.getOption("logmetrics")[0];
- llinfos << "'--logmetrics' argument : " << test_name << llendl;
- if (test_name == "")
- {
- llwarns << "No '--logmetrics' argument given, will output all metrics to " << DEFAULT_METRIC_NAME << llendl;
- LLFastTimer::sLogName = DEFAULT_METRIC_NAME;
- }
- else
- {
- LLFastTimer::sLogName = test_name;
- }
- }
-
- if (clp.hasOption("graphicslevel"))
- {
- const LLCommandLineParser::token_vector_t& value = clp.getOption("graphicslevel");
- if(value.size() != 1)
- {
- llwarns << "Usage: -graphicslevel <0-3>" << llendl;
- }
- else
- {
- std::string detail = value.front();
- mForceGraphicsDetail = TRUE;
-
- switch (detail.c_str()[0])
- {
- case '0':
- gSavedSettings.setU32("RenderQualityPerformance", 0);
- break;
- case '1':
- gSavedSettings.setU32("RenderQualityPerformance", 1);
- break;
- case '2':
- gSavedSettings.setU32("RenderQualityPerformance", 2);
- break;
- case '3':
- gSavedSettings.setU32("RenderQualityPerformance", 3);
- break;
- default:
- mForceGraphicsDetail = FALSE;
- llwarns << "Usage: -graphicslevel <0-3>" << llendl;
- break;
- }
- }
- }
-
- if (clp.hasOption("analyzeperformance"))
- {
- LLFastTimerView::sAnalyzePerformance = TRUE;
- }
-
- if (clp.hasOption("replaysession"))
- {
- LLAgentPilot::sReplaySession = TRUE;
- }
-
- if (clp.hasOption("nonotifications"))
- {
- gSavedSettings.getControl("IgnoreAllNotifications")->setValue(true, false);
- }
-
- if (clp.hasOption("debugsession"))
- {
- gDebugSession = TRUE;
- gDebugGL = TRUE;
-
- ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log"));
- }
-
- // Handle slurl use. NOTE: Don't let SL-55321 reappear.
-
- // *FIX: This init code should be made more robust to prevent
- // the issue SL-55321 from returning. One thought is to allow
- // only select options to be set from command line when a slurl
- // is specified. More work on the settings system is needed to
- // achieve this. For now...
-
- // *NOTE:Mani The command line parser parses tokens and is
- // setup to bail after parsing the '--url' option or the
- // first option specified without a '--option' flag (or
- // any other option that uses the 'last_option' setting -
- // see LLControlGroupCLP::configure())
-
- // What can happen is that someone can use IE (or potentially
- // other browsers) and do the rough equivalent of command
- // injection and steal passwords. Phoenix. SL-55321
- if(clp.hasOption("url"))
- {
- LLStartUp::setStartSLURL(LLSLURL(clp.getOption("url")[0]));
- if(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION)
- {
- LLGridManager::getInstance()->setGridChoice(LLStartUp::getStartSLURL().getGrid());
-
- }
- }
- else if(clp.hasOption("slurl"))
- {
- LLSLURL start_slurl(clp.getOption("slurl")[0]);
- LLStartUp::setStartSLURL(start_slurl);
- }
-
- const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent");
- if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
- {
- // hack to force the skin to default.
- gDirUtilp->setSkinFolder(skinfolder->getValue().asString());
- //gDirUtilp->setSkinFolder("default");
- }
-
- mYieldTime = gSavedSettings.getS32("YieldTime");
-
- // Read skin/branding settings if specified.
- //if (! gDirUtilp->getSkinDir().empty() )
- //{
- // std::string skin_def_file = gDirUtilp->findSkinnedFilename("skin.xml");
- // LLXmlTree skin_def_tree;
-
- // if (!skin_def_tree.parseFile(skin_def_file))
- // {
- // llerrs << "Failed to parse skin definition." << llendl;
- // }
-
- //}
-
-#if LL_DARWIN
- // Initialize apple menubar and various callbacks
- init_apple_menu(LLTrans::getString("APP_NAME").c_str());
-
-#if __ppc__
- // If the CPU doesn't have Altivec (i.e. it's not at least a G4), don't go any further.
- // Only test PowerPC - all Intel Macs have SSE.
- if(!gSysCPU.hasAltivec())
- {
- std::ostringstream msg;
- msg << LLTrans::getString("MBRequiresAltiVec");
- OSMessageBox(
- msg.str(),
- LLStringUtil::null,
- OSMB_OK);
- removeMarkerFile();
- return false;
- }
-#endif
-
-#endif // LL_DARWIN
-
- // Display splash screen. Must be after above check for previous
- // crash as this dialog is always frontmost.
- std::string splash_msg;
- LLStringUtil::format_map_t args;
- args["[APP_NAME]"] = LLTrans::getString("SECOND_LIFE");
- splash_msg = LLTrans::getString("StartupLoading", args);
- LLSplashScreen::show();
- LLSplashScreen::update(splash_msg);
-
- //LLVolumeMgr::initClass();
- LLVolumeMgr* volume_manager = new LLVolumeMgr();
- volume_manager->useMutex(); // LLApp and LLMutex magic must be manually enabled
- LLPrimitive::setVolumeManager(volume_manager);
-
- // Note: this is where we used to initialize gFeatureManagerp.
-
- gStartTime = totalTime();
-
- //
- // Set the name of the window
- //
- gWindowTitle = LLTrans::getString("APP_NAME");
-#if LL_DEBUG
- gWindowTitle += std::string(" [DEBUG] ") + gArgs;
-#else
- gWindowTitle += std::string(" ") + gArgs;
-#endif
- LLStringUtil::truncate(gWindowTitle, 255);
-
- //RN: if we received a URL, hand it off to the existing instance.
- // don't call anotherInstanceRunning() when doing URL handoff, as
- // it relies on checking a marker file which will not work when running
- // out of different directories
-
- if (LLStartUp::getStartSLURL().isValid())
- {
- if (sendURLToOtherInstance(LLStartUp::getStartSLURL().getSLURLString()))
- {
- // successfully handed off URL to existing instance, exit
- return false;
- }
- }
-
- if (!gSavedSettings.getBOOL("AllowMultipleViewers"))
- {
- //
- // Check for another instance of the app running
- //
-
- mSecondInstance = anotherInstanceRunning();
-
- if (mSecondInstance)
- {
- std::ostringstream msg;
- msg << LLTrans::getString("MBAlreadyRunning");
- OSMessageBox(
- msg.str(),
- LLStringUtil::null,
- OSMB_OK);
- return false;
- }
-
- initMarkerFile();
-
- checkForCrash();
- }
- else
- {
- mSecondInstance = anotherInstanceRunning();
-
- if (mSecondInstance)
- {
- // This is the second instance of SL. Turn off voice support,
- // but make sure the setting is *not* persisted.
- LLControlVariable* disable_voice = gSavedSettings.getControl("CmdLineDisableVoice");
- if(disable_voice)
- {
- const BOOL DO_NOT_PERSIST = FALSE;
- disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST);
- }
- }
-
- initMarkerFile();
-
- if(!mSecondInstance)
- {
- checkForCrash();
- }
- }
-
- // need to do this here - need to have initialized global settings first
- std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" );
- if ( !nextLoginLocation.empty() )
- {
- LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation));
- };
-
- gLastRunVersion = gSavedSettings.getString("LastRunVersion");
-
- loadColorSettings();
-
- return true; // Config was successful.
-}
-
-namespace {
- // *TODO - decide if there's a better place for these functions.
- // do we need a file llupdaterui.cpp or something? -brad
-
- void apply_update_callback(LLSD const & notification, LLSD const & response)
- {
- lldebugs << "LLUpdate user response: " << response << llendl;
- if(response["OK_okcancelbuttons"].asBoolean())
- {
- llinfos << "LLUpdate restarting viewer" << llendl;
- static const bool install_if_ready = true;
- // *HACK - this lets us launch the installer immediately for now
- LLUpdaterService().startChecking(install_if_ready);
- }
- }
-
- void apply_update_ok_callback(LLSD const & notification, LLSD const & response)
- {
- llinfos << "LLUpdate restarting viewer" << llendl;
- static const bool install_if_ready = true;
- // *HACK - this lets us launch the installer immediately for now
- LLUpdaterService().startChecking(install_if_ready);
- }
-
- void on_update_downloaded(LLSD const & data)
- {
- std::string notification_name;
- void (*apply_callback)(LLSD const &, LLSD const &) = NULL;
-
- if(data["required"].asBoolean())
- {
- if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT)
- {
- // The user never saw the progress bar.
- apply_callback = &apply_update_ok_callback;
- notification_name = "RequiredUpdateDownloadedVerboseDialog";
- }
- else if(LLStartUp::getStartupState() < STATE_WORLD_INIT)
- {
- // The user is logging in but blocked.
- apply_callback = &apply_update_ok_callback;
- notification_name = "RequiredUpdateDownloadedDialog";
- }
- else
- {
- // The user is already logged in; treat like an optional update.
- apply_callback = &apply_update_callback;
- notification_name = "DownloadBackgroundTip";
- }
- }
- else
- {
- apply_callback = &apply_update_callback;
- if(LLStartUp::getStartupState() < STATE_STARTED)
- {
- // CHOP-262 we need to use a different notification
- // method prior to login.
- notification_name = "DownloadBackgroundDialog";
- }
- else
- {
- notification_name = "DownloadBackgroundTip";
- }
- }
-
- LLSD substitutions;
- substitutions["VERSION"] = data["version"];
-
- // truncate version at the rightmost '.'
- std::string version_short(data["version"]);
- size_t short_length = version_short.rfind('.');
- if (short_length != std::string::npos)
- {
- version_short.resize(short_length);
- }
-
- LLUIString relnotes_url("[RELEASE_NOTES_BASE_URL][CHANNEL_URL]/[VERSION_SHORT]");
- relnotes_url.setArg("[VERSION_SHORT]", version_short);
-
- // *TODO thread the update service's response through to this point
- std::string const & channel = LLVersionInfo::getChannel();
- boost::shared_ptr<char> channel_escaped(curl_escape(channel.c_str(), channel.size()), &curl_free);
-
- relnotes_url.setArg("[CHANNEL_URL]", channel_escaped.get());
- relnotes_url.setArg("[RELEASE_NOTES_BASE_URL]", LLTrans::getString("RELEASE_NOTES_BASE_URL"));
- substitutions["RELEASE_NOTES_FULL_URL"] = relnotes_url.getString();
-
- LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_callback);
- }
-
- void install_error_callback(LLSD const & notification, LLSD const & response)
- {
- LLAppViewer::instance()->forceQuit();
- }
-
- bool notify_update(LLSD const & evt)
- {
- std::string notification_name;
- switch (evt["type"].asInteger())
- {
- case LLUpdaterService::DOWNLOAD_COMPLETE:
- on_update_downloaded(evt);
- break;
- case LLUpdaterService::INSTALL_ERROR:
- if(evt["required"].asBoolean()) {
- LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), &install_error_callback);
- } else {
- LLNotificationsUtil::add("FailedUpdateInstall");
- }
- break;
- default:
- break;
- }
-
- // let others also handle this event by default
- return false;
- }
-
- bool on_bandwidth_throttle(LLUpdaterService * updater, LLSD const & evt)
- {
- updater->setBandwidthLimit(evt.asInteger() * (1024/8));
- return false; // Let others receive this event.
- };
-};
-
-void LLAppViewer::initUpdater()
-{
- // Initialize the updater service.
- // Generate URL to the udpater service
- // Get Channel
- // Get Version
- std::string url = gSavedSettings.getString("UpdaterServiceURL");
- std::string channel = LLVersionInfo::getChannel();
- std::string version = LLVersionInfo::getVersion();
- std::string protocol_version = gSavedSettings.getString("UpdaterServiceProtocolVersion");
- std::string service_path = gSavedSettings.getString("UpdaterServicePath");
- U32 check_period = gSavedSettings.getU32("UpdaterServiceCheckPeriod");
-
- mUpdater->setAppExitCallback(boost::bind(&LLAppViewer::forceQuit, this));
- mUpdater->initialize(protocol_version,
- url,
- service_path,
- channel,
- version);
- mUpdater->setCheckPeriod(check_period);
- mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("UpdaterMaximumBandwidth") * (1024/8));
- gSavedSettings.getControl("UpdaterMaximumBandwidth")->getSignal()->
- connect(boost::bind(&on_bandwidth_throttle, mUpdater.get(), _2));
- if(gSavedSettings.getU32("UpdaterServiceSetting"))
- {
- bool install_if_ready = true;
- mUpdater->startChecking(install_if_ready);
- }
-
- LLEventPump & updater_pump = LLEventPumps::instance().obtain(LLUpdaterService::pumpName());
- updater_pump.listen("notify_update", &notify_update);
-}
-
-void LLAppViewer::checkForCrash(void)
-{
-
-#if LL_SEND_CRASH_REPORTS
- if (gLastExecEvent == LAST_EXEC_FROZE)
- {
- llinfos << "Last execution froze, requesting to send crash report." << llendl;
- //
- // Pop up a freeze or crash warning dialog
- //
- S32 choice;
- if(gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) == CRASH_BEHAVIOR_ASK)
- {
- std::ostringstream msg;
- msg << LLTrans::getString("MBFrozenCrashed");
- std::string alert = LLTrans::getString("APP_NAME") + " " + LLTrans::getString("MBAlert");
- choice = OSMessageBox(msg.str(),
- alert,
- OSMB_YESNO);
- }
- else if(gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) == CRASH_BEHAVIOR_NEVER_SEND)
- {
- choice = OSBTN_NO;
- }
- else
- {
- choice = OSBTN_YES;
- }
-
- if (OSBTN_YES == choice)
- {
- llinfos << "Sending crash report." << llendl;
-
- bool report_freeze = true;
- handleCrashReporting(report_freeze);
- }
- else
- {
- llinfos << "Not sending crash report." << llendl;
- }
- }
-#endif // LL_SEND_CRASH_REPORTS
-
-}
-
-bool LLAppViewer::initWindow()
-{
- LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL;
-
- // store setting in a global for easy access and modification
- gNoRender = gSavedSettings.getBOOL("DisableRendering");
-
- // always start windowed
- BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth");
- gViewerWindow = new LLViewerWindow(gWindowTitle,
- VIEWER_WINDOW_CLASSNAME,
- gSavedSettings.getS32("WindowX"), gSavedSettings.getS32("WindowY"),
- gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight"),
- gSavedSettings.getBOOL("WindowFullScreen"), ignorePixelDepth);
-
- // Need to load feature table before cheking to start watchdog.
- const S32 NEVER_SUBMIT_REPORT = 2;
- bool use_watchdog = false;
- int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled");
- if(watchdog_enabled_setting == -1){
- use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled");
- }
- else
- {
- // The user has explicitly set this setting; always use that value.
- use_watchdog = bool(watchdog_enabled_setting);
- }
-
- bool send_reports = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) != NEVER_SUBMIT_REPORT;
- if(use_watchdog && send_reports)
- {
- LLWatchdog::getInstance()->init(watchdog_killer_callback);
- }
-
- LLNotificationsUI::LLNotificationManager::getInstance();
-
- if (gSavedSettings.getBOOL("WindowMaximized"))
- {
- gViewerWindow->mWindow->maximize();
- }
-
- if (!gNoRender)
- {
- //
- // Initialize GL stuff
- //
-
- if (mForceGraphicsDetail)
- {
- LLFeatureManager::getInstance()->setGraphicsLevel(gSavedSettings.getU32("RenderQualityPerformance"), false);
- }
-
- // Set this flag in case we crash while initializing GL
- gSavedSettings.setBOOL("RenderInitError", TRUE);
- gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
-
- gPipeline.init();
- stop_glerror();
- gViewerWindow->initGLDefaults();
-
- gSavedSettings.setBOOL("RenderInitError", FALSE);
- gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
- }
-
- //If we have a startup crash, it's usually near GL initialization, so simulate that.
- if(gCrashOnStartup)
- {
- LLAppViewer::instance()->forceErrorLLError();
- }
-
- LLUI::sWindow = gViewerWindow->getWindow();
-
- // Show watch cursor
- gViewerWindow->setCursor(UI_CURSOR_WAIT);
-
- // Finish view initialization
- gViewerWindow->initBase();
-
- // show viewer window
- //gViewerWindow->mWindow->show();
-
-
- return true;
-}
-
-void LLAppViewer::writeDebugInfo()
-{
- std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
- llinfos << "Opening debug file " << debug_filename << llendl;
- llofstream out_file(debug_filename);
- LLSDSerialize::toPrettyXML(gDebugInfo, out_file);
- out_file.close();
-}
-
-void LLAppViewer::cleanupSavedSettings()
-{
- gSavedSettings.setBOOL("MouseSun", FALSE);
-
- gSavedSettings.setBOOL("UseEnergy", TRUE); // force toggle to turn off, since sends message to simulator
-
- gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc);
-
- gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates);
-
- if (!gNoRender)
- {
- if (gDebugView)
- {
- gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible());
- }
- }
-
- // save window position if not maximized
- // as we don't track it in callbacks
- if(NULL != gViewerWindow)
- {
- BOOL maximized = gViewerWindow->mWindow->getMaximized();
- if (!maximized)
- {
- LLCoordScreen window_pos;
-
- if (gViewerWindow->mWindow->getPosition(&window_pos))
- {
- gSavedSettings.setS32("WindowX", window_pos.mX);
- gSavedSettings.setS32("WindowY", window_pos.mY);
- }
- }
- }
-
- gSavedSettings.setF32("MapScale", LLWorldMapView::sMapScale );
-
- // Some things are cached in LLAgent.
- if (gAgent.isInitialized())
- {
- gSavedSettings.setF32("RenderFarClip", gAgentCamera.mDrawDistance);
- }
-}
-
-void LLAppViewer::removeCacheFiles(const std::string& file_mask)
-{
- std::string mask = gDirUtilp->getDirDelimiter() + file_mask;
- gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), mask);
-}
-
-void LLAppViewer::writeSystemInfo()
-{
- gDebugInfo["SLLog"] = LLError::logFileName();
-
- gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
- gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
- gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
- gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
- gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
-
- gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
-
- gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString();
- gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily();
- gDebugInfo["CPUInfo"]["CPUMhz"] = (S32)gSysCPU.getMHz();
- gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec();
- gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE();
- gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2();
-
- gDebugInfo["RAMInfo"]["Physical"] = (LLSD::Integer)(gSysMemory.getPhysicalMemoryKB());
- gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer)(gMemoryAllocated>>10); // MB -> KB
- gDebugInfo["OSInfo"] = getOSInfo().getOSStringSimple();
-
- // The user is not logged on yet, but record the current grid choice login url
- // which may have been the intended grid. This can b
- gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel();
-
- // *FIX:Mani - move this down in llappviewerwin32
-#ifdef LL_WINDOWS
- DWORD thread_id = GetCurrentThreadId();
- gDebugInfo["MainloopThreadID"] = (S32)thread_id;
-#endif
-
- // "CrashNotHandled" is set here, while things are running well,
- // in case of a freeze. If there is a freeze, the crash logger will be launched
- // and can read this value from the debug_info.log.
- // If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze,
- // then the value of "CrashNotHandled" will be set to true.
- gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true;
-
- // Insert crash host url (url to post crash log to) if configured. This insures
- // that the crash report will go to the proper location in the case of a
- // prior freeze.
- std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
- if(crashHostUrl != "")
- {
- gDebugInfo["CrashHostUrl"] = crashHostUrl;
- }
-
- // Dump some debugging info
- LL_INFOS("SystemInfo") << LLTrans::getString("APP_NAME")
- << " version " << LLVersionInfo::getShortVersion() << LL_ENDL;
-
- // Dump the local time and time zone
- time_t now;
- time(&now);
- char tbuffer[256]; /* Flawfinder: ignore */
- strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now));
- LL_INFOS("SystemInfo") << "Local time: " << tbuffer << LL_ENDL;
-
- // query some system information
- LL_INFOS("SystemInfo") << "CPU info:\n" << gSysCPU << LL_ENDL;
- LL_INFOS("SystemInfo") << "Memory info:\n" << gSysMemory << LL_ENDL;
- LL_INFOS("SystemInfo") << "OS: " << getOSInfo().getOSStringSimple() << LL_ENDL;
- LL_INFOS("SystemInfo") << "OS info: " << getOSInfo() << LL_ENDL;
-
- writeDebugInfo(); // Save out debug_info.log early, in case of crash.
-}
-
-void LLAppViewer::handleViewerCrash()
-{
- llinfos << "Handle viewer crash entry." << llendl;
-
- llinfos << "Last render pool type: " << LLPipeline::sCurRenderPoolType << llendl ;
-
- //print out recorded call stacks if there are any.
- LLError::LLCallStacks::print();
-
- LLAppViewer* pApp = LLAppViewer::instance();
- if (pApp->beingDebugged())
- {
- // This will drop us into the debugger.
- abort();
- }
-
- if (LLApp::isCrashloggerDisabled())
- {
- abort();
- }
-
- // Returns whether a dialog was shown.
- // Only do the logic in here once
- if (pApp->mReportedCrash)
- {
- return;
- }
- pApp->mReportedCrash = TRUE;
-
- // Insert crash host url (url to post crash log to) if configured.
- std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
- if(crashHostUrl != "")
- {
- gDebugInfo["CrashHostUrl"] = crashHostUrl;
- }
-
- //We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version
- //to check against no matter what
- gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
-
- gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
- gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
- gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
- gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
-
- LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
- if ( parcel && parcel->getMusicURL()[0])
- {
- gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL();
- }
- if ( parcel && parcel->getMediaURL()[0])
- {
- gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL();
- }
-
-
- gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile");
- gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
- gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();
- gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath();
- gDebugInfo["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds());
- gDebugInfo["StartupState"] = LLStartUp::getStartupStateString();
- gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10;
- gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin();
- gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");
-
- char *minidump_file = pApp->getMiniDumpFilename();
- if(minidump_file && minidump_file[0] != 0)
- {
- gDebugInfo["MinidumpPath"] = minidump_file;
- }
-
- if(gLogoutInProgress)
- {
- gDebugInfo["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH;
- }
- else
- {
- gDebugInfo["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH;
- }
-
- if(gAgent.getRegion())
- {
- gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName();
- gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName();
-
- const LLVector3& loc = gAgent.getPositionAgent();
- gDebugInfo["CurrentLocationX"] = loc.mV[0];
- gDebugInfo["CurrentLocationY"] = loc.mV[1];
- gDebugInfo["CurrentLocationZ"] = loc.mV[2];
- }
-
- if(LLAppViewer::instance()->mMainloopTimeout)
- {
- gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
- }
-
- // The crash is being handled here so set this value to false.
- // Otherwise the crash logger will think this crash was a freeze.
- gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)false;
-
- //Write out the crash status file
- //Use marker file style setup, as that's the simplest, especially since
- //we're already in a crash situation
- if (gDirUtilp)
- {
- std::string crash_file_name;
- if(gLLErrorActivated) crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LLERROR_MARKER_FILE_NAME);
- else crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,ERROR_MARKER_FILE_NAME);
- llinfos << "Creating crash marker file " << crash_file_name << llendl;
-
- LLAPRFile crash_file ;
- crash_file.open(crash_file_name, LL_APR_W);
- if (crash_file.getFileHandle())
- {
- LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL;
- }
- else
- {
- LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_file_name << LL_ENDL;
- }
- }
-
- if (gMessageSystem && gDirUtilp)
- {
- std::string filename;
- filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "stats.log");
- llofstream file(filename, llofstream::binary);
- if(file.good())
- {
- llinfos << "Handle viewer crash generating stats log." << llendl;
- gMessageSystem->summarizeLogs(file);
- file.close();
- }
- }
-
- if (gMessageSystem)
- {
- gMessageSystem->getCircuitInfo(gDebugInfo["CircuitInfo"]);
- gMessageSystem->stopLogging();
- }
-
- if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo);
-
- // Close the debug file
- pApp->writeDebugInfo();
-
- LLError::logToFile("");
-
- // Remove the marker file, since otherwise we'll spawn a process that'll keep it locked
- if(gDebugInfo["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH)
- {
- pApp->removeMarkerFile(true);
- }
- else
- {
- pApp->removeMarkerFile(false);
- }
-
-#if LL_SEND_CRASH_REPORTS
- // Call to pure virtual, handled by platform specific llappviewer instance.
- pApp->handleCrashReporting();
-#endif
-
- return;
-}
-
-bool LLAppViewer::anotherInstanceRunning()
-{
- // We create a marker file when the program starts and remove the file when it finishes.
- // If the file is currently locked, that means another process is already running.
-
- std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, MARKER_FILE_NAME);
- LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
-
- //Freeze case checks
- if (LLAPRFile::isExist(marker_file, NULL, LL_APR_RB))
- {
- // File exists, try opening with write permissions
- LLAPRFile outfile ;
- outfile.open(marker_file, LL_APR_WB);
- apr_file_t* fMarker = outfile.getFileHandle() ;
- if (!fMarker)
- {
- // Another instance is running. Skip the rest of these operations.
- LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
- return true;
- }
- if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) //flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1)
- {
- LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
- return true;
- }
- // No other instances; we'll lock this file now & delete on quit.
- }
- LL_DEBUGS("MarkerFile") << "Marker file isn't locked." << LL_ENDL;
- return false;
-}
-
-void LLAppViewer::initMarkerFile()
-{
- //First, check for the existence of other files.
- //There are marker files for two different types of crashes
-
- mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME);
- LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
-
- //We've got 4 things to test for here
- // - Other Process Running (SecondLife.exec_marker present, locked)
- // - Freeze (SecondLife.exec_marker present, not locked)
- // - LLError Crash (SecondLife.llerror_marker present)
- // - Other Crash (SecondLife.error_marker present)
- // These checks should also remove these files for the last 2 cases if they currently exist
-
- //LLError/Error checks. Only one of these should ever happen at a time.
- std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME);
- std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
- std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
-
- if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning())
- {
- gLastExecEvent = LAST_EXEC_FROZE;
- LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL;
- }
- if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB))
- {
- gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
- LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
- LLAPRFile::remove(logout_marker_file);
- }
- if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB))
- {
- if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
- else gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
- LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
- LLAPRFile::remove(llerror_marker_file);
- }
- if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB))
- {
- if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
- else gLastExecEvent = LAST_EXEC_OTHER_CRASH;
- LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
- LLAPRFile::remove(error_marker_file);
- }
-
- // No new markers if another instance is running.
- if(anotherInstanceRunning())
- {
- return;
- }
-
- // Create the marker file for this execution & lock it
- apr_status_t s;
- s = mMarkerFile.open(mMarkerFileName, LL_APR_W, TRUE);
-
- if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
- {
- LL_DEBUGS("MarkerFile") << "Marker file created." << LL_ENDL;
- }
- else
- {
- LL_INFOS("MarkerFile") << "Failed to create marker file." << LL_ENDL;
- return;
- }
- if (apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS)
- {
- mMarkerFile.close() ;
- LL_INFOS("MarkerFile") << "Marker file cannot be locked." << LL_ENDL;
- return;
- }
-
- LL_DEBUGS("MarkerFile") << "Marker file locked." << LL_ENDL;
-}
-
-void LLAppViewer::removeMarkerFile(bool leave_logout_marker)
-{
- LL_DEBUGS("MarkerFile") << "removeMarkerFile()" << LL_ENDL;
- if (mMarkerFile.getFileHandle())
- {
- mMarkerFile.close() ;
- LLAPRFile::remove( mMarkerFileName );
- }
- if (mLogoutMarkerFile != NULL && !leave_logout_marker)
- {
- LLAPRFile::remove( mLogoutMarkerFileName );
- mLogoutMarkerFile = NULL;
- }
-}
-
-void LLAppViewer::forceQuit()
-{
- LLApp::setQuitting();
-}
-
-//TODO: remove
-void LLAppViewer::fastQuit(S32 error_code)
-{
- // finish pending transfers
- flushVFSIO();
- // let sim know we're logging out
- sendLogoutRequest();
- // flush network buffers by shutting down messaging system
- end_messaging_system();
- // figure out the error code
- S32 final_error_code = error_code ? error_code : (S32)isError();
- // this isn't a crash
- removeMarkerFile();
- // get outta here
- _exit(final_error_code);
-}
-
-void LLAppViewer::requestQuit()
-{
- llinfos << "requestQuit" << llendl;
-
- LLViewerRegion* region = gAgent.getRegion();
-
- if( (LLStartUp::getStartupState() < STATE_STARTED) || !region )
- {
- // If we have a region, make some attempt to send a logout request first.
- // This prevents the halfway-logged-in avatar from hanging around inworld for a couple minutes.
- if(region)
- {
- sendLogoutRequest();
- }
-
- // Quit immediately
- forceQuit();
- return;
- }
-
- // Try to send metrics back to the grid
- metricsSend(!gDisconnected);
-
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
- effectp->setPositionGlobal(gAgent.getPositionGlobal());
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- LLHUDManager::getInstance()->sendEffects();
- effectp->markDead() ;//remove it.
-
- // Attempt to close all floaters that might be
- // editing things.
- if (gFloaterView)
- {
- // application is quitting
- gFloaterView->closeAllChildren(true);
- }
-
- LLSideTray::getInstance()->notifyChildren(LLSD().with("request","quit"));
-
- send_stats();
-
- gLogoutTimer.reset();
- mQuitRequested = true;
-}
-
-static bool finish_quit(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-
- if (option == 0)
- {
- LLAppViewer::instance()->requestQuit();
- }
- return false;
-}
-static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_quit);
-
-void LLAppViewer::userQuit()
-{
- if (gDisconnected || gViewerWindow->getProgressView()->getVisible())
- {
- requestQuit();
- }
- else
- {
- LLNotificationsUtil::add("ConfirmQuit");
- }
-}
-
-static bool finish_early_exit(const LLSD& notification, const LLSD& response)
-{
- LLAppViewer::instance()->forceQuit();
- return false;
-}
-
-void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions)
-{
- llwarns << "app_early_exit: " << name << llendl;
- gDoDisconnect = TRUE;
- LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit);
-}
-
-// case where we need the viewer to exit without any need for notifications
-void LLAppViewer::earlyExitNoNotify()
-{
- llwarns << "app_early_exit with no notification: " << llendl;
- gDoDisconnect = TRUE;
- finish_early_exit( LLSD(), LLSD() );
-}
-
-void LLAppViewer::abortQuit()
-{
- llinfos << "abortQuit()" << llendl;
- mQuitRequested = false;
-}
-
-void LLAppViewer::migrateCacheDirectory()
-{
-#if LL_WINDOWS || LL_DARWIN
- // NOTE: (Nyx) as of 1.21, cache for mac is moving to /library/caches/SecondLife from
- // /library/application support/SecondLife/cache This should clear/delete the old dir.
-
- // As of 1.23 the Windows cache moved from
- // C:\Documents and Settings\James\Application Support\SecondLife\cache
- // to
- // C:\Documents and Settings\James\Local Settings\Application Support\SecondLife
- //
- // The Windows Vista equivalent is from
- // C:\Users\James\AppData\Roaming\SecondLife\cache
- // to
- // C:\Users\James\AppData\Local\SecondLife
- //
- // Note the absence of \cache on the second path. James.
-
- // Only do this once per fresh install of this version.
- if (gSavedSettings.getBOOL("MigrateCacheDirectory"))
- {
- gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE);
-
- std::string delimiter = gDirUtilp->getDirDelimiter();
- std::string old_cache_dir = gDirUtilp->getOSUserAppDir() + delimiter + "cache";
- std::string new_cache_dir = gDirUtilp->getCacheDir(true);
-
- if (gDirUtilp->fileExists(old_cache_dir))
- {
- llinfos << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << llendl;
-
- // Migrate inventory cache to avoid pain to inventory database after mass update
- S32 file_count = 0;
- std::string file_name;
- std::string mask = delimiter + "*.*";
- while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name))
- {
- if (file_name == "." || file_name == "..") continue;
- std::string source_path = old_cache_dir + delimiter + file_name;
- std::string dest_path = new_cache_dir + delimiter + file_name;
- if (!LLFile::rename(source_path, dest_path))
- {
- file_count++;
- }
- }
- llinfos << "Moved " << file_count << " files" << llendl;
-
- // Nuke the old cache
- gDirUtilp->setCacheDir(old_cache_dir);
- purgeCache();
- gDirUtilp->setCacheDir(new_cache_dir);
-
-#if LL_DARWIN
- // Clean up Mac files not deleted by removing *.*
- std::string ds_store = old_cache_dir + "/.DS_Store";
- if (gDirUtilp->fileExists(ds_store))
- {
- LLFile::remove(ds_store);
- }
-#endif
- if (LLFile::rmdir(old_cache_dir) != 0)
- {
- llwarns << "could not delete old cache directory " << old_cache_dir << llendl;
- }
- }
- }
-#endif // LL_WINDOWS || LL_DARWIN
-}
-
-void dumpVFSCaches()
-{
- llinfos << "======= Static VFS ========" << llendl;
- gStaticVFS->listFiles();
-#if LL_WINDOWS
- llinfos << "======= Dumping static VFS to StaticVFSDump ========" << llendl;
- WCHAR w_str[MAX_PATH];
- GetCurrentDirectory(MAX_PATH, w_str);
- S32 res = LLFile::mkdir("StaticVFSDump");
- if (res == -1)
- {
- if (errno != EEXIST)
- {
- llwarns << "Couldn't create dir StaticVFSDump" << llendl;
- }
- }
- SetCurrentDirectory(utf8str_to_utf16str("StaticVFSDump").c_str());
- gStaticVFS->dumpFiles();
- SetCurrentDirectory(w_str);
-#endif
-
- llinfos << "========= Dynamic VFS ====" << llendl;
- gVFS->listFiles();
-#if LL_WINDOWS
- llinfos << "========= Dumping dynamic VFS to VFSDump ====" << llendl;
- res = LLFile::mkdir("VFSDump");
- if (res == -1)
- {
- if (errno != EEXIST)
- {
- llwarns << "Couldn't create dir VFSDump" << llendl;
- }
- }
- SetCurrentDirectory(utf8str_to_utf16str("VFSDump").c_str());
- gVFS->dumpFiles();
- SetCurrentDirectory(w_str);
-#endif
-}
-
-//static
-U32 LLAppViewer::getTextureCacheVersion()
-{
- //viewer texture cache version, change if the texture cache format changes.
- const U32 TEXTURE_CACHE_VERSION = 7;
-
- return TEXTURE_CACHE_VERSION ;
-}
-
-//static
-U32 LLAppViewer::getObjectCacheVersion()
-{
- // Viewer object cache version, change if object update
- // format changes. JC
- const U32 INDRA_OBJECT_CACHE_VERSION = 14;
-
- return INDRA_OBJECT_CACHE_VERSION;
-}
-
-bool LLAppViewer::initCache()
-{
- mPurgeCache = false;
- BOOL read_only = mSecondInstance ? TRUE : FALSE;
- LLAppViewer::getTextureCache()->setReadOnly(read_only) ;
- LLVOCache::getInstance()->setReadOnly(read_only);
-
- BOOL texture_cache_mismatch = FALSE ;
- if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion())
- {
- texture_cache_mismatch = TRUE ;
- if(!read_only)
- {
- gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion());
- }
- }
-
- if(!read_only)
- {
- // Purge cache if user requested it
- if (gSavedSettings.getBOOL("PurgeCacheOnStartup") ||
- gSavedSettings.getBOOL("PurgeCacheOnNextStartup"))
- {
- gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false);
- mPurgeCache = true;
- }
-
- // We have moved the location of the cache directory over time.
- migrateCacheDirectory();
-
- // Setup and verify the cache location
- std::string cache_location = gSavedSettings.getString("CacheLocation");
- std::string new_cache_location = gSavedSettings.getString("NewCacheLocation");
- if (new_cache_location != cache_location)
- {
- gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"));
- purgeCache(); // purge old cache
- gSavedSettings.setString("CacheLocation", new_cache_location);
- gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location));
- }
- }
-
- if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")))
- {
- LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL;
- gSavedSettings.setString("CacheLocation", "");
- gSavedSettings.setString("CacheLocationTopFolder", "");
- }
-
- if (mPurgeCache && !read_only)
- {
- LLSplashScreen::update(LLTrans::getString("StartupClearingCache"));
- purgeCache();
- }
-
- LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache"));
-
- // Init the texture cache
- // Allocate 80% of the cache size for textures
- const S32 MB = 1024*1024;
- S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB;
- const S64 MAX_CACHE_SIZE = 1024*MB;
- cache_size = llmin(cache_size, MAX_CACHE_SIZE);
- S64 texture_cache_size = ((cache_size * 8)/10);
- S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch);
- texture_cache_size -= extra;
-
- LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()) ;
-
- LLSplashScreen::update(LLTrans::getString("StartupInitializingVFS"));
-
- // Init the VFS
- S64 vfs_size = cache_size - texture_cache_size;
- const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB
- vfs_size = llmin(vfs_size, MAX_VFS_SIZE);
- vfs_size = (vfs_size / MB) * MB; // make sure it is MB aligned
- U32 vfs_size_u32 = (U32)vfs_size;
- U32 old_vfs_size = gSavedSettings.getU32("VFSOldSize") * MB;
- bool resize_vfs = (vfs_size_u32 != old_vfs_size);
- if (resize_vfs)
- {
- gSavedSettings.setU32("VFSOldSize", vfs_size_u32/MB);
- }
- LL_INFOS("AppCache") << "VFS CACHE SIZE: " << vfs_size/(1024*1024) << " MB" << LL_ENDL;
-
- // This has to happen BEFORE starting the vfs
- //time_t ltime;
- srand(time(NULL)); // Flawfinder: ignore
- U32 old_salt = gSavedSettings.getU32("VFSSalt");
- U32 new_salt;
- std::string old_vfs_data_file;
- std::string old_vfs_index_file;
- std::string new_vfs_data_file;
- std::string new_vfs_index_file;
- std::string static_vfs_index_file;
- std::string static_vfs_data_file;
-
- if (gSavedSettings.getBOOL("AllowMultipleViewers"))
- {
- // don't mess with renaming the VFS in this case
- new_salt = old_salt;
- }
- else
- {
- do
- {
- new_salt = rand();
- } while( new_salt == old_salt );
- }
-
- old_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE) + llformat("%u",old_salt);
-
- // make sure this file exists
- llstat s;
- S32 stat_result = LLFile::stat(old_vfs_data_file, &s);
- if (stat_result)
- {
- // doesn't exist, look for a data file
- std::string mask;
- mask = gDirUtilp->getDirDelimiter();
- mask += VFS_DATA_FILE_BASE;
- mask += "*";
-
- std::string dir;
- dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
-
- std::string found_file;
- if (gDirUtilp->getNextFileInDir(dir, mask, found_file))
- {
- old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file;
-
- S32 start_pos = found_file.find_last_of('.');
- if (start_pos > 0)
- {
- sscanf(found_file.substr(start_pos+1).c_str(), "%d", &old_salt);
- }
- LL_DEBUGS("AppCache") << "Default vfs data file not present, found: " << old_vfs_data_file << " Old salt: " << old_salt << llendl;
- }
- }
-
- old_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_INDEX_FILE_BASE) + llformat("%u",old_salt);
-
- stat_result = LLFile::stat(old_vfs_index_file, &s);
- if (stat_result)
- {
- // We've got a bad/missing index file, nukem!
- LL_WARNS("AppCache") << "Bad or missing vfx index file " << old_vfs_index_file << LL_ENDL;
- LL_WARNS("AppCache") << "Removing old vfs data file " << old_vfs_data_file << LL_ENDL;
- LLFile::remove(old_vfs_data_file);
- LLFile::remove(old_vfs_index_file);
-
- // Just in case, nuke any other old cache files in the directory.
- std::string dir;
- dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
-
- std::string mask;
- mask = gDirUtilp->getDirDelimiter();
- mask += VFS_DATA_FILE_BASE;
- mask += "*";
-
- gDirUtilp->deleteFilesInDir(dir, mask);
-
- mask = gDirUtilp->getDirDelimiter();
- mask += VFS_INDEX_FILE_BASE;
- mask += "*";
-
- gDirUtilp->deleteFilesInDir(dir, mask);
- }
-
- new_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE) + llformat("%u",new_salt);
- new_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u",new_salt);
-
- static_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_data.db2");
- static_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_index.db2");
-
- if (resize_vfs)
- {
- LL_DEBUGS("AppCache") << "Removing old vfs and re-sizing" << LL_ENDL;
-
- LLFile::remove(old_vfs_data_file);
- LLFile::remove(old_vfs_index_file);
- }
- else if (old_salt != new_salt)
- {
- // move the vfs files to a new name before opening
- LL_DEBUGS("AppCache") << "Renaming " << old_vfs_data_file << " to " << new_vfs_data_file << LL_ENDL;
- LL_DEBUGS("AppCache") << "Renaming " << old_vfs_index_file << " to " << new_vfs_index_file << LL_ENDL;
- LLFile::rename(old_vfs_data_file, new_vfs_data_file);
- LLFile::rename(old_vfs_index_file, new_vfs_index_file);
- }
-
- // Startup the VFS...
- gSavedSettings.setU32("VFSSalt", new_salt);
-
- // Don't remove VFS after viewer crashes. If user has corrupt data, they can reinstall. JC
- gVFS = LLVFS::createLLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false);
- if( !gVFS )
- {
- return false;
- }
-
- gStaticVFS = LLVFS::createLLVFS(static_vfs_index_file, static_vfs_data_file, true, 0, false);
- if( !gStaticVFS )
- {
- return false;
- }
-
- BOOL success = gVFS->isValid() && gStaticVFS->isValid();
- if( !success )
- {
- return false;
- }
- else
- {
- LLVFile::initClass();
-
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- if (gSavedSettings.getBOOL("DumpVFSCaches"))
- {
- dumpVFSCaches();
- }
-#endif
-
- return true;
- }
-}
-
-void LLAppViewer::purgeCache()
-{
- LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << llendl;
- LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE);
- LLVOCache::getInstance()->removeCache(LL_PATH_CACHE);
- std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
- gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
-}
-
-std::string LLAppViewer::getSecondLifeTitle() const
-{
- return LLTrans::getString("APP_NAME");
-}
-
-std::string LLAppViewer::getWindowTitle() const
-{
- return gWindowTitle;
-}
-
-// Callback from a dialog indicating user was logged out.
-bool finish_disconnect(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-
- if (1 == option)
- {
- LLAppViewer::instance()->forceQuit();
- }
- return false;
-}
-
-// Callback from an early disconnect dialog, force an exit
-bool finish_forced_disconnect(const LLSD& notification, const LLSD& response)
-{
- LLAppViewer::instance()->forceQuit();
- return false;
-}
-
-
-void LLAppViewer::forceDisconnect(const std::string& mesg)
-{
- if (gDoDisconnect)
- {
- // Already popped up one of these dialogs, don't
- // do this again.
- return;
- }
-
- // *TODO: Translate the message if possible
- std::string big_reason = LLAgent::sTeleportErrorMessages[mesg];
- if ( big_reason.size() == 0 )
- {
- big_reason = mesg;
- }
-
- LLSD args;
- gDoDisconnect = TRUE;
-
- if (LLStartUp::getStartupState() < STATE_STARTED)
- {
- // Tell users what happened
- args["ERROR_MESSAGE"] = big_reason;
- LLNotificationsUtil::add("ErrorMessage", args, LLSD(), &finish_forced_disconnect);
- }
- else
- {
- args["MESSAGE"] = big_reason;
- LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect );
- }
-}
-
-void LLAppViewer::badNetworkHandler()
-{
- // Dump the packet
- gMessageSystem->dumpPacketToLog();
-
- // Flush all of our caches on exit in the case of disconnect due to
- // invalid packets.
-
- mPurgeOnExit = TRUE;
-
- std::ostringstream message;
- message <<
- "The viewer has detected mangled network data indicative\n"
- "of a bad upstream network connection or an incomplete\n"
- "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n"
- " \n"
- "Try uninstalling and reinstalling to see if this resolves \n"
- "the issue. \n"
- " \n"
- "If the problem continues, see the Tech Support FAQ at: \n"
- "www.secondlife.com/support";
- forceDisconnect(message.str());
-
- LLApp::instance()->writeMiniDump();
-}
-
-// This routine may get called more than once during the shutdown process.
-// This can happen because we need to get the screenshot before the window
-// is destroyed.
-void LLAppViewer::saveFinalSnapshot()
-{
- if (!mSavedFinalSnapshot && !gNoRender)
- {
- gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal());
- gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal());
- gViewerWindow->setCursor(UI_CURSOR_WAIT);
- gAgentCamera.changeCameraToThirdPerson( FALSE ); // don't animate, need immediate switch
- gSavedSettings.setBOOL("ShowParcelOwners", FALSE);
- idle();
-
- std::string snap_filename = gDirUtilp->getLindenUserDir();
- snap_filename += gDirUtilp->getDirDelimiter();
- snap_filename += SCREEN_LAST_FILENAME;
- // use full pixel dimensions of viewer window (not post-scale dimensions)
- gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, TRUE);
- mSavedFinalSnapshot = TRUE;
- }
-}
-
-void LLAppViewer::loadNameCache()
-{
- // display names cache
- std::string filename =
- gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
- LL_INFOS("AvNameCache") << filename << LL_ENDL;
- llifstream name_cache_stream(filename);
- if(name_cache_stream.is_open())
- {
- LLAvatarNameCache::importFile(name_cache_stream);
- }
-
- if (!gCacheName) return;
-
- std::string name_cache;
- name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
- llifstream cache_file(name_cache);
- if(cache_file.is_open())
- {
- if(gCacheName->importFile(cache_file)) return;
- }
-}
-
-void LLAppViewer::saveNameCache()
- {
- // display names cache
- std::string filename =
- gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
- llofstream name_cache_stream(filename);
- if(name_cache_stream.is_open())
- {
- LLAvatarNameCache::exportFile(name_cache_stream);
-}
-
- if (!gCacheName) return;
-
- std::string name_cache;
- name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
- llofstream cache_file(name_cache);
- if(cache_file.is_open())
- {
- gCacheName->exportFile(cache_file);
- }
-}
-
-/*! @brief This class is an LLFrameTimer that can be created with
- an elapsed time that starts counting up from the given value
- rather than 0.0.
-
- Otherwise it behaves the same way as LLFrameTimer.
-*/
-class LLFrameStatsTimer : public LLFrameTimer
-{
-public:
- LLFrameStatsTimer(F64 elapsed_already = 0.0)
- : LLFrameTimer()
- {
- mStartTime -= elapsed_already;
- }
-};
-
-static LLFastTimer::DeclareTimer FTM_AUDIO_UPDATE("Update Audio");
-static LLFastTimer::DeclareTimer FTM_CLEANUP("Cleanup");
-static LLFastTimer::DeclareTimer FTM_IDLE_CB("Idle Callbacks");
-static LLFastTimer::DeclareTimer FTM_LOD_UPDATE("Update LOD");
-static LLFastTimer::DeclareTimer FTM_OBJECTLIST_UPDATE("Update Objectlist");
-static LLFastTimer::DeclareTimer FTM_REGION_UPDATE("Update Region");
-static LLFastTimer::DeclareTimer FTM_WORLD_UPDATE("Update World");
-static LLFastTimer::DeclareTimer FTM_NETWORK("Network");
-
-///////////////////////////////////////////////////////
-// idle()
-//
-// Called every time the window is not doing anything.
-// Receive packets, update statistics, and schedule a redisplay.
-///////////////////////////////////////////////////////
-void LLAppViewer::idle()
-{
- LLMemType mt_idle(LLMemType::MTYPE_IDLE);
- pingMainloopTimeout("Main:Idle");
-
- // Update frame timers
- static LLTimer idle_timer;
-
- LLFrameTimer::updateFrameTime();
- LLFrameTimer::updateFrameCount();
- LLEventTimer::updateClass();
- LLCriticalDamp::updateInterpolants();
- LLMortician::updateClass();
- F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
-
- // Cap out-of-control frame times
- // Too low because in menus, swapping, debugger, etc.
- // Too high because idle called with no objects in view, etc.
- const F32 MIN_FRAME_RATE = 1.f;
- const F32 MAX_FRAME_RATE = 200.f;
-
- F32 frame_rate_clamped = 1.f / dt_raw;
- frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE);
- gFrameDTClamped = 1.f / frame_rate_clamped;
-
- // Global frame timer
- // Smoothly weight toward current frame
- gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f;
-
- F32 qas = gSavedSettings.getF32("QuitAfterSeconds");
- if (qas > 0.f)
- {
- if (gRenderStartTime.getElapsedTimeF32() > qas)
- {
- LLAppViewer::instance()->forceQuit();
- }
- }
-
- // debug setting to quit after N seconds of being AFK - 0 to never do this
- F32 qas_afk = gSavedSettings.getF32("QuitAfterSecondsOfAFK");
- if (qas_afk > 0.f)
- {
- // idle time is more than setting
- if ( gAwayTriggerTimer.getElapsedTimeF32() > qas_afk )
- {
- // go ahead and just quit gracefully
- LLAppViewer::instance()->requestQuit();
- }
- }
-
- // Must wait until both have avatar object and mute list, so poll
- // here.
- request_initial_instant_messages();
-
- ///////////////////////////////////
- //
- // Special case idle if still starting up
- //
- if (LLStartUp::getStartupState() < STATE_STARTED)
- {
- // Skip rest if idle startup returns false (essentially, no world yet)
- gGLActive = TRUE;
- if (!idle_startup())
- {
- gGLActive = FALSE;
- return;
- }
- gGLActive = FALSE;
- }
-
-
- F32 yaw = 0.f; // radians
-
- if (!gDisconnected)
- {
- LLFastTimer t(FTM_NETWORK);
- // Update spaceserver timeinfo
- LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC));
-
-
- //////////////////////////////////////
- //
- // Update simulator agent state
- //
-
- if (gSavedSettings.getBOOL("RotateRight"))
- {
- gAgent.moveYaw(-1.f);
- }
-
- {
- LLFastTimer t(FTM_AGENT_AUTOPILOT);
- // Handle automatic walking towards points
- gAgentPilot.updateTarget();
- gAgent.autoPilot(&yaw);
- }
-
- static LLFrameTimer agent_update_timer;
- static U32 last_control_flags;
-
- // When appropriate, update agent location to the simulator.
- F32 agent_update_time = agent_update_timer.getElapsedTimeF32();
- BOOL flags_changed = gAgent.controlFlagsDirty() || (last_control_flags != gAgent.getControlFlags());
-
- if (flags_changed || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND)))
- {
- LLFastTimer t(FTM_AGENT_UPDATE);
- // Send avatar and camera info
- last_control_flags = gAgent.getControlFlags();
- send_agent_update(TRUE);
- agent_update_timer.reset();
- }
- }
-
- //////////////////////////////////////
- //
- // Manage statistics
- //
- //
- {
- // Initialize the viewer_stats_timer with an already elapsed time
- // of SEND_STATS_PERIOD so that the initial stats report will
- // be sent immediately.
- static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD);
- reset_statistics();
-
- // Update session stats every large chunk of time
- // *FIX: (???) SAMANTHA
- if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected)
- {
- llinfos << "Transmitting sessions stats" << llendl;
- send_stats();
- viewer_stats_timer.reset();
- }
-
- // Print the object debugging stats
- static LLFrameTimer object_debug_timer;
- if (object_debug_timer.getElapsedTimeF32() > 5.f)
- {
- object_debug_timer.reset();
- if (gObjectList.mNumDeadObjectUpdates)
- {
- llinfos << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << llendl;
- gObjectList.mNumDeadObjectUpdates = 0;
- }
- if (gObjectList.mNumUnknownKills)
- {
- llinfos << "Kills on unknown objects: " << gObjectList.mNumUnknownKills << llendl;
- gObjectList.mNumUnknownKills = 0;
- }
- if (gObjectList.mNumUnknownUpdates)
- {
- llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl;
- gObjectList.mNumUnknownUpdates = 0;
- }
-
- // ViewerMetrics FPS piggy-backing on the debug timer.
- // The 5-second interval is nice for this purpose. If the object debug
- // bit moves or is disabled, please give this a suitable home.
- LLViewerAssetStatsFF::record_fps_main(gFPSClamped);
- }
- }
-
- if (!gDisconnected)
- {
- LLFastTimer t(FTM_NETWORK);
-
- ////////////////////////////////////////////////
- //
- // Network processing
- //
- // NOTE: Starting at this point, we may still have pointers to "dead" objects
- // floating throughout the various object lists.
- //
- idleNameCache();
-
- idleNetwork();
-
-
- // Check for away from keyboard, kick idle agents.
- idle_afk_check();
-
- // Update statistics for this frame
- update_statistics(gFrameCount);
- }
-
- ////////////////////////////////////////
- //
- // Handle the regular UI idle callbacks as well as
- // hover callbacks
- //
-
- {
-// LLFastTimer t(FTM_IDLE_CB);
-
- // Do event notifications if necessary. Yes, we may want to move this elsewhere.
- gEventNotifier.update();
-
- gIdleCallbacks.callFunctions();
- gInventory.idleNotifyObservers();
- }
-
- // Metrics logging (LLViewerAssetStats, etc.)
- {
- static LLTimer report_interval;
-
- // *TODO: Add configuration controls for this
- if (report_interval.getElapsedTimeF32() >= app_metrics_interval)
- {
- metricsSend(! gDisconnected);
- report_interval.reset();
- }
- }
-
- if (gDisconnected)
- {
- return;
- }
-
- gViewerWindow->updateUI();
-
- ///////////////////////////////////////
- // Agent and camera movement
- //
- LLCoordGL current_mouse = gViewerWindow->getCurrentMouse();
-
- {
- // After agent and camera moved, figure out if we need to
- // deselect objects.
- LLSelectMgr::getInstance()->deselectAllIfTooFar();
-
- }
-
- {
- // Handle pending gesture processing
- static LLFastTimer::DeclareTimer ftm("Agent Position");
- LLFastTimer t(ftm);
- LLGestureMgr::instance().update();
-
- gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY);
- }
-
- {
- LLFastTimer t(FTM_OBJECTLIST_UPDATE);
-
- if (!(logoutRequestSent() && hasSavedFinalSnapshot()))
- {
- gObjectList.update(gAgent, *LLWorld::getInstance());
- }
- }
-
- //////////////////////////////////////
- //
- // Deletes objects...
- // Has to be done after doing idleUpdates (which can kill objects)
- //
-
- {
- LLFastTimer t(FTM_CLEANUP);
- gObjectList.cleanDeadObjects();
- LLDrawable::cleanupDeadDrawables();
- }
-
- //
- // After this point, in theory we should never see a dead object
- // in the various object/drawable lists.
- //
-
- //////////////////////////////////////
- //
- // Update/send HUD effects
- //
- // At this point, HUD effects may clean up some references to
- // dead objects.
- //
-
- {
- static LLFastTimer::DeclareTimer ftm("HUD Effects");
- LLFastTimer t(ftm);
- LLSelectMgr::getInstance()->updateEffects();
- LLHUDManager::getInstance()->cleanupEffects();
- LLHUDManager::getInstance()->sendEffects();
- }
-
- ////////////////////////////////////////
- //
- // Unpack layer data that we've received
- //
-
- {
- LLFastTimer t(FTM_NETWORK);
- gVLManager.unpackData();
- }
-
- /////////////////////////
- //
- // Update surfaces, and surface textures as well.
- //
-
- LLWorld::getInstance()->updateVisibilities();
- {
- const F32 max_region_update_time = .001f; // 1ms
- LLFastTimer t(FTM_REGION_UPDATE);
- LLWorld::getInstance()->updateRegions(max_region_update_time);
- }
-
- /////////////////////////
- //
- // Update weather effects
- //
- if (!gNoRender)
- {
- LLWorld::getInstance()->updateClouds(gFrameDTClamped);
- gSky.propagateHeavenlyBodies(gFrameDTClamped); // moves sun, moon, and planets
-
- // Update wind vector
- LLVector3 wind_position_region;
- static LLVector3 average_wind;
-
- LLViewerRegion *regionp;
- regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position
- if (regionp)
- {
- gWindVec = regionp->mWind.getVelocity(wind_position_region);
-
- // Compute average wind and use to drive motion of water
-
- average_wind = regionp->mWind.getAverage();
- F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region);
-
- gSky.setCloudDensityAtAgent(cloud_density);
- gSky.setWind(average_wind);
- //LLVOWater::setWind(average_wind);
- }
- else
- {
- gWindVec.setVec(0.0f, 0.0f, 0.0f);
- }
- }
-
- //////////////////////////////////////
- //
- // Sort and cull in the new renderer are moved to pipeline.cpp
- // Here, particles are updated and drawables are moved.
- //
-
- if (!gNoRender)
- {
- LLFastTimer t(FTM_WORLD_UPDATE);
- gPipeline.updateMove();
-
- LLWorld::getInstance()->updateParticles();
- }
-
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- LLViewerJoystick::getInstance()->moveFlycam();
- }
- else
- {
- if (LLToolMgr::getInstance()->inBuildMode())
- {
- LLViewerJoystick::getInstance()->moveObjects();
- }
-
- gAgentCamera.updateCamera();
- }
-
- // update media focus
- LLViewerMediaFocus::getInstance()->update();
-
- // objects and camera should be in sync, do LOD calculations now
- {
- LLFastTimer t(FTM_LOD_UPDATE);
- gObjectList.updateApparentAngles(gAgent);
- }
-
- {
- LLFastTimer t(FTM_AUDIO_UPDATE);
-
- if (gAudiop)
- {
- audio_update_volume(false);
- audio_update_listener();
- audio_update_wind(false);
-
- // this line actually commits the changes we've made to source positions, etc.
- const F32 max_audio_decode_time = 0.002f; // 2 ms decode time
- gAudiop->idle(max_audio_decode_time);
- }
- }
-
- // Handle shutdown process, for example,
- // wait for floaters to close, send quit message,
- // forcibly quit if it has taken too long
- if (mQuitRequested)
- {
- gGLActive = TRUE;
- idleShutdown();
- }
-}
-
-void LLAppViewer::idleShutdown()
-{
- // Wait for all modal alerts to get resolved
- if (LLModalDialog::activeCount() > 0)
- {
- return;
- }
-
- // close IM interface
- if(gIMMgr)
- {
- gIMMgr->disconnectAllSessions();
- }
-
- // Wait for all floaters to get resolved
- if (gFloaterView
- && !gFloaterView->allChildrenClosed())
- {
- return;
- }
-
- if (LLSideTray::getInstance()->notifyChildren(LLSD().with("request","wait_quit")))
- {
- return;
- }
-
-
-
- // ProductEngine: Try moving this code to where we shut down sTextureCache in cleanup()
- // *TODO: ugly
- static bool saved_teleport_history = false;
- if (!saved_teleport_history)
- {
- saved_teleport_history = true;
- LLTeleportHistory::getInstance()->dump();
- LLLocationHistory::getInstance()->save(); // *TODO: find a better place for doing this
- return;
- }
-
- static bool saved_snapshot = false;
- if (!saved_snapshot)
- {
- saved_snapshot = true;
- saveFinalSnapshot();
- return;
- }
-
- const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f;
-
- S32 pending_uploads = gAssetStorage->getNumPendingUploads();
- if (pending_uploads > 0
- && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME
- && !logoutRequestSent())
- {
- static S32 total_uploads = 0;
- // Sometimes total upload count can change during logout.
- total_uploads = llmax(total_uploads, pending_uploads);
- gViewerWindow->setShowProgress(TRUE);
- S32 finished_uploads = total_uploads - pending_uploads;
- F32 percent = 100.f * finished_uploads / total_uploads;
- gViewerWindow->setProgressPercent(percent);
- gViewerWindow->setProgressString(LLTrans::getString("SavingSettings"));
- return;
- }
-
- // All floaters are closed. Tell server we want to quit.
- if( !logoutRequestSent() )
- {
- sendLogoutRequest();
-
- // Wait for a LogoutReply message
- gViewerWindow->setShowProgress(TRUE);
- gViewerWindow->setProgressPercent(100.f);
- gViewerWindow->setProgressString(LLTrans::getString("LoggingOut"));
- return;
- }
-
- // Make sure that we quit if we haven't received a reply from the server.
- if( logoutRequestSent()
- && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime )
- {
- forceQuit();
- return;
- }
-}
-
-void LLAppViewer::sendLogoutRequest()
-{
- if(!mLogoutRequestSent)
- {
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessageFast(_PREHASH_LogoutRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gAgent.sendReliableMessage();
-
- gLogoutTimer.reset();
- gLogoutMaxTime = LOGOUT_REQUEST_TIME;
- mLogoutRequestSent = TRUE;
-
- if(LLVoiceClient::instanceExists())
- {
- LLVoiceClient::getInstance()->leaveChannel();
- }
-
- //Set internal status variables and marker files
- gLogoutInProgress = TRUE;
- mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
-
- LLAPRFile outfile ;
- outfile.open(mLogoutMarkerFileName, LL_APR_W);
- mLogoutMarkerFile = outfile.getFileHandle() ;
- if (mLogoutMarkerFile)
- {
- llinfos << "Created logout marker file " << mLogoutMarkerFileName << llendl;
- apr_file_close(mLogoutMarkerFile);
- }
- else
- {
- llwarns << "Cannot create logout marker file " << mLogoutMarkerFileName << llendl;
- }
- }
-}
-
-void LLAppViewer::idleNameCache()
-{
- // Neither old nor new name cache can function before agent has a region
- LLViewerRegion* region = gAgent.getRegion();
- if (!region) return;
-
- // deal with any queued name requests and replies.
- gCacheName->processPending();
-
- // Can't run the new cache until we have the list of capabilities
- // for the agent region, and can therefore decide whether to use
- // display names or fall back to the old name system.
- if (!region->capabilitiesReceived()) return;
-
- // Agent may have moved to a different region, so need to update cap URL
- // for name lookups. Can't do this in the cap grant code, as caps are
- // granted to neighbor regions before the main agent gets there. Can't
- // do it in the move-into-region code because cap not guaranteed to be
- // granted yet, for example on teleport.
- bool had_capability = LLAvatarNameCache::hasNameLookupURL();
- std::string name_lookup_url;
- name_lookup_url.reserve(128); // avoid a memory allocation below
- name_lookup_url = region->getCapability("GetDisplayNames");
- bool have_capability = !name_lookup_url.empty();
- if (have_capability)
- {
- // we have support for display names, use it
- U32 url_size = name_lookup_url.size();
- // capabilities require URLs with slashes before query params:
- // https://<host>:<port>/cap/<uuid>/?ids=<blah>
- // but the caps are granted like:
- // https://<host>:<port>/cap/<uuid>
- if (url_size > 0 && name_lookup_url[url_size-1] != '/')
- {
- name_lookup_url += '/';
- }
- LLAvatarNameCache::setNameLookupURL(name_lookup_url);
- }
- else
- {
- // Display names not available on this region
- LLAvatarNameCache::setNameLookupURL( std::string() );
- }
-
- // Error recovery - did we change state?
- if (had_capability != have_capability)
- {
- // name tags are persistant on screen, so make sure they refresh
- LLVOAvatar::invalidateNameTags();
- }
-
- LLAvatarNameCache::idle();
-}
-
-//
-// Handle messages, and all message related stuff
-//
-
-#define TIME_THROTTLE_MESSAGES
-
-#ifdef TIME_THROTTLE_MESSAGES
-#define CHECK_MESSAGES_DEFAULT_MAX_TIME .020f // 50 ms = 50 fps (just for messages!)
-static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
-#endif
-
-static LLFastTimer::DeclareTimer FTM_IDLE_NETWORK("Idle Network");
-
-void LLAppViewer::idleNetwork()
-{
- LLMemType mt_in(LLMemType::MTYPE_IDLE_NETWORK);
- pingMainloopTimeout("idleNetwork");
-
- gObjectList.mNumNewObjects = 0;
- S32 total_decoded = 0;
-
- if (!gSavedSettings.getBOOL("SpeedTest"))
- {
- LLFastTimer t(FTM_IDLE_NETWORK); // decode
-
- LLTimer check_message_timer;
- // Read all available packets from network
- const S64 frame_count = gFrameCount; // U32->S64
- F32 total_time = 0.0f;
-
- while (gMessageSystem->checkAllMessages(frame_count, gServicePump))
- {
- if (gDoDisconnect)
- {
- // We're disconnecting, don't process any more messages from the server
- // We're usually disconnecting due to either network corruption or a
- // server going down, so this is OK.
- break;
- }
-
- total_decoded++;
- gPacketsIn++;
-
- if (total_decoded > MESSAGE_MAX_PER_FRAME)
- {
- break;
- }
-
-#ifdef TIME_THROTTLE_MESSAGES
- // Prevent slow packets from completely destroying the frame rate.
- // This usually happens due to clumps of avatars taking huge amount
- // of network processing time (which needs to be fixed, but this is
- // a good limit anyway).
- total_time = check_message_timer.getElapsedTimeF32();
- if (total_time >= CheckMessagesMaxTime)
- break;
-#endif
- }
-
- // Handle per-frame message system processing.
- gMessageSystem->processAcks();
-
-#ifdef TIME_THROTTLE_MESSAGES
- if (total_time >= CheckMessagesMaxTime)
- {
- // Increase CheckMessagesMaxTime so that we will eventually catch up
- CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames
- }
- else
- {
- // Reset CheckMessagesMaxTime to default value
- CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
- }
-#endif
-
-
-
- // we want to clear the control after sending out all necessary agent updates
- gAgent.resetControlFlags();
-
- // Decode enqueued messages...
- S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded;
-
- if( remaining_possible_decodes <= 0 )
- {
- llinfos << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << llendl;
- }
-
- if (gPrintMessagesThisFrame)
- {
- llinfos << "Decoded " << total_decoded << " msgs this frame!" << llendl;
- gPrintMessagesThisFrame = FALSE;
- }
- }
- LLViewerStats::getInstance()->mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects);
-
- // Retransmit unacknowledged packets.
- gXferManager->retransmitUnackedPackets();
- gAssetStorage->checkForTimeouts();
- gViewerThrottle.updateDynamicThrottle();
-
- // Check that the circuit between the viewer and the agent's current
- // region is still alive
- LLViewerRegion *agent_region = gAgent.getRegion();
- if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED))
- {
- LLUUID this_region_id = agent_region->getRegionID();
- bool this_region_alive = agent_region->isAlive();
- if ((mAgentRegionLastAlive && !this_region_alive) // newly dead
- && (mAgentRegionLastID == this_region_id)) // same region
- {
- forceDisconnect(LLTrans::getString("AgentLostConnection"));
- }
- mAgentRegionLastID = this_region_id;
- mAgentRegionLastAlive = this_region_alive;
- }
-}
-
-void LLAppViewer::disconnectViewer()
-{
- if (gDisconnected)
- {
- return;
- }
- //
- // Cleanup after quitting.
- //
- // Save snapshot for next time, if we made it through initialization
-
- llinfos << "Disconnecting viewer!" << llendl;
-
- // Dump our frame statistics
-
- // Remember if we were flying
- gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() );
-
- // Un-minimize all windows so they don't get saved minimized
- if (!gNoRender)
- {
- if (gFloaterView)
- {
- gFloaterView->restoreAll();
- }
- }
-
- if (LLSelectMgr::getInstance())
- {
- LLSelectMgr::getInstance()->deselectAll();
- }
-
- // save inventory if appropriate
- gInventory.cache(gInventory.getRootFolderID(), gAgent.getID());
- if (gInventory.getLibraryRootFolderID().notNull()
- && gInventory.getLibraryOwnerID().notNull())
- {
- gInventory.cache(
- gInventory.getLibraryRootFolderID(),
- gInventory.getLibraryOwnerID());
- }
-
- saveNameCache();
-
- // close inventory interface, close all windows
- LLFloaterInventory::cleanup();
-
- gAgentWearables.cleanup();
- gAgentCamera.cleanup();
- // Also writes cached agent settings to gSavedSettings
- gAgent.cleanup();
-
- // This is where we used to call gObjectList.destroy() and then delete gWorldp.
- // Now we just ask the LLWorld singleton to cleanly shut down.
- if(LLWorld::instanceExists())
- {
- LLWorld::getInstance()->destroyClass();
- }
-
- // call all self-registered classes
- LLDestroyClassList::instance().fireCallbacks();
-
- cleanup_xfer_manager();
- gDisconnected = TRUE;
-
- // Pass the connection state to LLUrlEntryParcel not to attempt
- // parcel info requests while disconnected.
- LLUrlEntryParcel::setDisconnected(gDisconnected);
-}
-
-void LLAppViewer::forceErrorLLError()
-{
- llerrs << "This is an llerror" << llendl;
-}
-
-void LLAppViewer::forceErrorBreakpoint()
-{
-#ifdef LL_WINDOWS
- DebugBreak();
-#endif
- return;
-}
-
-void LLAppViewer::forceErrorBadMemoryAccess()
-{
- S32* crash = NULL;
- *crash = 0xDEADBEEF;
- return;
-}
-
-void LLAppViewer::forceErrorInfiniteLoop()
-{
- while(true)
- {
- ;
- }
- return;
-}
-
-void LLAppViewer::forceErrorSoftwareException()
-{
- // *FIX: Any way to insure it won't be handled?
- throw;
-}
-
-void LLAppViewer::forceErrorDriverCrash()
-{
- glDeleteTextures(1, NULL);
-}
-
-void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs)
-{
- if(!mMainloopTimeout)
- {
- mMainloopTimeout = new LLWatchdogTimeout();
- resumeMainloopTimeout(state, secs);
- }
-}
-
-void LLAppViewer::destroyMainloopTimeout()
-{
- if(mMainloopTimeout)
- {
- delete mMainloopTimeout;
- mMainloopTimeout = NULL;
- }
-}
-
-void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs)
-{
- if(mMainloopTimeout)
- {
- if(secs < 0.0f)
- {
- secs = gSavedSettings.getF32("MainloopTimeoutDefault");
- }
-
- mMainloopTimeout->setTimeout(secs);
- mMainloopTimeout->start(state);
- }
-}
-
-void LLAppViewer::pauseMainloopTimeout()
-{
- if(mMainloopTimeout)
- {
- mMainloopTimeout->stop();
- }
-}
-
-void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs)
-{
-// if(!restoreErrorTrap())
-// {
-// llwarns << "!!!!!!!!!!!!! Its an error trap!!!!" << state << llendl;
-// }
-
- if(mMainloopTimeout)
- {
- if(secs < 0.0f)
- {
- secs = gSavedSettings.getF32("MainloopTimeoutDefault");
- }
-
- mMainloopTimeout->setTimeout(secs);
- mMainloopTimeout->ping(state);
- }
-}
-
-void LLAppViewer::handleLoginComplete()
-{
- gLoggedInTime.start();
- initMainloopTimeout("Mainloop Init");
-
- // Store some data to DebugInfo in case of a freeze.
- gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
-
- gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
- gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
- gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
- gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
-
- LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
- if ( parcel && parcel->getMusicURL()[0])
- {
- gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL();
- }
- if ( parcel && parcel->getMediaURL()[0])
- {
- gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL();
- }
-
- gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile");
- gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
- gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();
- gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath();
-
- if(gAgent.getRegion())
- {
- gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName();
- gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName();
- }
-
- if(LLAppViewer::instance()->mMainloopTimeout)
- {
- gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
- }
-
- mOnLoginCompleted();
-
- writeDebugInfo();
-}
-
-// *TODO - generalize this and move DSO wrangling to a helper class -brad
-void LLAppViewer::loadEventHostModule(S32 listen_port)
-{
- std::string dso_name =
-#if LL_WINDOWS
- "lleventhost.dll";
-#elif LL_DARWIN
- "liblleventhost.dylib";
-#else
- "liblleventhost.so";
-#endif
-
- std::string dso_path = gDirUtilp->findFile(dso_name,
- gDirUtilp->getAppRODataDir(),
- gDirUtilp->getExecutableDir());
-
- if(dso_path == "")
- {
- llerrs << "QAModeEventHost requested but module \"" << dso_name << "\" not found!" << llendl;
- return;
- }
-
- LL_INFOS("eventhost") << "Found lleventhost at '" << dso_path << "'" << LL_ENDL;
-#if ! defined(LL_WINDOWS)
- {
- std::string outfile("/tmp/lleventhost.file.out");
- std::string command("file '" + dso_path + "' > '" + outfile + "' 2>&1");
- int rc = system(command.c_str());
- if (rc != 0)
- {
- LL_WARNS("eventhost") << command << " ==> " << rc << ':' << LL_ENDL;
- }
- else
- {
- LL_INFOS("eventhost") << command << ':' << LL_ENDL;
- }
- {
- std::ifstream reader(outfile.c_str());
- std::string line;
- while (std::getline(reader, line))
- {
- size_t len = line.length();
- if (len && line[len-1] == '\n')
- line.erase(len-1);
- LL_INFOS("eventhost") << line << LL_ENDL;
- }
- }
- remove(outfile.c_str());
- }
-#endif // LL_WINDOWS
-
- apr_dso_handle_t * eventhost_dso_handle = NULL;
- apr_pool_t * eventhost_dso_memory_pool = NULL;
-
- //attempt to load the shared library
- apr_pool_create(&eventhost_dso_memory_pool, NULL);
- apr_status_t rv = apr_dso_load(&eventhost_dso_handle,
- dso_path.c_str(),
- eventhost_dso_memory_pool);
- llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));
- llassert_always(eventhost_dso_handle != NULL);
-
- int (*ll_plugin_start_func)(LLSD const &) = NULL;
- rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_start_func, eventhost_dso_handle, "ll_plugin_start");
-
- llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));
- llassert_always(ll_plugin_start_func != NULL);
-
- LLSD args;
- args["listen_port"] = listen_port;
-
- int status = ll_plugin_start_func(args);
-
- if(status != 0)
- {
- llerrs << "problem loading eventhost plugin, status: " << status << llendl;
- }
-
- mPlugins.insert(eventhost_dso_handle);
-}
-
-void LLAppViewer::launchUpdater()
-{
- LLSD query_map = LLSD::emptyMap();
- // *TODO place os string in a global constant
-#if LL_WINDOWS
- query_map["os"] = "win";
-#elif LL_DARWIN
- query_map["os"] = "mac";
-#elif LL_LINUX
- query_map["os"] = "lnx";
-#elif LL_SOLARIS
- query_map["os"] = "sol";
-#endif
- // *TODO change userserver to be grid on both viewer and sim, since
- // userserver no longer exists.
- query_map["userserver"] = LLGridManager::getInstance()->getGridLabel();
- query_map["channel"] = LLVersionInfo::getChannel();
- // *TODO constantize this guy
- // *NOTE: This URL is also used in win_setup/lldownloader.cpp
- LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map);
-
- if(LLAppViewer::sUpdaterInfo)
- {
- delete LLAppViewer::sUpdaterInfo;
- }
- LLAppViewer::sUpdaterInfo = new LLAppViewer::LLUpdaterInfo() ;
-
- // if a sim name was passed in via command line parameter (typically through a SLURL)
- if ( LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION )
- {
- // record the location to start at next time
- gSavedSettings.setString( "NextLoginLocation", LLStartUp::getStartSLURL().getSLURLString());
- };
-
-#if LL_WINDOWS
- LLAppViewer::sUpdaterInfo->mUpdateExePath = gDirUtilp->getTempFilename();
- if (LLAppViewer::sUpdaterInfo->mUpdateExePath.empty())
- {
- delete LLAppViewer::sUpdaterInfo ;
- LLAppViewer::sUpdaterInfo = NULL ;
-
- // We're hosed, bail
- LL_WARNS("AppInit") << "LLDir::getTempFilename() failed" << LL_ENDL;
- return;
- }
-
- LLAppViewer::sUpdaterInfo->mUpdateExePath += ".exe";
-
- std::string updater_source = gDirUtilp->getAppRODataDir();
- updater_source += gDirUtilp->getDirDelimiter();
- updater_source += "updater.exe";
-
- LL_DEBUGS("AppInit") << "Calling CopyFile source: " << updater_source
- << " dest: " << LLAppViewer::sUpdaterInfo->mUpdateExePath
- << LL_ENDL;
-
-
- if (!CopyFileA(updater_source.c_str(), LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), FALSE))
- {
- delete LLAppViewer::sUpdaterInfo ;
- LLAppViewer::sUpdaterInfo = NULL ;
-
- LL_WARNS("AppInit") << "Unable to copy the updater!" << LL_ENDL;
-
- return;
- }
-
- LLAppViewer::sUpdaterInfo->mParams << "-url \"" << update_url.asString() << "\"";
-
- LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << " " << LLAppViewer::sUpdaterInfo->mParams.str() << LL_ENDL;
-
- //Explicitly remove the marker file, otherwise we pass the lock onto the child process and things get weird.
- LLAppViewer::instance()->removeMarkerFile(); // In case updater fails
-
- // *NOTE:Mani The updater is spawned as the last thing before the WinMain exit.
- // see LLAppViewerWin32.cpp
-
-#elif LL_DARWIN
- LLAppViewer::sUpdaterInfo->mUpdateExePath = "'";
- LLAppViewer::sUpdaterInfo->mUpdateExePath += gDirUtilp->getAppRODataDir();
- LLAppViewer::sUpdaterInfo->mUpdateExePath += "/mac-updater.app/Contents/MacOS/mac-updater' -url \"";
- LLAppViewer::sUpdaterInfo->mUpdateExePath += update_url.asString();
- LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -name \"";
- LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle();
- LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -bundleid \"";
- LLAppViewer::sUpdaterInfo->mUpdateExePath += LL_VERSION_BUNDLE_ID;
- LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" &";
-
- LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
-
- // Run the auto-updater.
- system(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str()); /* Flawfinder: ignore */
-
-#elif (LL_LINUX || LL_SOLARIS) && LL_GTK
- // we tell the updater where to find the xml containing string
- // translations which it can use for its own UI
- std::string xml_strings_file = "strings.xml";
- std::vector<std::string> xui_path_vec = LLUI::getXUIPaths();
- std::string xml_search_paths;
- std::vector<std::string>::const_iterator iter;
- // build comma-delimited list of xml paths to pass to updater
- for (iter = xui_path_vec.begin(); iter != xui_path_vec.end(); )
- {
- std::string this_skin_dir = gDirUtilp->getDefaultSkinDir()
- + gDirUtilp->getDirDelimiter()
- + (*iter);
- llinfos << "Got a XUI path: " << this_skin_dir << llendl;
- xml_search_paths.append(this_skin_dir);
- ++iter;
- if (iter != xui_path_vec.end())
- xml_search_paths.append(","); // comma-delimit
- }
- // build the overall command-line to run the updater correctly
- LLAppViewer::sUpdaterInfo->mUpdateExePath =
- gDirUtilp->getExecutableDir() + "/" + "linux-updater.bin" +
- " --url \"" + update_url.asString() + "\"" +
- " --name \"" + LLAppViewer::instance()->getSecondLifeTitle() + "\"" +
- " --dest \"" + gDirUtilp->getAppRODataDir() + "\"" +
- " --stringsdir \"" + xml_search_paths + "\"" +
- " --stringsfile \"" + xml_strings_file + "\"";
-
- LL_INFOS("AppInit") << "Calling updater: "
- << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
-
- // *TODO: we could use the gdk equivalent to ensure the updater
- // gets started on the same screen.
- GError *error = NULL;
- if (!g_spawn_command_line_async(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), &error))
- {
- llerrs << "Failed to launch updater: "
- << error->message
- << llendl;
- }
- if (error) {
- g_error_free(error);
- }
-#else
- OSMessageBox(LLTrans::getString("MBNoAutoUpdate"), LLStringUtil::null, OSMB_OK);
-#endif
-
- // *REMOVE:Mani - Saving for reference...
- // LLAppViewer::instance()->forceQuit();
-}
-
-
-//virtual
-void LLAppViewer::setMasterSystemAudioMute(bool mute)
-{
- gSavedSettings.setBOOL("MuteAudio", mute);
-}
-
-//virtual
-bool LLAppViewer::getMasterSystemAudioMute()
-{
- return gSavedSettings.getBOOL("MuteAudio");
-}
-
-//----------------------------------------------------------------------------
-// Metrics-related methods (static and otherwise)
-//----------------------------------------------------------------------------
-
-/**
- * LLViewerAssetStats collects data on a per-region (as defined by the agent's
- * location) so we need to tell it about region changes which become a kind of
- * hidden variable/global state in the collectors. For collectors not running
- * on the main thread, we need to send a message to move the data over safely
- * and cheaply (amortized over a run).
- */
-void LLAppViewer::metricsUpdateRegion(U64 region_handle)
-{
- if (0 != region_handle)
- {
- LLViewerAssetStatsFF::set_region_main(region_handle);
- if (LLAppViewer::sTextureFetch)
- {
- // Send a region update message into 'thread1' to get the new region.
- LLAppViewer::sTextureFetch->commandSetRegion(region_handle);
- }
- else
- {
- // No 'thread1', a.k.a. TextureFetch, so update directly
- LLViewerAssetStatsFF::set_region_thread1(region_handle);
- }
- }
-}
-
-
-/**
- * Attempts to start a multi-threaded metrics report to be sent back to
- * the grid for consumption.
- */
-void LLAppViewer::metricsSend(bool enable_reporting)
-{
- if (! gViewerAssetStatsMain)
- return;
-
- if (LLAppViewer::sTextureFetch)
- {
- LLViewerRegion * regionp = gAgent.getRegion();
-
- if (enable_reporting && regionp)
- {
- std::string caps_url = regionp->getCapability("ViewerMetrics");
-
- // Make a copy of the main stats to send into another thread.
- // Receiving thread takes ownership.
- LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStatsMain));
-
- // Send a report request into 'thread1' to get the rest of the data
- // and provide some additional parameters while here.
- LLAppViewer::sTextureFetch->commandSendMetrics(caps_url,
- gAgentSessionID,
- gAgentID,
- main_stats);
- main_stats = 0; // Ownership transferred
- }
- else
- {
- LLAppViewer::sTextureFetch->commandDataBreak();
- }
- }
-
- // Reset even if we can't report. Rather than gather up a huge chunk of
- // data, we'll keep to our sampling interval and retain the data
- // resolution in time.
- gViewerAssetStatsMain->reset();
-}
-
+ /**
+ * @file llappviewer.cpp
+ * @brief The LLAppViewer class definitions
+ *
+ * $LicenseInfo:firstyear=2007&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llappviewer.h"
+
+// Viewer includes
+#include "llversioninfo.h"
+#include "llversionviewer.h"
+#include "llfeaturemanager.h"
+#include "lluictrlfactory.h"
+#include "lltexteditor.h"
+#include "llerrorcontrol.h"
+#include "lleventtimer.h"
+#include "llviewertexturelist.h"
+#include "llgroupmgr.h"
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llagentlanguage.h"
+#include "llagentwearables.h"
+#include "llwindow.h"
+#include "llviewerstats.h"
+#include "llviewerstatsrecorder.h"
+#include "llmd5.h"
+#include "llpumpio.h"
+#include "llmimetypes.h"
+#include "llslurl.h"
+#include "llstartup.h"
+#include "llfocusmgr.h"
+#include "llviewerjoystick.h"
+#include "llallocator.h"
+#include "llares.h"
+#include "llcurl.h"
+#include "lltexturestats.h"
+#include "lltexturestats.h"
+#include "llviewerwindow.h"
+#include "llviewerdisplay.h"
+#include "llviewermedia.h"
+#include "llviewerparcelmedia.h"
+#include "llviewermediafocus.h"
+#include "llviewermessage.h"
+#include "llviewerobjectlist.h"
+#include "llworldmap.h"
+#include "llmutelist.h"
+#include "llviewerhelp.h"
+#include "lluicolortable.h"
+#include "llurldispatcher.h"
+#include "llurlhistory.h"
+//#include "llfirstuse.h"
+#include "llrender.h"
+#include "llteleporthistory.h"
+#include "lllocationhistory.h"
+#include "llfasttimerview.h"
+#include "llvoicechannel.h"
+#include "llvoavatarself.h"
+#include "llsidetray.h"
+#include "llfeaturemanager.h"
+#include "llurlmatch.h"
+#include "lltextutil.h"
+#include "lllogininstance.h"
+#include "llprogressview.h"
+
+#include "llweb.h"
+#include "llsecondlifeurls.h"
+#include "llupdaterservice.h"
+
+// Linden library includes
+#include "llavatarnamecache.h"
+#include "llimagej2c.h"
+#include "llmemory.h"
+#include "llprimitive.h"
+#include "llurlaction.h"
+#include "llurlentry.h"
+#include "llvfile.h"
+#include "llvfsthread.h"
+#include "llvolumemgr.h"
+#include "llxfermanager.h"
+
+#include "llnotificationmanager.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+
+// Third party library includes
+#include <boost/bind.hpp>
+
+
+#if LL_WINDOWS
+# include <share.h> // For _SH_DENYWR in initMarkerFile
+#else
+# include <sys/file.h> // For initMarkerFile support
+#endif
+
+#include "llapr.h"
+#include "apr_dso.h"
+#include <boost/lexical_cast.hpp>
+
+#include "llviewerkeyboard.h"
+#include "lllfsthread.h"
+#include "llworkerthread.h"
+#include "lltexturecache.h"
+#include "lltexturefetch.h"
+#include "llimageworker.h"
+#include "llevents.h"
+
+// The files below handle dependencies from cleanup.
+#include "llkeyframemotion.h"
+#include "llworldmap.h"
+#include "llhudmanager.h"
+#include "lltoolmgr.h"
+#include "llassetstorage.h"
+#include "llpolymesh.h"
+#include "llcachename.h"
+#include "llaudioengine.h"
+#include "llstreamingaudio.h"
+#include "llviewermenu.h"
+#include "llselectmgr.h"
+#include "lltrans.h"
+#include "lltransutil.h"
+#include "lltracker.h"
+#include "llviewerparcelmgr.h"
+#include "llworldmapview.h"
+#include "llpostprocess.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+
+#include "lldebugview.h"
+#include "llconsole.h"
+#include "llcontainerview.h"
+#include "lltooltip.h"
+
+#include "llsdserialize.h"
+
+#include "llworld.h"
+#include "llhudeffecttrail.h"
+#include "llvectorperfoptions.h"
+#include "llslurl.h"
+#include "llwatchdog.h"
+
+// Included so that constants/settings might be initialized
+// in save_settings_to_globals()
+#include "llbutton.h"
+#include "llstatusbar.h"
+#include "llsurface.h"
+#include "llvosky.h"
+#include "llvotree.h"
+#include "llvoavatar.h"
+#include "llfolderview.h"
+#include "llagentpilot.h"
+#include "llvovolume.h"
+#include "llflexibleobject.h"
+#include "llvosurfacepatch.h"
+#include "llviewerfloaterreg.h"
+#include "llcommandlineparser.h"
+#include "llfloatermemleak.h"
+#include "llfloaterreg.h"
+#include "llfloatersnapshot.h"
+#include "llfloaterinventory.h"
+
+// includes for idle() idleShutdown()
+#include "llviewercontrol.h"
+#include "lleventnotifier.h"
+#include "llcallbacklist.h"
+#include "pipeline.h"
+#include "llgesturemgr.h"
+#include "llsky.h"
+#include "llvlmanager.h"
+#include "llviewercamera.h"
+#include "lldrawpoolbump.h"
+#include "llvieweraudio.h"
+#include "llimview.h"
+#include "llviewerthrottle.h"
+#include "llparcel.h"
+#include "llavatariconctrl.h"
+#include "llgroupiconctrl.h"
+#include "llviewerassetstats.h"
+
+// Include for security api initialization
+#include "llsecapi.h"
+#include "llmachineid.h"
+
+#include "llmainlooprepeater.h"
+
+// *FIX: These extern globals should be cleaned up.
+// The globals either represent state/config/resource-storage of either
+// this app, or another 'component' of the viewer. App globals should be
+// moved into the app class, where as the other globals should be
+// moved out of here.
+// If a global symbol reference seems valid, it will be included
+// via header files above.
+
+//----------------------------------------------------------------------------
+// llviewernetwork.h
+#include "llviewernetwork.h"
+// define a self-registering event API object
+#include "llappviewerlistener.h"
+
+#if (LL_LINUX || LL_SOLARIS) && LL_GTK
+#include "glib.h"
+#endif // (LL_LINUX || LL_SOLARIS) && LL_GTK
+
+#if LL_MSVC
+// disable boost::lexical_cast warning
+#pragma warning (disable:4702)
+#endif
+
+static LLAppViewerListener sAppViewerListener(LLAppViewer::instance);
+
+////// Windows-specific includes to the bottom - nasty defines in these pollute the preprocessor
+//
+//----------------------------------------------------------------------------
+// viewer.cpp - these are only used in viewer, should be easily moved.
+
+#if LL_DARWIN
+extern void init_apple_menu(const char* product);
+#endif // LL_DARWIN
+
+extern BOOL gRandomizeFramerate;
+extern BOOL gPeriodicSlowFrame;
+extern BOOL gDebugGL;
+
+////////////////////////////////////////////////////////////
+// All from the last globals push...
+const F32 DEFAULT_AFK_TIMEOUT = 5.f * 60.f; // time with no input before user flagged as Away From Keyboard
+
+F32 gSimLastTime; // Used in LLAppViewer::init and send_stats()
+F32 gSimFrames;
+
+BOOL gShowObjectUpdates = FALSE;
+BOOL gUseQuickTime = TRUE;
+
+eLastExecEvent gLastExecEvent = LAST_EXEC_NORMAL;
+
+LLSD gDebugInfo;
+
+U32 gFrameCount = 0;
+U32 gForegroundFrameCount = 0; // number of frames that app window was in foreground
+LLPumpIO* gServicePump = NULL;
+
+U64 gFrameTime = 0;
+F32 gFrameTimeSeconds = 0.f;
+F32 gFrameIntervalSeconds = 0.f;
+F32 gFPSClamped = 10.f; // Pretend we start at target rate.
+F32 gFrameDTClamped = 0.f; // Time between adjacent checks to network for packets
+U64 gStartTime = 0; // gStartTime is "private", used only to calculate gFrameTimeSeconds
+U32 gFrameStalls = 0;
+const F64 FRAME_STALL_THRESHOLD = 1.0;
+
+LLTimer gRenderStartTime;
+LLFrameTimer gForegroundTime;
+LLFrameTimer gLoggedInTime;
+LLTimer gLogoutTimer;
+static const F32 LOGOUT_REQUEST_TIME = 6.f; // this will be cut short by the LogoutReply msg.
+F32 gLogoutMaxTime = LOGOUT_REQUEST_TIME;
+
+BOOL gDisconnected = FALSE;
+
+// used to restore texture state after a mode switch
+LLFrameTimer gRestoreGLTimer;
+BOOL gRestoreGL = FALSE;
+BOOL gUseWireframe = FALSE;
+
+// VFS globals - see llappviewer.h
+LLVFS* gStaticVFS = NULL;
+
+LLMemoryInfo gSysMemory;
+U64 gMemoryAllocated = 0; // updated in display_stats() in llviewerdisplay.cpp
+
+std::string gLastVersionChannel;
+
+LLVector3 gWindVec(3.0, 3.0, 0.0);
+LLVector3 gRelativeWindVec(0.0, 0.0, 0.0);
+
+U32 gPacketsIn = 0;
+
+BOOL gPrintMessagesThisFrame = FALSE;
+
+BOOL gRandomizeFramerate = FALSE;
+BOOL gPeriodicSlowFrame = FALSE;
+
+BOOL gCrashOnStartup = FALSE;
+BOOL gLLErrorActivated = FALSE;
+BOOL gLogoutInProgress = FALSE;
+
+////////////////////////////////////////////////////////////
+// Internal globals... that should be removed.
+static std::string gArgs;
+
+const std::string MARKER_FILE_NAME("SecondLife.exec_marker");
+const std::string ERROR_MARKER_FILE_NAME("SecondLife.error_marker");
+const std::string LLERROR_MARKER_FILE_NAME("SecondLife.llerror_marker");
+const std::string LOGOUT_MARKER_FILE_NAME("SecondLife.logout_marker");
+static BOOL gDoDisconnect = FALSE;
+static std::string gLaunchFileOnQuit;
+
+// Used on Win32 for other apps to identify our window (eg, win_setup)
+const char* const VIEWER_WINDOW_CLASSNAME = "Second Life";
+
+//----------------------------------------------------------------------------
+
+// List of entries from strings.xml to always replace
+static std::set<std::string> default_trans_args;
+void init_default_trans_args()
+{
+ default_trans_args.insert("SECOND_LIFE"); // World
+ default_trans_args.insert("APP_NAME");
+ default_trans_args.insert("CAPITALIZED_APP_NAME");
+ default_trans_args.insert("SECOND_LIFE_GRID");
+ default_trans_args.insert("SUPPORT_SITE");
+}
+
+//----------------------------------------------------------------------------
+// File scope definitons
+const char *VFS_DATA_FILE_BASE = "data.db2.x.";
+const char *VFS_INDEX_FILE_BASE = "index.db2.x.";
+
+
+struct SettingsFile : public LLInitParam::Block<SettingsFile>
+{
+ Mandatory<std::string> name;
+ Optional<std::string> file_name;
+ Optional<bool> required,
+ persistent;
+ Optional<std::string> file_name_setting;
+
+ SettingsFile()
+ : name("name"),
+ file_name("file_name"),
+ required("required", false),
+ persistent("persistent", true),
+ file_name_setting("file_name_setting")
+ {}
+};
+
+struct SettingsGroup : public LLInitParam::Block<SettingsGroup>
+{
+ Mandatory<std::string> name;
+ Mandatory<S32> path_index;
+ Multiple<SettingsFile> files;
+
+ SettingsGroup()
+ : name("name"),
+ path_index("path_index"),
+ files("file")
+ {}
+};
+
+struct SettingsFiles : public LLInitParam::Block<SettingsFiles>
+{
+ Multiple<SettingsGroup> groups;
+
+ SettingsFiles()
+ : groups("group")
+ {}
+};
+
+static std::string gWindowTitle;
+
+LLAppViewer::LLUpdaterInfo *LLAppViewer::sUpdaterInfo = NULL ;
+
+//----------------------------------------------------------------------------
+// Metrics logging control constants
+//----------------------------------------------------------------------------
+static const F32 METRICS_INTERVAL_DEFAULT = 600.0;
+static const F32 METRICS_INTERVAL_QA = 30.0;
+static F32 app_metrics_interval = METRICS_INTERVAL_DEFAULT;
+static bool app_metrics_qa_mode = false;
+
+void idle_afk_check()
+{
+ // check idle timers
+ if (gSavedSettings.getS32("AFKTimeout") && (gAwayTriggerTimer.getElapsedTimeF32() > gSavedSettings.getS32("AFKTimeout")))
+ {
+ gAgent.setAFK();
+ }
+}
+
+// A callback set in LLAppViewer::init()
+static void ui_audio_callback(const LLUUID& uuid)
+{
+ if (gAudiop)
+ {
+ gAudiop->triggerSound(uuid, gAgent.getID(), 1.0f, LLAudioEngine::AUDIO_TYPE_UI);
+ }
+}
+
+bool create_text_segment_icon_from_url_match(LLUrlMatch* match,LLTextBase* base)
+{
+ if(!match || !base || base->getPlainText())
+ return false;
+
+ LLUUID match_id = match->getID();
+
+ LLIconCtrl* icon;
+
+ if(gAgent.isInGroup(match_id, TRUE))
+ {
+ LLGroupIconCtrl::Params icon_params;
+ icon_params.group_id = match_id;
+ icon_params.rect = LLRect(0, 16, 16, 0);
+ icon_params.visible = true;
+ icon = LLUICtrlFactory::instance().create<LLGroupIconCtrl>(icon_params);
+ }
+ else
+ {
+ LLAvatarIconCtrl::Params icon_params;
+ icon_params.avatar_id = match_id;
+ icon_params.rect = LLRect(0, 16, 16, 0);
+ icon_params.visible = true;
+ icon = LLUICtrlFactory::instance().create<LLAvatarIconCtrl>(icon_params);
+ }
+
+ LLInlineViewSegment::Params params;
+ params.force_newline = false;
+ params.view = icon;
+ params.left_pad = 4;
+ params.right_pad = 4;
+ params.top_pad = -2;
+ params.bottom_pad = 2;
+
+ base->appendWidget(params," ",false);
+
+ return true;
+}
+
+void request_initial_instant_messages()
+{
+ static BOOL requested = FALSE;
+ if (!requested
+ && gMessageSystem
+ && LLMuteList::getInstance()->isLoaded()
+ && isAgentAvatarValid())
+ {
+ // Auto-accepted inventory items may require the avatar object
+ // to build a correct name. Likewise, inventory offers from
+ // muted avatars require the mute list to properly mute.
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_RetrieveInstantMessages);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ gAgent.sendReliableMessage();
+ requested = TRUE;
+ }
+}
+
+// A settings system callback for CrashSubmitBehavior
+bool handleCrashSubmitBehaviorChanged(const LLSD& newvalue)
+{
+ S32 cb = newvalue.asInteger();
+ const S32 NEVER_SUBMIT_REPORT = 2;
+ if(cb == NEVER_SUBMIT_REPORT)
+ {
+ LLAppViewer::instance()->destroyMainloopTimeout();
+ }
+ return true;
+}
+
+// Use these strictly for things that are constructed at startup,
+// or for things that are performance critical. JC
+static void settings_to_globals()
+{
+ LLBUTTON_H_PAD = gSavedSettings.getS32("ButtonHPad");
+ BTN_HEIGHT_SMALL = gSavedSettings.getS32("ButtonHeightSmall");
+ BTN_HEIGHT = gSavedSettings.getS32("ButtonHeight");
+
+ MENU_BAR_HEIGHT = gSavedSettings.getS32("MenuBarHeight");
+ MENU_BAR_WIDTH = gSavedSettings.getS32("MenuBarWidth");
+
+ LLSurface::setTextureSize(gSavedSettings.getU32("RegionTextureSize"));
+
+ LLImageGL::sGlobalUseAnisotropic = gSavedSettings.getBOOL("RenderAnisotropic");
+ LLVOVolume::sLODFactor = gSavedSettings.getF32("RenderVolumeLODFactor");
+ LLVOVolume::sDistanceFactor = 1.f-LLVOVolume::sLODFactor * 0.1f;
+ LLVolumeImplFlexible::sUpdateFactor = gSavedSettings.getF32("RenderFlexTimeFactor");
+ LLVOTree::sTreeFactor = gSavedSettings.getF32("RenderTreeLODFactor");
+ LLVOAvatar::sLODFactor = gSavedSettings.getF32("RenderAvatarLODFactor");
+ LLVOAvatar::sMaxVisible = (U32)gSavedSettings.getS32("RenderAvatarMaxVisible");
+ LLVOAvatar::sVisibleInFirstPerson = gSavedSettings.getBOOL("FirstPersonAvatarVisible");
+ // clamp auto-open time to some minimum usable value
+ LLFolderView::sAutoOpenTime = llmax(0.25f, gSavedSettings.getF32("FolderAutoOpenDelay"));
+ LLSelectMgr::sRectSelectInclusive = gSavedSettings.getBOOL("RectangleSelectInclusive");
+ LLSelectMgr::sRenderHiddenSelections = gSavedSettings.getBOOL("RenderHiddenSelections");
+ LLSelectMgr::sRenderLightRadius = gSavedSettings.getBOOL("RenderLightRadius");
+
+ gAgentPilot.mNumRuns = gSavedSettings.getS32("StatsNumRuns");
+ gAgentPilot.mQuitAfterRuns = gSavedSettings.getBOOL("StatsQuitAfterRuns");
+ gAgent.setHideGroupTitle(gSavedSettings.getBOOL("RenderHideGroupTitle"));
+
+ gDebugWindowProc = gSavedSettings.getBOOL("DebugWindowProc");
+ gShowObjectUpdates = gSavedSettings.getBOOL("ShowObjectUpdates");
+ LLWorldMapView::sMapScale = gSavedSettings.getF32("MapScale");
+}
+
+static void settings_modify()
+{
+ LLRenderTarget::sUseFBO = gSavedSettings.getBOOL("RenderUseFBO");
+ LLVOAvatar::sUseImpostors = gSavedSettings.getBOOL("RenderUseImpostors");
+ LLVOSurfacePatch::sLODFactor = gSavedSettings.getF32("RenderTerrainLODFactor");
+ LLVOSurfacePatch::sLODFactor *= LLVOSurfacePatch::sLODFactor; //square lod factor to get exponential range of [1,4]
+ gDebugGL = gSavedSettings.getBOOL("RenderDebugGL") || gDebugSession;
+ gDebugPipeline = gSavedSettings.getBOOL("RenderDebugPipeline");
+ gAuditTexture = gSavedSettings.getBOOL("AuditTexture");
+#if LL_VECTORIZE
+ if (gSysCPU.hasAltivec())
+ {
+ gSavedSettings.setBOOL("VectorizeEnable", TRUE );
+ gSavedSettings.setU32("VectorizeProcessor", 0 );
+ }
+ else
+ if (gSysCPU.hasSSE2())
+ {
+ gSavedSettings.setBOOL("VectorizeEnable", TRUE );
+ gSavedSettings.setU32("VectorizeProcessor", 2 );
+ }
+ else
+ if (gSysCPU.hasSSE())
+ {
+ gSavedSettings.setBOOL("VectorizeEnable", TRUE );
+ gSavedSettings.setU32("VectorizeProcessor", 1 );
+ }
+ else
+ {
+ // Don't bother testing or running if CPU doesn't support it. JC
+ gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
+ gSavedSettings.setBOOL("VectorizeEnable", FALSE );
+ gSavedSettings.setU32("VectorizeProcessor", 0 );
+ gSavedSettings.setBOOL("VectorizeSkin", FALSE);
+ }
+#else
+ // This build target doesn't support SSE, don't test/run.
+ gSavedSettings.setBOOL("VectorizePerfTest", FALSE );
+ gSavedSettings.setBOOL("VectorizeEnable", FALSE );
+ gSavedSettings.setU32("VectorizeProcessor", 0 );
+ gSavedSettings.setBOOL("VectorizeSkin", FALSE);
+
+ // disable fullscreen mode, unsupported
+ gSavedSettings.setBOOL("WindowFullScreen", FALSE);
+#endif
+}
+
+class LLFastTimerLogThread : public LLThread
+{
+public:
+ std::string mFile;
+
+ LLFastTimerLogThread(std::string& test_name) : LLThread("fast timer log")
+ {
+ std::string file_name = test_name + std::string(".slp");
+ mFile = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, file_name);
+ }
+
+ void run()
+ {
+ std::ofstream os(mFile.c_str());
+
+ while (!LLAppViewer::instance()->isQuitting())
+ {
+ LLFastTimer::writeLog(os);
+ os.flush();
+ ms_sleep(32);
+ }
+
+ os.close();
+ }
+
+};
+
+//virtual
+bool LLAppViewer::initSLURLHandler()
+{
+ // does nothing unless subclassed
+ return false;
+}
+
+//virtual
+bool LLAppViewer::sendURLToOtherInstance(const std::string& url)
+{
+ // does nothing unless subclassed
+ return false;
+}
+
+//----------------------------------------------------------------------------
+// LLAppViewer definition
+
+// Static members.
+// The single viewer app.
+LLAppViewer* LLAppViewer::sInstance = NULL;
+
+const std::string LLAppViewer::sGlobalSettingsName = "Global";
+
+LLTextureCache* LLAppViewer::sTextureCache = NULL;
+LLImageDecodeThread* LLAppViewer::sImageDecodeThread = NULL;
+LLTextureFetch* LLAppViewer::sTextureFetch = NULL;
+
+LLAppViewer::LLAppViewer() :
+ mMarkerFile(),
+ mLogoutMarkerFile(NULL),
+ mReportedCrash(false),
+ mNumSessions(0),
+ mPurgeCache(false),
+ mPurgeOnExit(false),
+ mSecondInstance(false),
+ mSavedFinalSnapshot(false),
+ mForceGraphicsDetail(false),
+ mQuitRequested(false),
+ mLogoutRequestSent(false),
+ mYieldTime(-1),
+ mMainloopTimeout(NULL),
+ mAgentRegionLastAlive(false),
+ mRandomizeFramerate(LLCachedControl<bool>(gSavedSettings,"Randomize Framerate", FALSE)),
+ mPeriodicSlowFrame(LLCachedControl<bool>(gSavedSettings,"Periodic Slow Frame", FALSE)),
+ mFastTimerLogThread(NULL),
+ mUpdater(new LLUpdaterService()),
+ mSettingsLocationList(NULL)
+{
+ if(NULL != sInstance)
+ {
+ llerrs << "Oh no! An instance of LLAppViewer already exists! LLAppViewer is sort of like a singleton." << llendl;
+ }
+
+ setupErrorHandling();
+ sInstance = this;
+ gLoggedInTime.stop();
+
+ LLLoginInstance::instance().setUpdaterService(mUpdater.get());
+}
+
+LLAppViewer::~LLAppViewer()
+{
+ delete mSettingsLocationList;
+
+ LLLoginInstance::instance().setUpdaterService(0);
+
+ destroyMainloopTimeout();
+
+ // If we got to this destructor somehow, the app didn't hang.
+ removeMarkerFile();
+}
+
+bool LLAppViewer::init()
+{
+ //
+ // Start of the application
+ //
+ // IMPORTANT! Do NOT put anything that will write
+ // into the log files during normal startup until AFTER
+ // we run the "program crashed last time" error handler below.
+ //
+ LLFastTimer::reset();
+
+ // Need to do this initialization before we do anything else, since anything
+ // that touches files should really go through the lldir API
+ gDirUtilp->initAppDirs("SecondLife");
+ // set skin search path to default, will be overridden later
+ // this allows simple skinned file lookups to work
+ gDirUtilp->setSkinFolder("default");
+
+ initLogging();
+
+ //
+ // OK to write stuff to logs now, we've now crash reported if necessary
+ //
+
+ init_default_trans_args();
+
+ if (!initConfiguration())
+ return false;
+
+ // write Google Breakpad minidump files to our log directory
+ std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
+ logdir += gDirUtilp->getDirDelimiter();
+ setMiniDumpDir(logdir);
+
+ // Although initLogging() is the right place to mess with
+ // setFatalFunction(), we can't query gSavedSettings until after
+ // initConfiguration().
+ S32 rc(gSavedSettings.getS32("QAModeTermCode"));
+ if (rc >= 0)
+ {
+ // QAModeTermCode set, terminate with that rc on LL_ERRS. Use _exit()
+ // rather than exit() because normal cleanup depends too much on
+ // successful startup!
+ LLError::setFatalFunction(boost::bind(_exit, rc));
+ }
+
+ mAlloc.setProfilingEnabled(gSavedSettings.getBOOL("MemProfiling"));
+
+#if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::initClass();
+#endif
+
+ // *NOTE:Mani - LLCurl::initClass is not thread safe.
+ // Called before threads are created.
+ LLCurl::initClass();
+ LLMachineID::init();
+
+ {
+ // Viewer metrics initialization
+ static LLCachedControl<bool> metrics_submode(gSavedSettings,
+ "QAModeMetrics",
+ false,
+ "Enables QA features (logging, faster cycling) for metrics collector");
+
+ if (metrics_submode)
+ {
+ app_metrics_qa_mode = true;
+ app_metrics_interval = METRICS_INTERVAL_QA;
+ }
+ LLViewerAssetStatsFF::init();
+ }
+
+ initThreads();
+ writeSystemInfo();
+
+ // Initialize updater service (now that we have an io pump)
+ initUpdater();
+ if(isQuitting())
+ {
+ // Early out here because updater set the quitting flag.
+ return true;
+ }
+
+ //////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////
+ //////////////////////////////////////////////////////////////////////////////
+ // *FIX: The following code isn't grouped into functions yet.
+
+ // Statistics / debug timer initialization
+ init_statistics();
+
+ //
+ // Various introspection concerning the libs we're using - particularly
+ // the libs involved in getting to a full login screen.
+ //
+ LL_INFOS("InitInfo") << "J2C Engine is: " << LLImageJ2C::getEngineInfo() << LL_ENDL;
+ LL_INFOS("InitInfo") << "libcurl version is: " << LLCurl::getVersionString() << LL_ENDL;
+
+ // Get the single value from the crash settings file, if it exists
+ std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
+ gCrashSettings.loadFromFile(crash_settings_filename);
+ if(gSavedSettings.getBOOL("IgnoreAllNotifications"))
+ {
+ gCrashSettings.setS32(CRASH_BEHAVIOR_SETTING, CRASH_BEHAVIOR_ALWAYS_SEND);
+ gCrashSettings.saveToFile(crash_settings_filename, FALSE);
+ }
+
+ /////////////////////////////////////////////////
+ // OS-specific login dialogs
+ /////////////////////////////////////////////////
+
+ //test_cached_control();
+
+ // track number of times that app has run
+ mNumSessions = gSavedSettings.getS32("NumSessions");
+ mNumSessions++;
+ gSavedSettings.setS32("NumSessions", mNumSessions);
+
+ if (gSavedSettings.getBOOL("VerboseLogs"))
+ {
+ LLError::setPrintLocation(true);
+ }
+
+ // Widget construction depends on LLUI being initialized
+ LLUI::settings_map_t settings_map;
+ settings_map["config"] = &gSavedSettings;
+ settings_map["ignores"] = &gWarningSettings;
+ settings_map["floater"] = &gSavedSettings; // *TODO: New settings file
+ settings_map["account"] = &gSavedPerAccountSettings;
+
+ LLUI::initClass(settings_map,
+ LLUIImageList::getInstance(),
+ ui_audio_callback,
+ &LLUI::sGLScaleFactor);
+
+ // Setup paths and LLTrans after LLUI::initClass has been called
+ LLUI::setupPaths();
+ LLTransUtil::parseStrings("strings.xml", default_trans_args);
+ LLTransUtil::parseLanguageStrings("language_settings.xml");
+
+ // LLKeyboard relies on LLUI to know what some accelerator keys are called.
+ LLKeyboard::setStringTranslatorFunc( LLTrans::getKeyboardString );
+
+ LLWeb::initClass(); // do this after LLUI
+
+ // Provide the text fields with callbacks for opening Urls
+ LLUrlAction::setOpenURLCallback(&LLWeb::loadURL);
+ LLUrlAction::setOpenURLInternalCallback(&LLWeb::loadURLInternal);
+ LLUrlAction::setOpenURLExternalCallback(&LLWeb::loadURLExternal);
+ LLUrlAction::setExecuteSLURLCallback(&LLURLDispatcher::dispatchFromTextEditor);
+
+ // Let code in llui access the viewer help floater
+ LLUI::sHelpImpl = LLViewerHelp::getInstance();
+
+ // Load translations for tooltips
+ LLFloater::initClass();
+
+ /////////////////////////////////////////////////
+
+ LLToolMgr::getInstance(); // Initialize tool manager if not already instantiated
+
+ LLViewerFloaterReg::registerFloaters();
+
+ /////////////////////////////////////////////////
+ //
+ // Load settings files
+ //
+ //
+ LLGroupMgr::parseRoleActions("role_actions.xml");
+
+ LLAgent::parseTeleportMessages("teleport_strings.xml");
+
+ LLViewerJointMesh::updateVectorize();
+
+ // load MIME type -> media impl mappings
+ std::string mime_types_name;
+#if LL_DARWIN
+ mime_types_name = "mime_types_mac.xml";
+#elif LL_LINUX
+ mime_types_name = "mime_types_linux.xml";
+#else
+ mime_types_name = "mime_types.xml";
+#endif
+ LLMIMETypes::parseMIMETypes( mime_types_name );
+
+ // Copy settings to globals. *TODO: Remove or move to appropriage class initializers
+ settings_to_globals();
+ // Setup settings listeners
+ settings_setup_listeners();
+ // Modify settings based on system configuration and compile options
+ settings_modify();
+
+ // Find partition serial number (Windows) or hardware serial (Mac)
+ mSerialNumber = generateSerialNumber();
+
+ // do any necessary set-up for accepting incoming SLURLs from apps
+ initSLURLHandler();
+
+ if(false == initHardwareTest())
+ {
+ // Early out from user choice.
+ return false;
+ }
+
+ // Prepare for out-of-memory situations, during which we will crash on
+ // purpose and save a dump.
+#if LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
+ MemSetErrorHandler(first_mem_error_handler);
+#endif // LL_WINDOWS && LL_RELEASE_FOR_DOWNLOAD && LL_USE_SMARTHEAP
+
+ // *Note: this is where gViewerStats used to be created.
+
+ //
+ // Initialize the VFS, and gracefully handle initialization errors
+ //
+
+ if (!initCache())
+ {
+ std::ostringstream msg;
+ msg << LLTrans::getString("MBUnableToAccessFile");
+ OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
+ return 1;
+ }
+
+ // Initialize the repeater service.
+ LLMainLoopRepeater::instance().start();
+
+ //
+ // Initialize the window
+ //
+ gGLActive = TRUE;
+ initWindow();
+
+ // initWindow also initializes the Feature List, so now we can initialize this global.
+ LLCubeMap::sUseCubeMaps = LLFeatureManager::getInstance()->isFeatureAvailable("RenderCubeMap");
+
+ // call all self-registered classes
+ LLInitClassList::instance().fireCallbacks();
+
+ LLFolderViewItem::initClass(); // SJB: Needs to happen after initWindow(), not sure why but related to fonts
+
+ gGLManager.getGLInfo(gDebugInfo);
+ gGLManager.printGLInfoString();
+
+ // Load Default bindings
+ std::string key_bindings_file = gDirUtilp->findFile("keys.xml",
+ gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
+ gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+
+
+ if (!gViewerKeyboard.loadBindingsXML(key_bindings_file))
+ {
+ std::string key_bindings_file = gDirUtilp->findFile("keys.ini",
+ gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, ""),
+ gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+ if (!gViewerKeyboard.loadBindings(key_bindings_file))
+ {
+ LL_ERRS("InitInfo") << "Unable to open keys.ini" << LL_ENDL;
+ }
+ }
+
+ // If we don't have the right GL requirements, exit.
+ if (!gGLManager.mHasRequirements && !gNoRender)
+ {
+ // can't use an alert here since we're exiting and
+ // all hell breaks lose.
+ OSMessageBox(
+ LLNotifications::instance().getGlobalString("UnsupportedGLRequirements"),
+ LLStringUtil::null,
+ OSMB_OK);
+ return 0;
+ }
+
+ // alert the user if they are using unsupported hardware
+ if(!gSavedSettings.getBOOL("AlertedUnsupportedHardware"))
+ {
+ bool unsupported = false;
+ LLSD args;
+ std::string minSpecs;
+
+ // get cpu data from xml
+ std::stringstream minCPUString(LLNotifications::instance().getGlobalString("UnsupportedCPUAmount"));
+ S32 minCPU = 0;
+ minCPUString >> minCPU;
+
+ // get RAM data from XML
+ std::stringstream minRAMString(LLNotifications::instance().getGlobalString("UnsupportedRAMAmount"));
+ U64 minRAM = 0;
+ minRAMString >> minRAM;
+ minRAM = minRAM * 1024 * 1024;
+
+ if(!LLFeatureManager::getInstance()->isGPUSupported() && LLFeatureManager::getInstance()->getGPUClass() != GPU_CLASS_UNKNOWN)
+ {
+ minSpecs += LLNotifications::instance().getGlobalString("UnsupportedGPU");
+ minSpecs += "\n";
+ unsupported = true;
+ }
+ if(gSysCPU.getMHz() < minCPU)
+ {
+ minSpecs += LLNotifications::instance().getGlobalString("UnsupportedCPU");
+ minSpecs += "\n";
+ unsupported = true;
+ }
+ if(gSysMemory.getPhysicalMemoryClamped() < minRAM)
+ {
+ minSpecs += LLNotifications::instance().getGlobalString("UnsupportedRAM");
+ minSpecs += "\n";
+ unsupported = true;
+ }
+
+ if (LLFeatureManager::getInstance()->getGPUClass() == GPU_CLASS_UNKNOWN)
+ {
+ LLNotificationsUtil::add("UnknownGPU");
+ }
+
+ if(unsupported)
+ {
+ if(!gSavedSettings.controlExists("WarnUnsupportedHardware")
+ || gSavedSettings.getBOOL("WarnUnsupportedHardware"))
+ {
+ args["MINSPECS"] = minSpecs;
+ LLNotificationsUtil::add("UnsupportedHardware", args );
+ }
+
+ }
+ }
+
+
+ // save the graphics card
+ gDebugInfo["GraphicsCard"] = LLFeatureManager::getInstance()->getGPUString();
+
+ // Save the current version to the prefs file
+ gSavedSettings.setString("LastRunVersion",
+ LLVersionInfo::getChannelAndVersion());
+
+ gSimLastTime = gRenderStartTime.getElapsedTimeF32();
+ gSimFrames = (F32)gFrameCount;
+
+ LLViewerJoystick::getInstance()->init(false);
+
+ try {
+ initializeSecHandler();
+ }
+ catch (LLProtectedDataException ex)
+ {
+ LLNotificationsUtil::add("CorruptedProtectedDataStore");
+ }
+ LLHTTPClient::setCertVerifyCallback(secapiSSLCertVerifyCallback);
+
+
+ gGLActive = FALSE;
+ if (gSavedSettings.getBOOL("QAMode") && gSavedSettings.getS32("QAModeEventHostPort") > 0)
+ {
+ loadEventHostModule(gSavedSettings.getS32("QAModeEventHostPort"));
+ }
+
+ LLViewerMedia::initClass();
+ LLTextUtil::TextHelpers::iconCallbackCreationFunction = create_text_segment_icon_from_url_match;
+
+ //EXT-7013 - On windows for some locale (Japanese) standard
+ //datetime formatting functions didn't support some parameters such as "weekday".
+ //Names for days and months localized in xml are also useful for Polish locale(STORM-107).
+ std::string language = LLControlGroup::getInstance(sGlobalSettingsName)->getString("Language");
+ if(language == "ja" || language == "pl")
+ {
+ LLStringOps::setupWeekDaysNames(LLTrans::getString("dateTimeWeekdaysNames"));
+ LLStringOps::setupWeekDaysShortNames(LLTrans::getString("dateTimeWeekdaysShortNames"));
+ LLStringOps::setupMonthNames(LLTrans::getString("dateTimeMonthNames"));
+ LLStringOps::setupMonthShortNames(LLTrans::getString("dateTimeMonthShortNames"));
+ LLStringOps::setupDayFormat(LLTrans::getString("dateTimeDayFormat"));
+
+ LLStringOps::sAM = LLTrans::getString("dateTimeAM");
+ LLStringOps::sPM = LLTrans::getString("dateTimePM");
+ }
+
+ LLAgentLanguage::init();
+
+
+
+ return true;
+}
+
+static LLFastTimer::DeclareTimer FTM_MESSAGES("System Messages");
+static LLFastTimer::DeclareTimer FTM_SLEEP("Sleep");
+static LLFastTimer::DeclareTimer FTM_TEXTURE_CACHE("Texture Cache");
+static LLFastTimer::DeclareTimer FTM_DECODE("Image Decode");
+static LLFastTimer::DeclareTimer FTM_VFS("VFS Thread");
+static LLFastTimer::DeclareTimer FTM_LFS("LFS Thread");
+static LLFastTimer::DeclareTimer FTM_PAUSE_THREADS("Pause Threads");
+static LLFastTimer::DeclareTimer FTM_IDLE("Idle");
+static LLFastTimer::DeclareTimer FTM_PUMP("Pump");
+static LLFastTimer::DeclareTimer FTM_PUMP_ARES("Ares");
+static LLFastTimer::DeclareTimer FTM_PUMP_SERVICE("Service");
+static LLFastTimer::DeclareTimer FTM_SERVICE_CALLBACK("Callback");
+static LLFastTimer::DeclareTimer FTM_AGENT_AUTOPILOT("Autopilot");
+static LLFastTimer::DeclareTimer FTM_AGENT_UPDATE("Update");
+
+bool LLAppViewer::mainLoop()
+{
+ LLMemType mt1(LLMemType::MTYPE_MAIN);
+ mMainloopTimeout = new LLWatchdogTimeout();
+
+ //-------------------------------------------
+ // Run main loop until time to quit
+ //-------------------------------------------
+
+ // Create IO Pump to use for HTTP Requests.
+ gServicePump = new LLPumpIO(gAPRPoolp);
+ LLHTTPClient::setPump(*gServicePump);
+ LLCurl::setCAFile(gDirUtilp->getCAFile());
+
+ // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be instantiated.
+
+ LLVoiceChannel::initClass();
+ LLVoiceClient::getInstance()->init(gServicePump);
+ LLTimer frameTimer,idleTimer;
+ LLTimer debugTime;
+ LLFrameTimer memCheckTimer;
+ LLViewerJoystick* joystick(LLViewerJoystick::getInstance());
+ joystick->setNeedsReset(true);
+
+ LLEventPump& mainloop(LLEventPumps::instance().obtain("mainloop"));
+ // As we do not (yet) send data on the mainloop LLEventPump that varies
+ // with each frame, no need to instantiate a new LLSD event object each
+ // time. Obviously, if that changes, just instantiate the LLSD at the
+ // point of posting.
+ LLSD newFrame;
+
+ const F32 memory_check_interval = 1.0f ; //second
+
+ // Handle messages
+ while (!LLApp::isExiting())
+ {
+ LLFastTimer::nextFrame(); // Should be outside of any timer instances
+
+ //clear call stack records
+ llclearcallstacks;
+
+ //check memory availability information
+ {
+ if(memory_check_interval < memCheckTimer.getElapsedTimeF32())
+ {
+ memCheckTimer.reset() ;
+
+ //update the availability of memory
+ LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ;
+ }
+ llcallstacks << "Available physical mem(KB): " << mAvailPhysicalMemInKB << llcallstacksendl ;
+ llcallstacks << "Available virtual mem(KB): " << mAvailVirtualMemInKB << llcallstacksendl ;
+ }
+
+ try
+ {
+ pingMainloopTimeout("Main:MiscNativeWindowEvents");
+
+ if (gViewerWindow)
+ {
+ LLFastTimer t2(FTM_MESSAGES);
+ gViewerWindow->mWindow->processMiscNativeEvents();
+ }
+
+ pingMainloopTimeout("Main:GatherInput");
+
+ if (gViewerWindow)
+ {
+ LLFastTimer t2(FTM_MESSAGES);
+ if (!restoreErrorTrap())
+ {
+ llwarns << " Someone took over my signal/exception handler (post messagehandling)!" << llendl;
+ }
+
+ gViewerWindow->mWindow->gatherInput();
+ }
+
+#if 1 && !LL_RELEASE_FOR_DOWNLOAD
+ // once per second debug info
+ if (debugTime.getElapsedTimeF32() > 1.f)
+ {
+ debugTime.reset();
+ }
+
+#endif
+ //memory leaking simulation
+ LLFloaterMemLeak* mem_leak_instance =
+ LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
+ if(mem_leak_instance)
+ {
+ mem_leak_instance->idle() ;
+ }
+
+ // canonical per-frame event
+ mainloop.post(newFrame);
+
+ if (!LLApp::isExiting())
+ {
+ pingMainloopTimeout("Main:JoystickKeyboard");
+
+ // Scan keyboard for movement keys. Command keys and typing
+ // are handled by windows callbacks. Don't do this until we're
+ // done initializing. JC
+ if (gViewerWindow->mWindow->getVisible()
+ && gViewerWindow->getActive()
+ && !gViewerWindow->mWindow->getMinimized()
+ && LLStartUp::getStartupState() == STATE_STARTED
+ && !gViewerWindow->getShowProgress()
+ && !gFocusMgr.focusLocked())
+ {
+ LLMemType mjk(LLMemType::MTYPE_JOY_KEY);
+ joystick->scanJoystick();
+ gKeyboard->scanKeyboard();
+ }
+
+ // Update state based on messages, user input, object idle.
+ {
+ pauseMainloopTimeout(); // *TODO: Remove. Messages shouldn't be stalling for 20+ seconds!
+
+ LLFastTimer t3(FTM_IDLE);
+ idle();
+
+ if (gAres != NULL && gAres->isInitialized())
+ {
+ LLMemType mt_ip(LLMemType::MTYPE_IDLE_PUMP);
+ pingMainloopTimeout("Main:ServicePump");
+ LLFastTimer t4(FTM_PUMP);
+ {
+ LLFastTimer t(FTM_PUMP_ARES);
+ gAres->process();
+ }
+ {
+ LLFastTimer t(FTM_PUMP_SERVICE);
+ // this pump is necessary to make the login screen show up
+ gServicePump->pump();
+
+ {
+ LLFastTimer t(FTM_SERVICE_CALLBACK);
+ gServicePump->callback();
+ }
+ }
+ }
+
+ resumeMainloopTimeout();
+ }
+
+ if (gDoDisconnect && (LLStartUp::getStartupState() == STATE_STARTED))
+ {
+ pauseMainloopTimeout();
+ saveFinalSnapshot();
+ disconnectViewer();
+ resumeMainloopTimeout();
+ }
+
+ // Render scene.
+ if (!LLApp::isExiting())
+ {
+ pingMainloopTimeout("Main:Display");
+ gGLActive = TRUE;
+ display();
+ pingMainloopTimeout("Main:Snapshot");
+ LLFloaterSnapshot::update(); // take snapshots
+ gGLActive = FALSE;
+ }
+
+ }
+
+ pingMainloopTimeout("Main:Sleep");
+
+ pauseMainloopTimeout();
+
+ // Sleep and run background threads
+ {
+ LLMemType mt_sleep(LLMemType::MTYPE_SLEEP);
+ LLFastTimer t2(FTM_SLEEP);
+
+ // yield some time to the os based on command line option
+ if(mYieldTime >= 0)
+ {
+ ms_sleep(mYieldTime);
+ }
+
+ // yield cooperatively when not running as foreground window
+ if ( gNoRender
+ || (gViewerWindow && !gViewerWindow->mWindow->getVisible())
+ || !gFocusMgr.getAppHasFocus())
+ {
+ // Sleep if we're not rendering, or the window is minimized.
+ S32 milliseconds_to_sleep = llclamp(gSavedSettings.getS32("BackgroundYieldTime"), 0, 1000);
+ // don't sleep when BackgroundYieldTime set to 0, since this will still yield to other threads
+ // of equal priority on Windows
+ if (milliseconds_to_sleep > 0)
+ {
+ ms_sleep(milliseconds_to_sleep);
+ // also pause worker threads during this wait period
+ LLAppViewer::getTextureCache()->pause();
+ LLAppViewer::getImageDecodeThread()->pause();
+ }
+ }
+
+ if (mRandomizeFramerate)
+ {
+ ms_sleep(rand() % 200);
+ }
+
+ if (mPeriodicSlowFrame
+ && (gFrameCount % 10 == 0))
+ {
+ llinfos << "Periodic slow frame - sleeping 500 ms" << llendl;
+ ms_sleep(500);
+ }
+
+ static const F64 FRAME_SLOW_THRESHOLD = 0.5; //2 frames per seconds
+ const F64 max_idle_time = llmin(.005*10.0*gFrameTimeSeconds, 0.005); // 5 ms a second
+ idleTimer.reset();
+ bool is_slow = (frameTimer.getElapsedTimeF64() > FRAME_SLOW_THRESHOLD) ;
+ S32 total_work_pending = 0;
+ S32 total_io_pending = 0;
+ while(!is_slow)//do not unpause threads if the frame rates are very low.
+ {
+ S32 work_pending = 0;
+ S32 io_pending = 0;
+ {
+ LLFastTimer ftm(FTM_TEXTURE_CACHE);
+ work_pending += LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
+ }
+ {
+ LLFastTimer ftm(FTM_DECODE);
+ work_pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
+ }
+ {
+ LLFastTimer ftm(FTM_DECODE);
+ work_pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
+ }
+
+ {
+ LLFastTimer ftm(FTM_VFS);
+ io_pending += LLVFSThread::updateClass(1);
+ }
+ {
+ LLFastTimer ftm(FTM_LFS);
+ io_pending += LLLFSThread::updateClass(1);
+ }
+
+ if (io_pending > 1000)
+ {
+ ms_sleep(llmin(io_pending/100,100)); // give the vfs some time to catch up
+ }
+
+ total_work_pending += work_pending ;
+ total_io_pending += io_pending ;
+
+ if (!work_pending || idleTimer.getElapsedTimeF64() >= max_idle_time)
+ {
+ break;
+ }
+ }
+
+ if(!total_work_pending) //pause texture fetching threads if nothing to process.
+ {
+ LLAppViewer::getTextureCache()->pause();
+ LLAppViewer::getImageDecodeThread()->pause();
+ LLAppViewer::getTextureFetch()->pause();
+ }
+ if(!total_io_pending) //pause file threads if nothing to process.
+ {
+ LLVFSThread::sLocal->pause();
+ LLLFSThread::sLocal->pause();
+ }
+
+ if ((LLStartUp::getStartupState() >= STATE_CLEANUP) &&
+ (frameTimer.getElapsedTimeF64() > FRAME_STALL_THRESHOLD))
+ {
+ gFrameStalls++;
+ }
+ frameTimer.reset();
+
+ resumeMainloopTimeout();
+
+ pingMainloopTimeout("Main:End");
+ }
+ }
+ catch(std::bad_alloc)
+ {
+ {
+ llinfos << "Availabe physical memory(KB) at the beginning of the frame: " << mAvailPhysicalMemInKB << llendl ;
+ llinfos << "Availabe virtual memory(KB) at the beginning of the frame: " << mAvailVirtualMemInKB << llendl ;
+
+ LLMemoryInfo::getAvailableMemoryKB(mAvailPhysicalMemInKB, mAvailVirtualMemInKB) ;
+
+ llinfos << "Current availabe physical memory(KB): " << mAvailPhysicalMemInKB << llendl ;
+ llinfos << "Current availabe virtual memory(KB): " << mAvailVirtualMemInKB << llendl ;
+ }
+
+ //stop memory leaking simulation
+ LLFloaterMemLeak* mem_leak_instance =
+ LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
+ if(mem_leak_instance)
+ {
+ mem_leak_instance->stop() ;
+ llwarns << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ;
+ }
+ else
+ {
+ //output possible call stacks to log file.
+ LLError::LLCallStacks::print() ;
+
+ llerrs << "Bad memory allocation in LLAppViewer::mainLoop()!" << llendl ;
+ }
+ }
+ }
+
+ // Save snapshot for next time, if we made it through initialization
+ if (STATE_STARTED == LLStartUp::getStartupState())
+ {
+ try
+ {
+ saveFinalSnapshot();
+ }
+ catch(std::bad_alloc)
+ {
+ llwarns << "Bad memory allocation when saveFinalSnapshot() is called!" << llendl ;
+
+ //stop memory leaking simulation
+ LLFloaterMemLeak* mem_leak_instance =
+ LLFloaterReg::findTypedInstance<LLFloaterMemLeak>("mem_leaking");
+ if(mem_leak_instance)
+ {
+ mem_leak_instance->stop() ;
+ }
+ }
+ }
+
+ delete gServicePump;
+
+ destroyMainloopTimeout();
+
+ llinfos << "Exiting main_loop" << llendflush;
+
+ return true;
+}
+
+void LLAppViewer::flushVFSIO()
+{
+ while (1)
+ {
+ S32 pending = LLVFSThread::updateClass(0);
+ pending += LLLFSThread::updateClass(0);
+ if (!pending)
+ {
+ break;
+ }
+ llinfos << "Waiting for pending IO to finish: " << pending << llendflush;
+ ms_sleep(100);
+ }
+}
+
+bool LLAppViewer::cleanup()
+{
+ // workaround for DEV-35406 crash on shutdown
+ LLEventPumps::instance().reset();
+
+ // remove any old breakpad minidump files from the log directory
+ if (! isError())
+ {
+ std::string logdir = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "");
+ logdir += gDirUtilp->getDirDelimiter();
+ gDirUtilp->deleteFilesInDir(logdir, "*-*-*-*-*.dmp");
+ }
+
+ // *TODO - generalize this and move DSO wrangling to a helper class -brad
+ std::set<struct apr_dso_handle_t *>::const_iterator i;
+ for(i = mPlugins.begin(); i != mPlugins.end(); ++i)
+ {
+ int (*ll_plugin_stop_func)(void) = NULL;
+ apr_status_t rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_stop_func, *i, "ll_plugin_stop");
+ ll_plugin_stop_func();
+
+ rv = apr_dso_unload(*i);
+ }
+ mPlugins.clear();
+
+ //flag all elements as needing to be destroyed immediately
+ // to ensure shutdown order
+ LLMortician::setZealous(TRUE);
+
+ LLVoiceClient::getInstance()->terminate();
+
+ disconnectViewer();
+
+ llinfos << "Viewer disconnected" << llendflush;
+
+ display_cleanup();
+
+ release_start_screen(); // just in case
+
+ LLError::logToFixedBuffer(NULL);
+
+ llinfos << "Cleaning Up" << llendflush;
+
+ // Must clean up texture references before viewer window is destroyed.
+ if(LLHUDManager::instanceExists())
+ {
+ LLHUDManager::getInstance()->updateEffects();
+ LLHUDObject::updateAll();
+ LLHUDManager::getInstance()->cleanupEffects();
+ LLHUDObject::cleanupHUDObjects();
+ llinfos << "HUD Objects cleaned up" << llendflush;
+ }
+
+ LLKeyframeDataCache::clear();
+
+ // End TransferManager before deleting systems it depends on (Audio, VFS, AssetStorage)
+#if 0 // this seems to get us stuck in an infinite loop...
+ gTransferManager.cleanup();
+#endif
+
+ // Note: this is where gWorldMap used to be deleted.
+
+ // Note: this is where gHUDManager used to be deleted.
+ if(LLHUDManager::instanceExists())
+ {
+ LLHUDManager::getInstance()->shutdownClass();
+ }
+
+ delete gAssetStorage;
+ gAssetStorage = NULL;
+
+ LLPolyMesh::freeAllMeshes();
+
+ LLStartUp::cleanupNameCache();
+
+ // Note: this is where gLocalSpeakerMgr and gActiveSpeakerMgr used to be deleted.
+
+ LLWorldMap::getInstance()->reset(); // release any images
+
+ llinfos << "Global stuff deleted" << llendflush;
+
+ if (gAudiop)
+ {
+ // shut down the streaming audio sub-subsystem first, in case it relies on not outliving the general audio subsystem.
+
+ LLStreamingAudioInterface *sai = gAudiop->getStreamingAudioImpl();
+ delete sai;
+ gAudiop->setStreamingAudioImpl(NULL);
+
+ // shut down the audio subsystem
+
+ bool want_longname = false;
+ if (gAudiop->getDriverName(want_longname) == "FMOD")
+ {
+ // This hack exists because fmod likes to occasionally
+ // crash or hang forever when shutting down, for no
+ // apparent reason.
+ llwarns << "Hack, skipping FMOD audio engine cleanup" << llendflush;
+ }
+ else
+ {
+ gAudiop->shutdown();
+ }
+
+ delete gAudiop;
+ gAudiop = NULL;
+ }
+
+ // Note: this is where LLFeatureManager::getInstance()-> used to be deleted.
+
+ // Patch up settings for next time
+ // Must do this before we delete the viewer window,
+ // such that we can suck rectangle information out of
+ // it.
+ cleanupSavedSettings();
+ llinfos << "Settings patched up" << llendflush;
+
+ // delete some of the files left around in the cache.
+ removeCacheFiles("*.wav");
+ removeCacheFiles("*.tmp");
+ removeCacheFiles("*.lso");
+ removeCacheFiles("*.out");
+ removeCacheFiles("*.dsf");
+ removeCacheFiles("*.bodypart");
+ removeCacheFiles("*.clothing");
+
+ llinfos << "Cache files removed" << llendflush;
+
+ // Wait for any pending VFS IO
+ flushVFSIO();
+ llinfos << "Shutting down Views" << llendflush;
+
+ // Destroy the UI
+ if( gViewerWindow)
+ gViewerWindow->shutdownViews();
+
+ llinfos << "Cleaning up Inventory" << llendflush;
+
+ // Cleanup Inventory after the UI since it will delete any remaining observers
+ // (Deleted observers should have already removed themselves)
+ gInventory.cleanupInventory();
+
+ llinfos << "Cleaning up Selections" << llendflush;
+
+ // Clean up selection managers after UI is destroyed, as UI may be observing them.
+ // Clean up before GL is shut down because we might be holding on to objects with texture references
+ LLSelectMgr::cleanupGlobals();
+
+ llinfos << "Shutting down OpenGL" << llendflush;
+
+ // Shut down OpenGL
+ if( gViewerWindow)
+ {
+ gViewerWindow->shutdownGL();
+
+ // Destroy window, and make sure we're not fullscreen
+ // This may generate window reshape and activation events.
+ // Therefore must do this before destroying the message system.
+ delete gViewerWindow;
+ gViewerWindow = NULL;
+ llinfos << "ViewerWindow deleted" << llendflush;
+ }
+
+ llinfos << "Cleaning up Keyboard & Joystick" << llendflush;
+
+ // viewer UI relies on keyboard so keep it aound until viewer UI isa gone
+ delete gKeyboard;
+ gKeyboard = NULL;
+
+ // Turn off Space Navigator and similar devices
+ LLViewerJoystick::getInstance()->terminate();
+
+ llinfos << "Cleaning up Objects" << llendflush;
+
+ LLViewerObject::cleanupVOClasses();
+
+ LLWaterParamManager::cleanupClass();
+ LLWLParamManager::cleanupClass();
+ LLPostProcess::cleanupClass();
+
+ LLTracker::cleanupInstance();
+
+ // *FIX: This is handled in LLAppViewerWin32::cleanup().
+ // I'm keeping the comment to remember its order in cleanup,
+ // in case of unforseen dependency.
+ //#if LL_WINDOWS
+ // gDXHardware.cleanup();
+ //#endif // LL_WINDOWS
+
+ LLVolumeMgr* volume_manager = LLPrimitive::getVolumeManager();
+ if (!volume_manager->cleanup())
+ {
+ llwarns << "Remaining references in the volume manager!" << llendflush;
+ }
+ LLPrimitive::cleanupVolumeManager();
+
+ llinfos << "Additional Cleanup..." << llendflush;
+
+ LLViewerParcelMgr::cleanupGlobals();
+
+ // *Note: this is where gViewerStats used to be deleted.
+
+ //end_messaging_system();
+
+ LLFollowCamMgr::cleanupClass();
+ //LLVolumeMgr::cleanupClass();
+ LLPrimitive::cleanupVolumeManager();
+ LLWorldMapView::cleanupClass();
+ LLFolderViewItem::cleanupClass();
+ LLUI::cleanupClass();
+
+ //
+ // Shut down the VFS's AFTER the decode manager cleans up (since it cleans up vfiles).
+ // Also after viewerwindow is deleted, since it may have image pointers (which have vfiles)
+ // Also after shutting down the messaging system since it has VFS dependencies
+
+ //
+ llinfos << "Cleaning up VFS" << llendflush;
+ LLVFile::cleanupClass();
+
+ llinfos << "Saving Data" << llendflush;
+
+ // Store the time of our current logoff
+ gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
+
+ // Must do this after all panels have been deleted because panels that have persistent rects
+ // save their rects on delete.
+ gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);
+
+ LLUIColorTable::instance().saveUserSettings();
+
+ // PerAccountSettingsFile should be empty if no user has been logged on.
+ // *FIX:Mani This should get really saved in a "logoff" mode.
+ if (gSavedSettings.getString("PerAccountSettingsFile").empty())
+ {
+ llinfos << "Not saving per-account settings; don't know the account name yet." << llendl;
+ }
+ else
+ {
+ gSavedPerAccountSettings.saveToFile(gSavedSettings.getString("PerAccountSettingsFile"), TRUE);
+ llinfos << "Saved settings" << llendflush;
+ }
+
+ std::string crash_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, CRASH_SETTINGS_FILE);
+ // save all settings, even if equals defaults
+ gCrashSettings.saveToFile(crash_settings_filename, FALSE);
+
+ std::string warnings_settings_filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Warnings"));
+ gWarningSettings.saveToFile(warnings_settings_filename, TRUE);
+
+ // Save URL history file
+ LLURLHistory::saveFile("url_history.xml");
+
+ // save mute list. gMuteList used to also be deleted here too.
+ LLMuteList::getInstance()->cache(gAgent.getID());
+
+ if (mPurgeOnExit)
+ {
+ llinfos << "Purging all cache files on exit" << llendflush;
+ std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
+ gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
+ }
+
+ removeMarkerFile(); // Any crashes from here on we'll just have to ignore
+
+ writeDebugInfo();
+
+ LLLocationHistory::getInstance()->save();
+
+ LLAvatarIconIDCache::getInstance()->save();
+
+ LLViewerMedia::saveCookieFile();
+
+ // Stop the plugin read thread if it's running.
+ LLPluginProcessParent::setUseReadThread(false);
+
+ llinfos << "Shutting down Threads" << llendflush;
+
+ // Let threads finish
+ LLTimer idleTimer;
+ idleTimer.reset();
+ const F64 max_idle_time = 5.f; // 5 seconds
+ while(1)
+ {
+ S32 pending = 0;
+ pending += LLAppViewer::getTextureCache()->update(1); // unpauses the worker thread
+ pending += LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
+ pending += LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
+ pending += LLVFSThread::updateClass(0);
+ pending += LLLFSThread::updateClass(0);
+ F64 idle_time = idleTimer.getElapsedTimeF64();
+ if(!pending)
+ {
+ break ; //done
+ }
+ else if(idle_time >= max_idle_time)
+ {
+ llwarns << "Quitting with pending background tasks." << llendl;
+ break;
+ }
+ }
+
+ // Delete workers first
+ // shotdown all worker threads before deleting them in case of co-dependencies
+ sTextureFetch->shutdown();
+ sTextureCache->shutdown();
+ sImageDecodeThread->shutdown();
+
+ sTextureFetch->shutDownTextureCacheThread() ;
+ sTextureFetch->shutDownImageDecodeThread() ;
+
+ delete sTextureCache;
+ sTextureCache = NULL;
+ delete sTextureFetch;
+ sTextureFetch = NULL;
+ delete sImageDecodeThread;
+ sImageDecodeThread = NULL;
+ delete mFastTimerLogThread;
+ mFastTimerLogThread = NULL;
+
+ if (LLFastTimerView::sAnalyzePerformance)
+ {
+ llinfos << "Analyzing performance" << llendl;
+
+ std::string baseline_name = LLFastTimer::sLogName + "_baseline.slp";
+ std::string current_name = LLFastTimer::sLogName + ".slp";
+ std::string report_name = LLFastTimer::sLogName + "_report.csv";
+
+ LLFastTimerView::doAnalysis(
+ gDirUtilp->getExpandedFilename(LL_PATH_LOGS, baseline_name),
+ gDirUtilp->getExpandedFilename(LL_PATH_LOGS, current_name),
+ gDirUtilp->getExpandedFilename(LL_PATH_LOGS, report_name));
+ }
+ LLMetricPerformanceTesterBasic::cleanClass() ;
+
+#if LL_RECORD_VIEWER_STATS
+ LLViewerStatsRecorder::cleanupClass();
+#endif
+
+ llinfos << "Cleaning up Media and Textures" << llendflush;
+
+ //Note:
+ //LLViewerMedia::cleanupClass() has to be put before gTextureList.shutdown()
+ //because some new image might be generated during cleaning up media. --bao
+ LLViewerMedia::cleanupClass();
+ LLViewerParcelMedia::cleanupClass();
+ gTextureList.shutdown(); // shutdown again in case a callback added something
+ LLUIImageList::getInstance()->cleanUp();
+
+ // This should eventually be done in LLAppViewer
+ LLImage::cleanupClass();
+ LLVFSThread::cleanupClass();
+ LLLFSThread::cleanupClass();
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ llinfos << "Auditing VFS" << llendl;
+ if(gVFS)
+ {
+ gVFS->audit();
+ }
+#endif
+
+ llinfos << "Misc Cleanup" << llendflush;
+
+ // For safety, the LLVFS has to be deleted *after* LLVFSThread. This should be cleaned up.
+ // (LLVFS doesn't know about LLVFSThread so can't kill pending requests) -Steve
+ delete gStaticVFS;
+ gStaticVFS = NULL;
+ delete gVFS;
+ gVFS = NULL;
+
+ gSavedSettings.cleanup();
+ LLUIColorTable::instance().clear();
+ gCrashSettings.cleanup();
+
+ LLWatchdog::getInstance()->cleanup();
+
+ LLViewerAssetStatsFF::cleanup();
+
+ llinfos << "Shutting down message system" << llendflush;
+ end_messaging_system();
+
+ // *NOTE:Mani - The following call is not thread safe.
+ LLCurl::cleanupClass();
+
+ // If we're exiting to launch an URL, do that here so the screen
+ // is at the right resolution before we launch IE.
+ if (!gLaunchFileOnQuit.empty())
+ {
+ llinfos << "Launch file on quit." << llendflush;
+#if LL_WINDOWS
+ // Indicate an application is starting.
+ SetCursor(LoadCursor(NULL, IDC_WAIT));
+#endif
+
+ // HACK: Attempt to wait until the screen res. switch is complete.
+ ms_sleep(1000);
+
+ LLWeb::loadURLExternal( gLaunchFileOnQuit, false );
+ llinfos << "File launched." << llendflush;
+ }
+
+ LLMainLoopRepeater::instance().stop();
+
+ ll_close_fail_log();
+
+ MEM_TRACK_RELEASE
+
+ llinfos << "Goodbye!" << llendflush;
+
+ // return 0;
+ return true;
+}
+
+// A callback for llerrs to call during the watchdog error.
+void watchdog_llerrs_callback(const std::string &error_string)
+{
+ gLLErrorActivated = true;
+
+#ifdef LL_WINDOWS
+ RaiseException(0,0,0,0);
+#else
+ raise(SIGQUIT);
+#endif
+}
+
+// A callback for the watchdog to call.
+void watchdog_killer_callback()
+{
+ LLError::setFatalFunction(watchdog_llerrs_callback);
+ llerrs << "Watchdog killer event" << llendl;
+}
+
+bool LLAppViewer::initThreads()
+{
+#if MEM_TRACK_MEM
+ static const bool enable_threads = false;
+#else
+ static const bool enable_threads = true;
+#endif
+
+ LLVFSThread::initClass(enable_threads && false);
+ LLLFSThread::initClass(enable_threads && false);
+
+ // Image decoding
+ LLAppViewer::sImageDecodeThread = new LLImageDecodeThread(enable_threads && true);
+ LLAppViewer::sTextureCache = new LLTextureCache(enable_threads && true);
+ LLAppViewer::sTextureFetch = new LLTextureFetch(LLAppViewer::getTextureCache(),
+ sImageDecodeThread,
+ enable_threads && true,
+ app_metrics_qa_mode);
+ LLImage::initClass();
+
+ if (LLFastTimer::sLog || LLFastTimer::sMetricLog)
+ {
+ LLFastTimer::sLogLock = new LLMutex(NULL);
+ mFastTimerLogThread = new LLFastTimerLogThread(LLFastTimer::sLogName);
+ mFastTimerLogThread->start();
+ }
+
+ // *FIX: no error handling here!
+ return true;
+}
+
+void errorCallback(const std::string &error_string)
+{
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ OSMessageBox(error_string, LLTrans::getString("MBFatalError"), OSMB_OK);
+#endif
+
+ //Set the ErrorActivated global so we know to create a marker file
+ gLLErrorActivated = true;
+
+ LLError::crashAndLoop(error_string);
+}
+
+bool LLAppViewer::initLogging()
+{
+ //
+ // Set up logging defaults for the viewer
+ //
+ LLError::initForApplication(
+ gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+ LLError::setFatalFunction(errorCallback);
+
+ // Remove the last ".old" log file.
+ std::string old_log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+ "SecondLife.old");
+ LLFile::remove(old_log_file);
+
+ // Rename current log file to ".old"
+ std::string log_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,
+ "SecondLife.log");
+ LLFile::rename(log_file, old_log_file);
+
+ // Set the log file to SecondLife.log
+
+ LLError::logToFile(log_file);
+
+ // *FIX:Mani no error handling here!
+ return true;
+}
+
+bool LLAppViewer::loadSettingsFromDirectory(const std::string& location_key,
+ bool set_defaults)
+{
+ if (!mSettingsLocationList)
+ {
+ llerrs << "Invalid settings location list" << llendl;
+ }
+
+ LLControlGroup* global_settings = LLControlGroup::getInstance(sGlobalSettingsName);
+ for(LLInitParam::ParamIterator<SettingsGroup>::const_iterator it = mSettingsLocationList->groups.begin(), end_it = mSettingsLocationList->groups.end();
+ it != end_it;
+ ++it)
+ {
+ // skip settings groups that aren't the one we requested
+ if (it->name() != location_key) continue;
+
+ ELLPath path_index = (ELLPath)it->path_index();
+ if(path_index <= LL_PATH_NONE || path_index >= LL_PATH_LAST)
+ {
+ llerrs << "Out of range path index in app_settings/settings_files.xml" << llendl;
+ return false;
+ }
+
+ LLInitParam::ParamIterator<SettingsFile>::const_iterator file_it, end_file_it;
+ for (file_it = it->files.begin(), end_file_it = it->files.end();
+ file_it != end_file_it;
+ ++file_it)
+ {
+ llinfos << "Attempting to load settings for the group " << file_it->name()
+ << " - from location " << location_key << llendl;
+
+ LLControlGroup* settings_group = LLControlGroup::getInstance(file_it->name);
+ if(!settings_group)
+ {
+ llwarns << "No matching settings group for name " << file_it->name() << llendl;
+ continue;
+ }
+
+ std::string full_settings_path;
+
+ if (file_it->file_name_setting.isProvided()
+ && global_settings->controlExists(file_it->file_name_setting))
+ {
+ // try to find filename stored in file_name_setting control
+ full_settings_path = global_settings->getString(file_it->file_name_setting);
+ if (!gDirUtilp->fileExists(full_settings_path))
+ {
+ // search in default path
+ full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, full_settings_path);
+ }
+ }
+ else
+ {
+ // by default, use specified file name
+ full_settings_path = gDirUtilp->getExpandedFilename((ELLPath)path_index, file_it->file_name());
+ }
+
+ if(settings_group->loadFromFile(full_settings_path, set_defaults, file_it->persistent))
+ { // success!
+ llinfos << "Loaded settings file " << full_settings_path << llendl;
+ }
+ else
+ { // failed to load
+ if(file_it->required)
+ {
+ llerrs << "Error: Cannot load required settings file from: " << full_settings_path << llendl;
+ return false;
+ }
+ else
+ {
+ // only complain if we actually have a filename at this point
+ if (!full_settings_path.empty())
+ {
+ llinfos << "Cannot load " << full_settings_path << " - No settings found." << llendl;
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+std::string LLAppViewer::getSettingsFilename(const std::string& location_key,
+ const std::string& file)
+{
+ for(LLInitParam::ParamIterator<SettingsGroup>::const_iterator it = mSettingsLocationList->groups.begin(), end_it = mSettingsLocationList->groups.end();
+ it != end_it;
+ ++it)
+ {
+ if (it->name() == location_key)
+ {
+ LLInitParam::ParamIterator<SettingsFile>::const_iterator file_it, end_file_it;
+ for (file_it = it->files.begin(), end_file_it = it->files.end();
+ file_it != end_file_it;
+ ++file_it)
+ {
+ if (file_it->name() == file)
+ {
+ return file_it->file_name;
+ }
+ }
+ }
+ }
+
+ return std::string();
+}
+
+void LLAppViewer::loadColorSettings()
+{
+ LLUIColorTable::instance().loadFromSettings();
+}
+
+bool LLAppViewer::initConfiguration()
+{
+ //Load settings files list
+ std::string settings_file_list = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "settings_files.xml");
+ //LLControlGroup settings_control("SettingsFiles");
+ //llinfos << "Loading settings file list " << settings_file_list << llendl;
+ //if (0 == settings_control.loadFromFile(settings_file_list))
+ //{
+ // llerrs << "Cannot load default configuration file " << settings_file_list << llendl;
+ //}
+
+ LLXMLNodePtr root;
+ BOOL success = LLXMLNode::parseFile(settings_file_list, root, NULL);
+ if (!success)
+ {
+ llerrs << "Cannot load default configuration file " << settings_file_list << llendl;
+ }
+
+ mSettingsLocationList = new SettingsFiles();
+
+ LLXUIParser parser;
+ parser.readXUI(root, *mSettingsLocationList, settings_file_list);
+
+ if (!mSettingsLocationList->validateBlock())
+ {
+ llerrs << "Invalid settings file list " << settings_file_list << llendl;
+ }
+
+ // The settings and command line parsing have a fragile
+ // order-of-operation:
+ // - load defaults from app_settings
+ // - set procedural settings values
+ // - read command line settings
+ // - selectively apply settings needed to load user settings.
+ // - load overrides from user_settings
+ // - apply command line settings (to override the overrides)
+ // - load per account settings (happens in llstartup
+
+ // - load defaults
+ bool set_defaults = true;
+ if(!loadSettingsFromDirectory("Default", set_defaults))
+ {
+ std::ostringstream msg;
+ msg << "Unable to load default settings file. The installation may be corrupted.";
+ OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
+ return false;
+ }
+
+ LLUI::setupPaths(); // setup paths for LLTrans based on settings files only
+ LLTransUtil::parseStrings("strings.xml", default_trans_args);
+ LLTransUtil::parseLanguageStrings("language_settings.xml");
+ // - set procedural settings
+ // Note: can't use LL_PATH_PER_SL_ACCOUNT for any of these since we haven't logged in yet
+ gSavedSettings.setString("ClientSettingsFile",
+ gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, getSettingsFilename("Default", "Global")));
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ // provide developer build only overrides for these control variables that are not
+ // persisted to settings.xml
+ LLControlVariable* c = gSavedSettings.getControl("ShowConsoleWindow");
+ if (c)
+ {
+ c->setValue(true, false);
+ }
+ c = gSavedSettings.getControl("AllowMultipleViewers");
+ if (c)
+ {
+ c->setValue(true, false);
+ }
+#endif
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ gSavedSettings.setBOOL("QAMode", TRUE );
+ gSavedSettings.setS32("WatchdogEnabled", 0);
+#endif
+
+ gCrashSettings.getControl(CRASH_BEHAVIOR_SETTING)->getSignal()->connect(boost::bind(&handleCrashSubmitBehaviorChanged, _2));
+
+ // These are warnings that appear on the first experience of that condition.
+ // They are already set in the settings_default.xml file, but still need to be added to LLFirstUse
+ // for disable/reset ability
+// LLFirstUse::addConfigVariable("FirstBalanceIncrease");
+// LLFirstUse::addConfigVariable("FirstBalanceDecrease");
+// LLFirstUse::addConfigVariable("FirstSit");
+// LLFirstUse::addConfigVariable("FirstMap");
+// LLFirstUse::addConfigVariable("FirstGoTo");
+// LLFirstUse::addConfigVariable("FirstBuild");
+// LLFirstUse::addConfigVariable("FirstLeftClickNoHit");
+// LLFirstUse::addConfigVariable("FirstTeleport");
+// LLFirstUse::addConfigVariable("FirstOverrideKeys");
+// LLFirstUse::addConfigVariable("FirstAttach");
+// LLFirstUse::addConfigVariable("FirstAppearance");
+// LLFirstUse::addConfigVariable("FirstInventory");
+// LLFirstUse::addConfigVariable("FirstSandbox");
+// LLFirstUse::addConfigVariable("FirstFlexible");
+// LLFirstUse::addConfigVariable("FirstDebugMenus");
+// LLFirstUse::addConfigVariable("FirstSculptedPrim");
+// LLFirstUse::addConfigVariable("FirstVoice");
+// LLFirstUse::addConfigVariable("FirstMedia");
+
+ // - read command line settings.
+ LLControlGroupCLP clp;
+ std::string cmd_line_config = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,
+ "cmd_line.xml");
+
+ clp.configure(cmd_line_config, &gSavedSettings);
+
+ if(!initParseCommandLine(clp))
+ {
+ llwarns << "Error parsing command line options. Command Line options ignored." << llendl;
+
+ llinfos << "Command line usage:\n" << clp << llendl;
+
+ std::ostringstream msg;
+ msg << LLTrans::getString("MBCmdLineError") << clp.getErrorMessage();
+ OSMessageBox(msg.str(),LLStringUtil::null,OSMB_OK);
+ return false;
+ }
+
+ // - selectively apply settings
+
+ // If the user has specified a alternate settings file name.
+ // Load it now before loading the user_settings/settings.xml
+ if(clp.hasOption("settings"))
+ {
+ std::string user_settings_filename =
+ gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS,
+ clp.getOption("settings")[0]);
+ gSavedSettings.setString("ClientSettingsFile", user_settings_filename);
+ llinfos << "Using command line specified settings filename: "
+ << user_settings_filename << llendl;
+ }
+
+ // - load overrides from user_settings
+ loadSettingsFromDirectory("User");
+
+ if (gSavedSettings.getBOOL("FirstRunThisInstall"))
+ {
+ gSavedSettings.setString("SessionSettingsFile", "settings_minimal.xml");
+ }
+
+ if (clp.hasOption("sessionsettings"))
+ {
+ std::string session_settings_filename = clp.getOption("sessionsettings")[0];
+ gSavedSettings.setString("SessionSettingsFile", session_settings_filename);
+ llinfos << "Using session settings filename: "
+ << session_settings_filename << llendl;
+ }
+ loadSettingsFromDirectory("Session");
+
+ if (clp.hasOption("usersessionsettings"))
+ {
+ std::string user_session_settings_filename = clp.getOption("usersessionsettings")[0];
+ gSavedSettings.setString("UserSessionSettingsFile", user_session_settings_filename);
+ llinfos << "Using user session settings filename: "
+ << user_session_settings_filename << llendl;
+
+ }
+ loadSettingsFromDirectory("UserSession");
+
+ // - apply command line settings
+ clp.notify();
+
+ // Register the core crash option as soon as we can
+ // if we want gdb post-mortem on cores we need to be up and running
+ // ASAP or we might miss init issue etc.
+ if(clp.hasOption("disablecrashlogger"))
+ {
+ llwarns << "Crashes will be handled by system, stack trace logs and crash logger are both disabled" << llendl;
+ LLAppViewer::instance()->disableCrashlogger();
+ }
+
+ // Handle initialization from settings.
+ // Start up the debugging console before handling other options.
+ if (gSavedSettings.getBOOL("ShowConsoleWindow"))
+ {
+ initConsole();
+ }
+
+ if(clp.hasOption("help"))
+ {
+ std::ostringstream msg;
+ msg << LLTrans::getString("MBCmdLineUsg") << "\n" << clp;
+ llinfos << msg.str() << llendl;
+
+ OSMessageBox(
+ msg.str().c_str(),
+ LLStringUtil::null,
+ OSMB_OK);
+
+ return false;
+ }
+
+ if(clp.hasOption("set"))
+ {
+ const LLCommandLineParser::token_vector_t& set_values = clp.getOption("set");
+ if(0x1 & set_values.size())
+ {
+ llwarns << "Invalid '--set' parameter count." << llendl;
+ }
+ else
+ {
+ LLCommandLineParser::token_vector_t::const_iterator itr = set_values.begin();
+ for(; itr != set_values.end(); ++itr)
+ {
+ const std::string& name = *itr;
+ const std::string& value = *(++itr);
+ LLControlVariable* c = LLControlGroup::getInstance(sGlobalSettingsName)->getControl(name);
+ if(c)
+ {
+ c->setValue(value, false);
+ }
+ else
+ {
+ llwarns << "'--set' specified with unknown setting: '"
+ << name << "'." << llendl;
+ }
+ }
+ }
+ }
+
+ if(clp.hasOption("channel"))
+ {
+ LLVersionInfo::resetChannel(clp.getOption("channel")[0]);
+ }
+
+
+ // If we have specified crash on startup, set the global so we'll trigger the crash at the right time
+ if(clp.hasOption("crashonstartup"))
+ {
+ gCrashOnStartup = TRUE;
+ }
+
+ if (clp.hasOption("logperformance"))
+ {
+ LLFastTimer::sLog = TRUE;
+ LLFastTimer::sLogName = std::string("performance");
+ }
+
+ if (clp.hasOption("logmetrics"))
+ {
+ LLFastTimer::sMetricLog = TRUE ;
+ // '--logmetrics' can be specified with a named test metric argument so the data gathering is done only on that test
+ // In the absence of argument, every metric is gathered (makes for a rather slow run and hard to decipher report...)
+ std::string test_name = clp.getOption("logmetrics")[0];
+ llinfos << "'--logmetrics' argument : " << test_name << llendl;
+ if (test_name == "")
+ {
+ llwarns << "No '--logmetrics' argument given, will output all metrics to " << DEFAULT_METRIC_NAME << llendl;
+ LLFastTimer::sLogName = DEFAULT_METRIC_NAME;
+ }
+ else
+ {
+ LLFastTimer::sLogName = test_name;
+ }
+ }
+
+ if (clp.hasOption("graphicslevel"))
+ {
+ const LLCommandLineParser::token_vector_t& value = clp.getOption("graphicslevel");
+ if(value.size() != 1)
+ {
+ llwarns << "Usage: -graphicslevel <0-3>" << llendl;
+ }
+ else
+ {
+ std::string detail = value.front();
+ mForceGraphicsDetail = TRUE;
+
+ switch (detail.c_str()[0])
+ {
+ case '0':
+ gSavedSettings.setU32("RenderQualityPerformance", 0);
+ break;
+ case '1':
+ gSavedSettings.setU32("RenderQualityPerformance", 1);
+ break;
+ case '2':
+ gSavedSettings.setU32("RenderQualityPerformance", 2);
+ break;
+ case '3':
+ gSavedSettings.setU32("RenderQualityPerformance", 3);
+ break;
+ default:
+ mForceGraphicsDetail = FALSE;
+ llwarns << "Usage: -graphicslevel <0-3>" << llendl;
+ break;
+ }
+ }
+ }
+
+ if (clp.hasOption("analyzeperformance"))
+ {
+ LLFastTimerView::sAnalyzePerformance = TRUE;
+ }
+
+ if (clp.hasOption("replaysession"))
+ {
+ LLAgentPilot::sReplaySession = TRUE;
+ }
+
+ if (clp.hasOption("nonotifications"))
+ {
+ gSavedSettings.getControl("IgnoreAllNotifications")->setValue(true, false);
+ }
+
+ if (clp.hasOption("debugsession"))
+ {
+ gDebugSession = TRUE;
+ gDebugGL = TRUE;
+
+ ll_init_fail_log(gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "test_failures.log"));
+ }
+
+ // Handle slurl use. NOTE: Don't let SL-55321 reappear.
+
+ // *FIX: This init code should be made more robust to prevent
+ // the issue SL-55321 from returning. One thought is to allow
+ // only select options to be set from command line when a slurl
+ // is specified. More work on the settings system is needed to
+ // achieve this. For now...
+
+ // *NOTE:Mani The command line parser parses tokens and is
+ // setup to bail after parsing the '--url' option or the
+ // first option specified without a '--option' flag (or
+ // any other option that uses the 'last_option' setting -
+ // see LLControlGroupCLP::configure())
+
+ // What can happen is that someone can use IE (or potentially
+ // other browsers) and do the rough equivalent of command
+ // injection and steal passwords. Phoenix. SL-55321
+ if(clp.hasOption("url"))
+ {
+ LLStartUp::setStartSLURL(LLSLURL(clp.getOption("url")[0]));
+ if(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION)
+ {
+ LLGridManager::getInstance()->setGridChoice(LLStartUp::getStartSLURL().getGrid());
+
+ }
+ }
+ else if(clp.hasOption("slurl"))
+ {
+ LLSLURL start_slurl(clp.getOption("slurl")[0]);
+ LLStartUp::setStartSLURL(start_slurl);
+ }
+
+ const LLControlVariable* skinfolder = gSavedSettings.getControl("SkinCurrent");
+ if(skinfolder && LLStringUtil::null != skinfolder->getValue().asString())
+ {
+ // hack to force the skin to default.
+ gDirUtilp->setSkinFolder(skinfolder->getValue().asString());
+ //gDirUtilp->setSkinFolder("default");
+ }
+
+ mYieldTime = gSavedSettings.getS32("YieldTime");
+
+ // Read skin/branding settings if specified.
+ //if (! gDirUtilp->getSkinDir().empty() )
+ //{
+ // std::string skin_def_file = gDirUtilp->findSkinnedFilename("skin.xml");
+ // LLXmlTree skin_def_tree;
+
+ // if (!skin_def_tree.parseFile(skin_def_file))
+ // {
+ // llerrs << "Failed to parse skin definition." << llendl;
+ // }
+
+ //}
+
+#if LL_DARWIN
+ // Initialize apple menubar and various callbacks
+ init_apple_menu(LLTrans::getString("APP_NAME").c_str());
+
+#if __ppc__
+ // If the CPU doesn't have Altivec (i.e. it's not at least a G4), don't go any further.
+ // Only test PowerPC - all Intel Macs have SSE.
+ if(!gSysCPU.hasAltivec())
+ {
+ std::ostringstream msg;
+ msg << LLTrans::getString("MBRequiresAltiVec");
+ OSMessageBox(
+ msg.str(),
+ LLStringUtil::null,
+ OSMB_OK);
+ removeMarkerFile();
+ return false;
+ }
+#endif
+
+#endif // LL_DARWIN
+
+ // Display splash screen. Must be after above check for previous
+ // crash as this dialog is always frontmost.
+ std::string splash_msg;
+ LLStringUtil::format_map_t args;
+ args["[APP_NAME]"] = LLTrans::getString("SECOND_LIFE");
+ splash_msg = LLTrans::getString("StartupLoading", args);
+ LLSplashScreen::show();
+ LLSplashScreen::update(splash_msg);
+
+ //LLVolumeMgr::initClass();
+ LLVolumeMgr* volume_manager = new LLVolumeMgr();
+ volume_manager->useMutex(); // LLApp and LLMutex magic must be manually enabled
+ LLPrimitive::setVolumeManager(volume_manager);
+
+ // Note: this is where we used to initialize gFeatureManagerp.
+
+ gStartTime = totalTime();
+
+ //
+ // Set the name of the window
+ //
+ gWindowTitle = LLTrans::getString("APP_NAME");
+#if LL_DEBUG
+ gWindowTitle += std::string(" [DEBUG] ") + gArgs;
+#else
+ gWindowTitle += std::string(" ") + gArgs;
+#endif
+ LLStringUtil::truncate(gWindowTitle, 255);
+
+ //RN: if we received a URL, hand it off to the existing instance.
+ // don't call anotherInstanceRunning() when doing URL handoff, as
+ // it relies on checking a marker file which will not work when running
+ // out of different directories
+
+ if (LLStartUp::getStartSLURL().isValid())
+ {
+ if (sendURLToOtherInstance(LLStartUp::getStartSLURL().getSLURLString()))
+ {
+ // successfully handed off URL to existing instance, exit
+ return false;
+ }
+ }
+
+ if (!gSavedSettings.getBOOL("AllowMultipleViewers"))
+ {
+ //
+ // Check for another instance of the app running
+ //
+
+ mSecondInstance = anotherInstanceRunning();
+
+ if (mSecondInstance)
+ {
+ std::ostringstream msg;
+ msg << LLTrans::getString("MBAlreadyRunning");
+ OSMessageBox(
+ msg.str(),
+ LLStringUtil::null,
+ OSMB_OK);
+ return false;
+ }
+
+ initMarkerFile();
+
+ checkForCrash();
+ }
+ else
+ {
+ mSecondInstance = anotherInstanceRunning();
+
+ if (mSecondInstance)
+ {
+ // This is the second instance of SL. Turn off voice support,
+ // but make sure the setting is *not* persisted.
+ LLControlVariable* disable_voice = gSavedSettings.getControl("CmdLineDisableVoice");
+ if(disable_voice)
+ {
+ const BOOL DO_NOT_PERSIST = FALSE;
+ disable_voice->setValue(LLSD(TRUE), DO_NOT_PERSIST);
+ }
+ }
+
+ initMarkerFile();
+
+ if(!mSecondInstance)
+ {
+ checkForCrash();
+ }
+ }
+
+ // need to do this here - need to have initialized global settings first
+ std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" );
+ if ( !nextLoginLocation.empty() )
+ {
+ LLStartUp::setStartSLURL(LLSLURL(nextLoginLocation));
+ };
+
+ gLastRunVersion = gSavedSettings.getString("LastRunVersion");
+
+ loadColorSettings();
+
+ return true; // Config was successful.
+}
+
+namespace {
+ // *TODO - decide if there's a better place for these functions.
+ // do we need a file llupdaterui.cpp or something? -brad
+
+ void apply_update_callback(LLSD const & notification, LLSD const & response)
+ {
+ lldebugs << "LLUpdate user response: " << response << llendl;
+ if(response["OK_okcancelbuttons"].asBoolean())
+ {
+ llinfos << "LLUpdate restarting viewer" << llendl;
+ static const bool install_if_ready = true;
+ // *HACK - this lets us launch the installer immediately for now
+ LLUpdaterService().startChecking(install_if_ready);
+ }
+ }
+
+ void apply_update_ok_callback(LLSD const & notification, LLSD const & response)
+ {
+ llinfos << "LLUpdate restarting viewer" << llendl;
+ static const bool install_if_ready = true;
+ // *HACK - this lets us launch the installer immediately for now
+ LLUpdaterService().startChecking(install_if_ready);
+ }
+
+ void on_update_downloaded(LLSD const & data)
+ {
+ std::string notification_name;
+ void (*apply_callback)(LLSD const &, LLSD const &) = NULL;
+
+ if(data["required"].asBoolean())
+ {
+ if(LLStartUp::getStartupState() <= STATE_LOGIN_WAIT)
+ {
+ // The user never saw the progress bar.
+ apply_callback = &apply_update_ok_callback;
+ notification_name = "RequiredUpdateDownloadedVerboseDialog";
+ }
+ else if(LLStartUp::getStartupState() < STATE_WORLD_INIT)
+ {
+ // The user is logging in but blocked.
+ apply_callback = &apply_update_ok_callback;
+ notification_name = "RequiredUpdateDownloadedDialog";
+ }
+ else
+ {
+ // The user is already logged in; treat like an optional update.
+ apply_callback = &apply_update_callback;
+ notification_name = "DownloadBackgroundTip";
+ }
+ }
+ else
+ {
+ apply_callback = &apply_update_callback;
+ if(LLStartUp::getStartupState() < STATE_STARTED)
+ {
+ // CHOP-262 we need to use a different notification
+ // method prior to login.
+ notification_name = "DownloadBackgroundDialog";
+ }
+ else
+ {
+ notification_name = "DownloadBackgroundTip";
+ }
+ }
+
+ LLSD substitutions;
+ substitutions["VERSION"] = data["version"];
+
+ // truncate version at the rightmost '.'
+ std::string version_short(data["version"]);
+ size_t short_length = version_short.rfind('.');
+ if (short_length != std::string::npos)
+ {
+ version_short.resize(short_length);
+ }
+
+ LLUIString relnotes_url("[RELEASE_NOTES_BASE_URL][CHANNEL_URL]/[VERSION_SHORT]");
+ relnotes_url.setArg("[VERSION_SHORT]", version_short);
+
+ // *TODO thread the update service's response through to this point
+ std::string const & channel = LLVersionInfo::getChannel();
+ boost::shared_ptr<char> channel_escaped(curl_escape(channel.c_str(), channel.size()), &curl_free);
+
+ relnotes_url.setArg("[CHANNEL_URL]", channel_escaped.get());
+ relnotes_url.setArg("[RELEASE_NOTES_BASE_URL]", LLTrans::getString("RELEASE_NOTES_BASE_URL"));
+ substitutions["RELEASE_NOTES_FULL_URL"] = relnotes_url.getString();
+
+ LLNotificationsUtil::add(notification_name, substitutions, LLSD(), apply_callback);
+ }
+
+ void install_error_callback(LLSD const & notification, LLSD const & response)
+ {
+ LLAppViewer::instance()->forceQuit();
+ }
+
+ bool notify_update(LLSD const & evt)
+ {
+ std::string notification_name;
+ switch (evt["type"].asInteger())
+ {
+ case LLUpdaterService::DOWNLOAD_COMPLETE:
+ on_update_downloaded(evt);
+ break;
+ case LLUpdaterService::INSTALL_ERROR:
+ if(evt["required"].asBoolean()) {
+ LLNotificationsUtil::add("FailedRequiredUpdateInstall", LLSD(), LLSD(), &install_error_callback);
+ } else {
+ LLNotificationsUtil::add("FailedUpdateInstall");
+ }
+ break;
+ default:
+ break;
+ }
+
+ // let others also handle this event by default
+ return false;
+ }
+
+ bool on_bandwidth_throttle(LLUpdaterService * updater, LLSD const & evt)
+ {
+ updater->setBandwidthLimit(evt.asInteger() * (1024/8));
+ return false; // Let others receive this event.
+ };
+};
+
+void LLAppViewer::initUpdater()
+{
+ // Initialize the updater service.
+ // Generate URL to the udpater service
+ // Get Channel
+ // Get Version
+ std::string url = gSavedSettings.getString("UpdaterServiceURL");
+ std::string channel = LLVersionInfo::getChannel();
+ std::string version = LLVersionInfo::getVersion();
+ std::string protocol_version = gSavedSettings.getString("UpdaterServiceProtocolVersion");
+ std::string service_path = gSavedSettings.getString("UpdaterServicePath");
+ U32 check_period = gSavedSettings.getU32("UpdaterServiceCheckPeriod");
+
+ mUpdater->setAppExitCallback(boost::bind(&LLAppViewer::forceQuit, this));
+ mUpdater->initialize(protocol_version,
+ url,
+ service_path,
+ channel,
+ version);
+ mUpdater->setCheckPeriod(check_period);
+ mUpdater->setBandwidthLimit((int)gSavedSettings.getF32("UpdaterMaximumBandwidth") * (1024/8));
+ gSavedSettings.getControl("UpdaterMaximumBandwidth")->getSignal()->
+ connect(boost::bind(&on_bandwidth_throttle, mUpdater.get(), _2));
+ if(gSavedSettings.getU32("UpdaterServiceSetting"))
+ {
+ bool install_if_ready = true;
+ mUpdater->startChecking(install_if_ready);
+ }
+
+ LLEventPump & updater_pump = LLEventPumps::instance().obtain(LLUpdaterService::pumpName());
+ updater_pump.listen("notify_update", &notify_update);
+}
+
+void LLAppViewer::checkForCrash(void)
+{
+
+#if LL_SEND_CRASH_REPORTS
+ if (gLastExecEvent == LAST_EXEC_FROZE)
+ {
+ llinfos << "Last execution froze, requesting to send crash report." << llendl;
+ //
+ // Pop up a freeze or crash warning dialog
+ //
+ S32 choice;
+ if(gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) == CRASH_BEHAVIOR_ASK)
+ {
+ std::ostringstream msg;
+ msg << LLTrans::getString("MBFrozenCrashed");
+ std::string alert = LLTrans::getString("APP_NAME") + " " + LLTrans::getString("MBAlert");
+ choice = OSMessageBox(msg.str(),
+ alert,
+ OSMB_YESNO);
+ }
+ else if(gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) == CRASH_BEHAVIOR_NEVER_SEND)
+ {
+ choice = OSBTN_NO;
+ }
+ else
+ {
+ choice = OSBTN_YES;
+ }
+
+ if (OSBTN_YES == choice)
+ {
+ llinfos << "Sending crash report." << llendl;
+
+ bool report_freeze = true;
+ handleCrashReporting(report_freeze);
+ }
+ else
+ {
+ llinfos << "Not sending crash report." << llendl;
+ }
+ }
+#endif // LL_SEND_CRASH_REPORTS
+
+}
+
+bool LLAppViewer::initWindow()
+{
+ LL_INFOS("AppInit") << "Initializing window..." << LL_ENDL;
+
+ // store setting in a global for easy access and modification
+ gNoRender = gSavedSettings.getBOOL("DisableRendering");
+
+ // always start windowed
+ BOOL ignorePixelDepth = gSavedSettings.getBOOL("IgnorePixelDepth");
+ gViewerWindow = new LLViewerWindow(gWindowTitle,
+ VIEWER_WINDOW_CLASSNAME,
+ gSavedSettings.getS32("WindowX"), gSavedSettings.getS32("WindowY"),
+ gSavedSettings.getS32("WindowWidth"), gSavedSettings.getS32("WindowHeight"),
+ gSavedSettings.getBOOL("WindowFullScreen"), ignorePixelDepth);
+
+ // Need to load feature table before cheking to start watchdog.
+ const S32 NEVER_SUBMIT_REPORT = 2;
+ bool use_watchdog = false;
+ int watchdog_enabled_setting = gSavedSettings.getS32("WatchdogEnabled");
+ if(watchdog_enabled_setting == -1){
+ use_watchdog = !LLFeatureManager::getInstance()->isFeatureAvailable("WatchdogDisabled");
+ }
+ else
+ {
+ // The user has explicitly set this setting; always use that value.
+ use_watchdog = bool(watchdog_enabled_setting);
+ }
+
+ bool send_reports = gCrashSettings.getS32(CRASH_BEHAVIOR_SETTING) != NEVER_SUBMIT_REPORT;
+ if(use_watchdog && send_reports)
+ {
+ LLWatchdog::getInstance()->init(watchdog_killer_callback);
+ }
+
+ LLNotificationsUI::LLNotificationManager::getInstance();
+
+ if (gSavedSettings.getBOOL("WindowMaximized"))
+ {
+ gViewerWindow->mWindow->maximize();
+ }
+
+ if (!gNoRender)
+ {
+ //
+ // Initialize GL stuff
+ //
+
+ if (mForceGraphicsDetail)
+ {
+ LLFeatureManager::getInstance()->setGraphicsLevel(gSavedSettings.getU32("RenderQualityPerformance"), false);
+ }
+
+ // Set this flag in case we crash while initializing GL
+ gSavedSettings.setBOOL("RenderInitError", TRUE);
+ gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
+
+ gPipeline.init();
+ stop_glerror();
+ gViewerWindow->initGLDefaults();
+
+ gSavedSettings.setBOOL("RenderInitError", FALSE);
+ gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile"), TRUE );
+ }
+
+ //If we have a startup crash, it's usually near GL initialization, so simulate that.
+ if(gCrashOnStartup)
+ {
+ LLAppViewer::instance()->forceErrorLLError();
+ }
+
+ LLUI::sWindow = gViewerWindow->getWindow();
+
+ // Show watch cursor
+ gViewerWindow->setCursor(UI_CURSOR_WAIT);
+
+ // Finish view initialization
+ gViewerWindow->initBase();
+
+ // show viewer window
+ //gViewerWindow->mWindow->show();
+
+
+ return true;
+}
+
+void LLAppViewer::writeDebugInfo()
+{
+ std::string debug_filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,"debug_info.log");
+ llinfos << "Opening debug file " << debug_filename << llendl;
+ llofstream out_file(debug_filename);
+ LLSDSerialize::toPrettyXML(gDebugInfo, out_file);
+ out_file.close();
+}
+
+void LLAppViewer::cleanupSavedSettings()
+{
+ gSavedSettings.setBOOL("MouseSun", FALSE);
+
+ gSavedSettings.setBOOL("UseEnergy", TRUE); // force toggle to turn off, since sends message to simulator
+
+ gSavedSettings.setBOOL("DebugWindowProc", gDebugWindowProc);
+
+ gSavedSettings.setBOOL("ShowObjectUpdates", gShowObjectUpdates);
+
+ if (!gNoRender)
+ {
+ if (gDebugView)
+ {
+ gSavedSettings.setBOOL("ShowDebugConsole", gDebugView->mDebugConsolep->getVisible());
+ }
+ }
+
+ // save window position if not maximized
+ // as we don't track it in callbacks
+ if(NULL != gViewerWindow)
+ {
+ BOOL maximized = gViewerWindow->mWindow->getMaximized();
+ if (!maximized)
+ {
+ LLCoordScreen window_pos;
+
+ if (gViewerWindow->mWindow->getPosition(&window_pos))
+ {
+ gSavedSettings.setS32("WindowX", window_pos.mX);
+ gSavedSettings.setS32("WindowY", window_pos.mY);
+ }
+ }
+ }
+
+ gSavedSettings.setF32("MapScale", LLWorldMapView::sMapScale );
+
+ // Some things are cached in LLAgent.
+ if (gAgent.isInitialized())
+ {
+ gSavedSettings.setF32("RenderFarClip", gAgentCamera.mDrawDistance);
+ }
+}
+
+void LLAppViewer::removeCacheFiles(const std::string& file_mask)
+{
+ std::string mask = gDirUtilp->getDirDelimiter() + file_mask;
+ gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE, ""), mask);
+}
+
+void LLAppViewer::writeSystemInfo()
+{
+ gDebugInfo["SLLog"] = LLError::logFileName();
+
+ gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
+ gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
+ gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
+ gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
+ gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
+
+ gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
+
+ gDebugInfo["CPUInfo"]["CPUString"] = gSysCPU.getCPUString();
+ gDebugInfo["CPUInfo"]["CPUFamily"] = gSysCPU.getFamily();
+ gDebugInfo["CPUInfo"]["CPUMhz"] = (S32)gSysCPU.getMHz();
+ gDebugInfo["CPUInfo"]["CPUAltivec"] = gSysCPU.hasAltivec();
+ gDebugInfo["CPUInfo"]["CPUSSE"] = gSysCPU.hasSSE();
+ gDebugInfo["CPUInfo"]["CPUSSE2"] = gSysCPU.hasSSE2();
+
+ gDebugInfo["RAMInfo"]["Physical"] = (LLSD::Integer)(gSysMemory.getPhysicalMemoryKB());
+ gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer)(gMemoryAllocated>>10); // MB -> KB
+ gDebugInfo["OSInfo"] = getOSInfo().getOSStringSimple();
+
+ // The user is not logged on yet, but record the current grid choice login url
+ // which may have been the intended grid. This can b
+ gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel();
+
+ // *FIX:Mani - move this down in llappviewerwin32
+#ifdef LL_WINDOWS
+ DWORD thread_id = GetCurrentThreadId();
+ gDebugInfo["MainloopThreadID"] = (S32)thread_id;
+#endif
+
+ // "CrashNotHandled" is set here, while things are running well,
+ // in case of a freeze. If there is a freeze, the crash logger will be launched
+ // and can read this value from the debug_info.log.
+ // If the crash is handled by LLAppViewer::handleViewerCrash, ie not a freeze,
+ // then the value of "CrashNotHandled" will be set to true.
+ gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)true;
+
+ // Insert crash host url (url to post crash log to) if configured. This insures
+ // that the crash report will go to the proper location in the case of a
+ // prior freeze.
+ std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
+ if(crashHostUrl != "")
+ {
+ gDebugInfo["CrashHostUrl"] = crashHostUrl;
+ }
+
+ // Dump some debugging info
+ LL_INFOS("SystemInfo") << LLTrans::getString("APP_NAME")
+ << " version " << LLVersionInfo::getShortVersion() << LL_ENDL;
+
+ // Dump the local time and time zone
+ time_t now;
+ time(&now);
+ char tbuffer[256]; /* Flawfinder: ignore */
+ strftime(tbuffer, 256, "%Y-%m-%dT%H:%M:%S %Z", localtime(&now));
+ LL_INFOS("SystemInfo") << "Local time: " << tbuffer << LL_ENDL;
+
+ // query some system information
+ LL_INFOS("SystemInfo") << "CPU info:\n" << gSysCPU << LL_ENDL;
+ LL_INFOS("SystemInfo") << "Memory info:\n" << gSysMemory << LL_ENDL;
+ LL_INFOS("SystemInfo") << "OS: " << getOSInfo().getOSStringSimple() << LL_ENDL;
+ LL_INFOS("SystemInfo") << "OS info: " << getOSInfo() << LL_ENDL;
+
+ writeDebugInfo(); // Save out debug_info.log early, in case of crash.
+}
+
+void LLAppViewer::handleViewerCrash()
+{
+ llinfos << "Handle viewer crash entry." << llendl;
+
+ llinfos << "Last render pool type: " << LLPipeline::sCurRenderPoolType << llendl ;
+
+ //print out recorded call stacks if there are any.
+ LLError::LLCallStacks::print();
+
+ LLAppViewer* pApp = LLAppViewer::instance();
+ if (pApp->beingDebugged())
+ {
+ // This will drop us into the debugger.
+ abort();
+ }
+
+ if (LLApp::isCrashloggerDisabled())
+ {
+ abort();
+ }
+
+ // Returns whether a dialog was shown.
+ // Only do the logic in here once
+ if (pApp->mReportedCrash)
+ {
+ return;
+ }
+ pApp->mReportedCrash = TRUE;
+
+ // Insert crash host url (url to post crash log to) if configured.
+ std::string crashHostUrl = gSavedSettings.get<std::string>("CrashHostUrl");
+ if(crashHostUrl != "")
+ {
+ gDebugInfo["CrashHostUrl"] = crashHostUrl;
+ }
+
+ //We already do this in writeSystemInfo(), but we do it again here to make /sure/ we have a version
+ //to check against no matter what
+ gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
+
+ gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
+ gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
+ gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
+ gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
+
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if ( parcel && parcel->getMusicURL()[0])
+ {
+ gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL();
+ }
+ if ( parcel && parcel->getMediaURL()[0])
+ {
+ gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL();
+ }
+
+
+ gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile");
+ gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
+ gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();
+ gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath();
+ gDebugInfo["SessionLength"] = F32(LLFrameTimer::getElapsedSeconds());
+ gDebugInfo["StartupState"] = LLStartUp::getStartupStateString();
+ gDebugInfo["RAMInfo"]["Allocated"] = (LLSD::Integer) LLMemory::getCurrentRSS() >> 10;
+ gDebugInfo["FirstLogin"] = (LLSD::Boolean) gAgent.isFirstLogin();
+ gDebugInfo["FirstRunThisInstall"] = gSavedSettings.getBOOL("FirstRunThisInstall");
+
+ char *minidump_file = pApp->getMiniDumpFilename();
+ if(minidump_file && minidump_file[0] != 0)
+ {
+ gDebugInfo["MinidumpPath"] = minidump_file;
+ }
+
+ if(gLogoutInProgress)
+ {
+ gDebugInfo["LastExecEvent"] = LAST_EXEC_LOGOUT_CRASH;
+ }
+ else
+ {
+ gDebugInfo["LastExecEvent"] = gLLErrorActivated ? LAST_EXEC_LLERROR_CRASH : LAST_EXEC_OTHER_CRASH;
+ }
+
+ if(gAgent.getRegion())
+ {
+ gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName();
+ gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName();
+
+ const LLVector3& loc = gAgent.getPositionAgent();
+ gDebugInfo["CurrentLocationX"] = loc.mV[0];
+ gDebugInfo["CurrentLocationY"] = loc.mV[1];
+ gDebugInfo["CurrentLocationZ"] = loc.mV[2];
+ }
+
+ if(LLAppViewer::instance()->mMainloopTimeout)
+ {
+ gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
+ }
+
+ // The crash is being handled here so set this value to false.
+ // Otherwise the crash logger will think this crash was a freeze.
+ gDebugInfo["CrashNotHandled"] = (LLSD::Boolean)false;
+
+ //Write out the crash status file
+ //Use marker file style setup, as that's the simplest, especially since
+ //we're already in a crash situation
+ if (gDirUtilp)
+ {
+ std::string crash_file_name;
+ if(gLLErrorActivated) crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LLERROR_MARKER_FILE_NAME);
+ else crash_file_name = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,ERROR_MARKER_FILE_NAME);
+ llinfos << "Creating crash marker file " << crash_file_name << llendl;
+
+ LLAPRFile crash_file ;
+ crash_file.open(crash_file_name, LL_APR_W);
+ if (crash_file.getFileHandle())
+ {
+ LL_INFOS("MarkerFile") << "Created crash marker file " << crash_file_name << LL_ENDL;
+ }
+ else
+ {
+ LL_WARNS("MarkerFile") << "Cannot create error marker file " << crash_file_name << LL_ENDL;
+ }
+ }
+
+ if (gMessageSystem && gDirUtilp)
+ {
+ std::string filename;
+ filename = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, "stats.log");
+ llofstream file(filename, llofstream::binary);
+ if(file.good())
+ {
+ llinfos << "Handle viewer crash generating stats log." << llendl;
+ gMessageSystem->summarizeLogs(file);
+ file.close();
+ }
+ }
+
+ if (gMessageSystem)
+ {
+ gMessageSystem->getCircuitInfo(gDebugInfo["CircuitInfo"]);
+ gMessageSystem->stopLogging();
+ }
+
+ if (LLWorld::instanceExists()) LLWorld::getInstance()->getInfo(gDebugInfo);
+
+ // Close the debug file
+ pApp->writeDebugInfo();
+
+ LLError::logToFile("");
+
+ // Remove the marker file, since otherwise we'll spawn a process that'll keep it locked
+ if(gDebugInfo["LastExecEvent"].asInteger() == LAST_EXEC_LOGOUT_CRASH)
+ {
+ pApp->removeMarkerFile(true);
+ }
+ else
+ {
+ pApp->removeMarkerFile(false);
+ }
+
+#if LL_SEND_CRASH_REPORTS
+ // Call to pure virtual, handled by platform specific llappviewer instance.
+ pApp->handleCrashReporting();
+#endif
+
+ return;
+}
+
+bool LLAppViewer::anotherInstanceRunning()
+{
+ // We create a marker file when the program starts and remove the file when it finishes.
+ // If the file is currently locked, that means another process is already running.
+
+ std::string marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, MARKER_FILE_NAME);
+ LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
+
+ //Freeze case checks
+ if (LLAPRFile::isExist(marker_file, NULL, LL_APR_RB))
+ {
+ // File exists, try opening with write permissions
+ LLAPRFile outfile ;
+ outfile.open(marker_file, LL_APR_WB);
+ apr_file_t* fMarker = outfile.getFileHandle() ;
+ if (!fMarker)
+ {
+ // Another instance is running. Skip the rest of these operations.
+ LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
+ return true;
+ }
+ if (apr_file_lock(fMarker, APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS) //flock(fileno(fMarker), LOCK_EX | LOCK_NB) == -1)
+ {
+ LL_INFOS("MarkerFile") << "Marker file is locked." << LL_ENDL;
+ return true;
+ }
+ // No other instances; we'll lock this file now & delete on quit.
+ }
+ LL_DEBUGS("MarkerFile") << "Marker file isn't locked." << LL_ENDL;
+ return false;
+}
+
+void LLAppViewer::initMarkerFile()
+{
+ //First, check for the existence of other files.
+ //There are marker files for two different types of crashes
+
+ mMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,MARKER_FILE_NAME);
+ LL_DEBUGS("MarkerFile") << "Checking marker file for lock..." << LL_ENDL;
+
+ //We've got 4 things to test for here
+ // - Other Process Running (SecondLife.exec_marker present, locked)
+ // - Freeze (SecondLife.exec_marker present, not locked)
+ // - LLError Crash (SecondLife.llerror_marker present)
+ // - Other Crash (SecondLife.error_marker present)
+ // These checks should also remove these files for the last 2 cases if they currently exist
+
+ //LLError/Error checks. Only one of these should ever happen at a time.
+ std::string logout_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LOGOUT_MARKER_FILE_NAME);
+ std::string llerror_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, LLERROR_MARKER_FILE_NAME);
+ std::string error_marker_file = gDirUtilp->getExpandedFilename(LL_PATH_LOGS, ERROR_MARKER_FILE_NAME);
+
+ if (LLAPRFile::isExist(mMarkerFileName, NULL, LL_APR_RB) && !anotherInstanceRunning())
+ {
+ gLastExecEvent = LAST_EXEC_FROZE;
+ LL_INFOS("MarkerFile") << "Exec marker found: program froze on previous execution" << LL_ENDL;
+ }
+ if(LLAPRFile::isExist(logout_marker_file, NULL, LL_APR_RB))
+ {
+ gLastExecEvent = LAST_EXEC_LOGOUT_FROZE;
+ LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+ LLAPRFile::remove(logout_marker_file);
+ }
+ if(LLAPRFile::isExist(llerror_marker_file, NULL, LL_APR_RB))
+ {
+ if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
+ else gLastExecEvent = LAST_EXEC_LLERROR_CRASH;
+ LL_INFOS("MarkerFile") << "Last exec LLError crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+ LLAPRFile::remove(llerror_marker_file);
+ }
+ if(LLAPRFile::isExist(error_marker_file, NULL, LL_APR_RB))
+ {
+ if(gLastExecEvent == LAST_EXEC_LOGOUT_FROZE) gLastExecEvent = LAST_EXEC_LOGOUT_CRASH;
+ else gLastExecEvent = LAST_EXEC_OTHER_CRASH;
+ LL_INFOS("MarkerFile") << "Last exec crashed, setting LastExecEvent to " << gLastExecEvent << LL_ENDL;
+ LLAPRFile::remove(error_marker_file);
+ }
+
+ // No new markers if another instance is running.
+ if(anotherInstanceRunning())
+ {
+ return;
+ }
+
+ // Create the marker file for this execution & lock it
+ apr_status_t s;
+ s = mMarkerFile.open(mMarkerFileName, LL_APR_W, TRUE);
+
+ if (s == APR_SUCCESS && mMarkerFile.getFileHandle())
+ {
+ LL_DEBUGS("MarkerFile") << "Marker file created." << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS("MarkerFile") << "Failed to create marker file." << LL_ENDL;
+ return;
+ }
+ if (apr_file_lock(mMarkerFile.getFileHandle(), APR_FLOCK_NONBLOCK | APR_FLOCK_EXCLUSIVE) != APR_SUCCESS)
+ {
+ mMarkerFile.close() ;
+ LL_INFOS("MarkerFile") << "Marker file cannot be locked." << LL_ENDL;
+ return;
+ }
+
+ LL_DEBUGS("MarkerFile") << "Marker file locked." << LL_ENDL;
+}
+
+void LLAppViewer::removeMarkerFile(bool leave_logout_marker)
+{
+ LL_DEBUGS("MarkerFile") << "removeMarkerFile()" << LL_ENDL;
+ if (mMarkerFile.getFileHandle())
+ {
+ mMarkerFile.close() ;
+ LLAPRFile::remove( mMarkerFileName );
+ }
+ if (mLogoutMarkerFile != NULL && !leave_logout_marker)
+ {
+ LLAPRFile::remove( mLogoutMarkerFileName );
+ mLogoutMarkerFile = NULL;
+ }
+}
+
+void LLAppViewer::forceQuit()
+{
+ LLApp::setQuitting();
+}
+
+//TODO: remove
+void LLAppViewer::fastQuit(S32 error_code)
+{
+ // finish pending transfers
+ flushVFSIO();
+ // let sim know we're logging out
+ sendLogoutRequest();
+ // flush network buffers by shutting down messaging system
+ end_messaging_system();
+ // figure out the error code
+ S32 final_error_code = error_code ? error_code : (S32)isError();
+ // this isn't a crash
+ removeMarkerFile();
+ // get outta here
+ _exit(final_error_code);
+}
+
+void LLAppViewer::requestQuit()
+{
+ llinfos << "requestQuit" << llendl;
+
+ LLViewerRegion* region = gAgent.getRegion();
+
+ if( (LLStartUp::getStartupState() < STATE_STARTED) || !region )
+ {
+ // If we have a region, make some attempt to send a logout request first.
+ // This prevents the halfway-logged-in avatar from hanging around inworld for a couple minutes.
+ if(region)
+ {
+ sendLogoutRequest();
+ }
+
+ // Quit immediately
+ forceQuit();
+ return;
+ }
+
+ // Try to send metrics back to the grid
+ metricsSend(!gDisconnected);
+
+ LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
+ effectp->setPositionGlobal(gAgent.getPositionGlobal());
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ LLHUDManager::getInstance()->sendEffects();
+ effectp->markDead() ;//remove it.
+
+ // Attempt to close all floaters that might be
+ // editing things.
+ if (gFloaterView)
+ {
+ // application is quitting
+ gFloaterView->closeAllChildren(true);
+ }
+
+ LLSideTray::getInstance()->notifyChildren(LLSD().with("request","quit"));
+
+ send_stats();
+
+ gLogoutTimer.reset();
+ mQuitRequested = true;
+}
+
+static bool finish_quit(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ if (option == 0)
+ {
+ LLAppViewer::instance()->requestQuit();
+ }
+ return false;
+}
+static LLNotificationFunctorRegistration finish_quit_reg("ConfirmQuit", finish_quit);
+
+static bool switch_standard_skin_and_quit(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ if (option == 0)
+ {
+ gSavedSettings.setString("SessionSettingsFile", "");
+ LLAppViewer::instance()->requestQuit();
+ }
+ return false;
+}
+
+static LLNotificationFunctorRegistration standard_skin_quit_reg("SwitchToStandardSkinAndQuit", switch_standard_skin_and_quit);
+
+void LLAppViewer::userQuit()
+{
+ if (gDisconnected || gViewerWindow->getProgressView()->getVisible())
+ {
+ requestQuit();
+ }
+ else
+ {
+ LLNotificationsUtil::add("ConfirmQuit");
+ }
+}
+
+static bool finish_early_exit(const LLSD& notification, const LLSD& response)
+{
+ LLAppViewer::instance()->forceQuit();
+ return false;
+}
+
+void LLAppViewer::earlyExit(const std::string& name, const LLSD& substitutions)
+{
+ llwarns << "app_early_exit: " << name << llendl;
+ gDoDisconnect = TRUE;
+ LLNotificationsUtil::add(name, substitutions, LLSD(), finish_early_exit);
+}
+
+// case where we need the viewer to exit without any need for notifications
+void LLAppViewer::earlyExitNoNotify()
+{
+ llwarns << "app_early_exit with no notification: " << llendl;
+ gDoDisconnect = TRUE;
+ finish_early_exit( LLSD(), LLSD() );
+}
+
+void LLAppViewer::abortQuit()
+{
+ llinfos << "abortQuit()" << llendl;
+ mQuitRequested = false;
+}
+
+void LLAppViewer::migrateCacheDirectory()
+{
+#if LL_WINDOWS || LL_DARWIN
+ // NOTE: (Nyx) as of 1.21, cache for mac is moving to /library/caches/SecondLife from
+ // /library/application support/SecondLife/cache This should clear/delete the old dir.
+
+ // As of 1.23 the Windows cache moved from
+ // C:\Documents and Settings\James\Application Support\SecondLife\cache
+ // to
+ // C:\Documents and Settings\James\Local Settings\Application Support\SecondLife
+ //
+ // The Windows Vista equivalent is from
+ // C:\Users\James\AppData\Roaming\SecondLife\cache
+ // to
+ // C:\Users\James\AppData\Local\SecondLife
+ //
+ // Note the absence of \cache on the second path. James.
+
+ // Only do this once per fresh install of this version.
+ if (gSavedSettings.getBOOL("MigrateCacheDirectory"))
+ {
+ gSavedSettings.setBOOL("MigrateCacheDirectory", FALSE);
+
+ std::string delimiter = gDirUtilp->getDirDelimiter();
+ std::string old_cache_dir = gDirUtilp->getOSUserAppDir() + delimiter + "cache";
+ std::string new_cache_dir = gDirUtilp->getCacheDir(true);
+
+ if (gDirUtilp->fileExists(old_cache_dir))
+ {
+ llinfos << "Migrating cache from " << old_cache_dir << " to " << new_cache_dir << llendl;
+
+ // Migrate inventory cache to avoid pain to inventory database after mass update
+ S32 file_count = 0;
+ std::string file_name;
+ std::string mask = delimiter + "*.*";
+ while (gDirUtilp->getNextFileInDir(old_cache_dir, mask, file_name))
+ {
+ if (file_name == "." || file_name == "..") continue;
+ std::string source_path = old_cache_dir + delimiter + file_name;
+ std::string dest_path = new_cache_dir + delimiter + file_name;
+ if (!LLFile::rename(source_path, dest_path))
+ {
+ file_count++;
+ }
+ }
+ llinfos << "Moved " << file_count << " files" << llendl;
+
+ // Nuke the old cache
+ gDirUtilp->setCacheDir(old_cache_dir);
+ purgeCache();
+ gDirUtilp->setCacheDir(new_cache_dir);
+
+#if LL_DARWIN
+ // Clean up Mac files not deleted by removing *.*
+ std::string ds_store = old_cache_dir + "/.DS_Store";
+ if (gDirUtilp->fileExists(ds_store))
+ {
+ LLFile::remove(ds_store);
+ }
+#endif
+ if (LLFile::rmdir(old_cache_dir) != 0)
+ {
+ llwarns << "could not delete old cache directory " << old_cache_dir << llendl;
+ }
+ }
+ }
+#endif // LL_WINDOWS || LL_DARWIN
+}
+
+void dumpVFSCaches()
+{
+ llinfos << "======= Static VFS ========" << llendl;
+ gStaticVFS->listFiles();
+#if LL_WINDOWS
+ llinfos << "======= Dumping static VFS to StaticVFSDump ========" << llendl;
+ WCHAR w_str[MAX_PATH];
+ GetCurrentDirectory(MAX_PATH, w_str);
+ S32 res = LLFile::mkdir("StaticVFSDump");
+ if (res == -1)
+ {
+ if (errno != EEXIST)
+ {
+ llwarns << "Couldn't create dir StaticVFSDump" << llendl;
+ }
+ }
+ SetCurrentDirectory(utf8str_to_utf16str("StaticVFSDump").c_str());
+ gStaticVFS->dumpFiles();
+ SetCurrentDirectory(w_str);
+#endif
+
+ llinfos << "========= Dynamic VFS ====" << llendl;
+ gVFS->listFiles();
+#if LL_WINDOWS
+ llinfos << "========= Dumping dynamic VFS to VFSDump ====" << llendl;
+ res = LLFile::mkdir("VFSDump");
+ if (res == -1)
+ {
+ if (errno != EEXIST)
+ {
+ llwarns << "Couldn't create dir VFSDump" << llendl;
+ }
+ }
+ SetCurrentDirectory(utf8str_to_utf16str("VFSDump").c_str());
+ gVFS->dumpFiles();
+ SetCurrentDirectory(w_str);
+#endif
+}
+
+//static
+U32 LLAppViewer::getTextureCacheVersion()
+{
+ //viewer texture cache version, change if the texture cache format changes.
+ const U32 TEXTURE_CACHE_VERSION = 7;
+
+ return TEXTURE_CACHE_VERSION ;
+}
+
+//static
+U32 LLAppViewer::getObjectCacheVersion()
+{
+ // Viewer object cache version, change if object update
+ // format changes. JC
+ const U32 INDRA_OBJECT_CACHE_VERSION = 14;
+
+ return INDRA_OBJECT_CACHE_VERSION;
+}
+
+bool LLAppViewer::initCache()
+{
+ mPurgeCache = false;
+ BOOL read_only = mSecondInstance ? TRUE : FALSE;
+ LLAppViewer::getTextureCache()->setReadOnly(read_only) ;
+ LLVOCache::getInstance()->setReadOnly(read_only);
+
+ BOOL texture_cache_mismatch = FALSE ;
+ if (gSavedSettings.getS32("LocalCacheVersion") != LLAppViewer::getTextureCacheVersion())
+ {
+ texture_cache_mismatch = TRUE ;
+ if(!read_only)
+ {
+ gSavedSettings.setS32("LocalCacheVersion", LLAppViewer::getTextureCacheVersion());
+ }
+ }
+
+ if(!read_only)
+ {
+ // Purge cache if user requested it
+ if (gSavedSettings.getBOOL("PurgeCacheOnStartup") ||
+ gSavedSettings.getBOOL("PurgeCacheOnNextStartup"))
+ {
+ gSavedSettings.setBOOL("PurgeCacheOnNextStartup", false);
+ mPurgeCache = true;
+ }
+
+ // We have moved the location of the cache directory over time.
+ migrateCacheDirectory();
+
+ // Setup and verify the cache location
+ std::string cache_location = gSavedSettings.getString("CacheLocation");
+ std::string new_cache_location = gSavedSettings.getString("NewCacheLocation");
+ if (new_cache_location != cache_location)
+ {
+ gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation"));
+ purgeCache(); // purge old cache
+ gSavedSettings.setString("CacheLocation", new_cache_location);
+ gSavedSettings.setString("CacheLocationTopFolder", gDirUtilp->getBaseFileName(new_cache_location));
+ }
+ }
+
+ if (!gDirUtilp->setCacheDir(gSavedSettings.getString("CacheLocation")))
+ {
+ LL_WARNS("AppCache") << "Unable to set cache location" << LL_ENDL;
+ gSavedSettings.setString("CacheLocation", "");
+ gSavedSettings.setString("CacheLocationTopFolder", "");
+ }
+
+ if (mPurgeCache && !read_only)
+ {
+ LLSplashScreen::update(LLTrans::getString("StartupClearingCache"));
+ purgeCache();
+ }
+
+ LLSplashScreen::update(LLTrans::getString("StartupInitializingTextureCache"));
+
+ // Init the texture cache
+ // Allocate 80% of the cache size for textures
+ const S32 MB = 1024*1024;
+ S64 cache_size = (S64)(gSavedSettings.getU32("CacheSize")) * MB;
+ const S64 MAX_CACHE_SIZE = 1024*MB;
+ cache_size = llmin(cache_size, MAX_CACHE_SIZE);
+ S64 texture_cache_size = ((cache_size * 8)/10);
+ S64 extra = LLAppViewer::getTextureCache()->initCache(LL_PATH_CACHE, texture_cache_size, texture_cache_mismatch);
+ texture_cache_size -= extra;
+
+ LLVOCache::getInstance()->initCache(LL_PATH_CACHE, gSavedSettings.getU32("CacheNumberOfRegionsForObjects"), getObjectCacheVersion()) ;
+
+ LLSplashScreen::update(LLTrans::getString("StartupInitializingVFS"));
+
+ // Init the VFS
+ S64 vfs_size = cache_size - texture_cache_size;
+ const S64 MAX_VFS_SIZE = 1024 * MB; // 1 GB
+ vfs_size = llmin(vfs_size, MAX_VFS_SIZE);
+ vfs_size = (vfs_size / MB) * MB; // make sure it is MB aligned
+ U32 vfs_size_u32 = (U32)vfs_size;
+ U32 old_vfs_size = gSavedSettings.getU32("VFSOldSize") * MB;
+ bool resize_vfs = (vfs_size_u32 != old_vfs_size);
+ if (resize_vfs)
+ {
+ gSavedSettings.setU32("VFSOldSize", vfs_size_u32/MB);
+ }
+ LL_INFOS("AppCache") << "VFS CACHE SIZE: " << vfs_size/(1024*1024) << " MB" << LL_ENDL;
+
+ // This has to happen BEFORE starting the vfs
+ //time_t ltime;
+ srand(time(NULL)); // Flawfinder: ignore
+ U32 old_salt = gSavedSettings.getU32("VFSSalt");
+ U32 new_salt;
+ std::string old_vfs_data_file;
+ std::string old_vfs_index_file;
+ std::string new_vfs_data_file;
+ std::string new_vfs_index_file;
+ std::string static_vfs_index_file;
+ std::string static_vfs_data_file;
+
+ if (gSavedSettings.getBOOL("AllowMultipleViewers"))
+ {
+ // don't mess with renaming the VFS in this case
+ new_salt = old_salt;
+ }
+ else
+ {
+ do
+ {
+ new_salt = rand();
+ } while( new_salt == old_salt );
+ }
+
+ old_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE) + llformat("%u",old_salt);
+
+ // make sure this file exists
+ llstat s;
+ S32 stat_result = LLFile::stat(old_vfs_data_file, &s);
+ if (stat_result)
+ {
+ // doesn't exist, look for a data file
+ std::string mask;
+ mask = gDirUtilp->getDirDelimiter();
+ mask += VFS_DATA_FILE_BASE;
+ mask += "*";
+
+ std::string dir;
+ dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
+
+ std::string found_file;
+ if (gDirUtilp->getNextFileInDir(dir, mask, found_file))
+ {
+ old_vfs_data_file = dir + gDirUtilp->getDirDelimiter() + found_file;
+
+ S32 start_pos = found_file.find_last_of('.');
+ if (start_pos > 0)
+ {
+ sscanf(found_file.substr(start_pos+1).c_str(), "%d", &old_salt);
+ }
+ LL_DEBUGS("AppCache") << "Default vfs data file not present, found: " << old_vfs_data_file << " Old salt: " << old_salt << llendl;
+ }
+ }
+
+ old_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_INDEX_FILE_BASE) + llformat("%u",old_salt);
+
+ stat_result = LLFile::stat(old_vfs_index_file, &s);
+ if (stat_result)
+ {
+ // We've got a bad/missing index file, nukem!
+ LL_WARNS("AppCache") << "Bad or missing vfx index file " << old_vfs_index_file << LL_ENDL;
+ LL_WARNS("AppCache") << "Removing old vfs data file " << old_vfs_data_file << LL_ENDL;
+ LLFile::remove(old_vfs_data_file);
+ LLFile::remove(old_vfs_index_file);
+
+ // Just in case, nuke any other old cache files in the directory.
+ std::string dir;
+ dir = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,"");
+
+ std::string mask;
+ mask = gDirUtilp->getDirDelimiter();
+ mask += VFS_DATA_FILE_BASE;
+ mask += "*";
+
+ gDirUtilp->deleteFilesInDir(dir, mask);
+
+ mask = gDirUtilp->getDirDelimiter();
+ mask += VFS_INDEX_FILE_BASE;
+ mask += "*";
+
+ gDirUtilp->deleteFilesInDir(dir, mask);
+ }
+
+ new_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE,VFS_DATA_FILE_BASE) + llformat("%u",new_salt);
+ new_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, VFS_INDEX_FILE_BASE) + llformat("%u",new_salt);
+
+ static_vfs_data_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_data.db2");
+ static_vfs_index_file = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"static_index.db2");
+
+ if (resize_vfs)
+ {
+ LL_DEBUGS("AppCache") << "Removing old vfs and re-sizing" << LL_ENDL;
+
+ LLFile::remove(old_vfs_data_file);
+ LLFile::remove(old_vfs_index_file);
+ }
+ else if (old_salt != new_salt)
+ {
+ // move the vfs files to a new name before opening
+ LL_DEBUGS("AppCache") << "Renaming " << old_vfs_data_file << " to " << new_vfs_data_file << LL_ENDL;
+ LL_DEBUGS("AppCache") << "Renaming " << old_vfs_index_file << " to " << new_vfs_index_file << LL_ENDL;
+ LLFile::rename(old_vfs_data_file, new_vfs_data_file);
+ LLFile::rename(old_vfs_index_file, new_vfs_index_file);
+ }
+
+ // Startup the VFS...
+ gSavedSettings.setU32("VFSSalt", new_salt);
+
+ // Don't remove VFS after viewer crashes. If user has corrupt data, they can reinstall. JC
+ gVFS = LLVFS::createLLVFS(new_vfs_index_file, new_vfs_data_file, false, vfs_size_u32, false);
+ if( !gVFS )
+ {
+ return false;
+ }
+
+ gStaticVFS = LLVFS::createLLVFS(static_vfs_index_file, static_vfs_data_file, true, 0, false);
+ if( !gStaticVFS )
+ {
+ return false;
+ }
+
+ BOOL success = gVFS->isValid() && gStaticVFS->isValid();
+ if( !success )
+ {
+ return false;
+ }
+ else
+ {
+ LLVFile::initClass();
+
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ if (gSavedSettings.getBOOL("DumpVFSCaches"))
+ {
+ dumpVFSCaches();
+ }
+#endif
+
+ return true;
+ }
+}
+
+void LLAppViewer::purgeCache()
+{
+ LL_INFOS("AppCache") << "Purging Cache and Texture Cache..." << llendl;
+ LLAppViewer::getTextureCache()->purgeCache(LL_PATH_CACHE);
+ LLVOCache::getInstance()->removeCache(LL_PATH_CACHE);
+ std::string mask = gDirUtilp->getDirDelimiter() + "*.*";
+ gDirUtilp->deleteFilesInDir(gDirUtilp->getExpandedFilename(LL_PATH_CACHE,""),mask);
+}
+
+std::string LLAppViewer::getSecondLifeTitle() const
+{
+ return LLTrans::getString("APP_NAME");
+}
+
+std::string LLAppViewer::getWindowTitle() const
+{
+ return gWindowTitle;
+}
+
+// Callback from a dialog indicating user was logged out.
+bool finish_disconnect(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ if (1 == option)
+ {
+ LLAppViewer::instance()->forceQuit();
+ }
+ return false;
+}
+
+// Callback from an early disconnect dialog, force an exit
+bool finish_forced_disconnect(const LLSD& notification, const LLSD& response)
+{
+ LLAppViewer::instance()->forceQuit();
+ return false;
+}
+
+
+void LLAppViewer::forceDisconnect(const std::string& mesg)
+{
+ if (gDoDisconnect)
+ {
+ // Already popped up one of these dialogs, don't
+ // do this again.
+ return;
+ }
+
+ // *TODO: Translate the message if possible
+ std::string big_reason = LLAgent::sTeleportErrorMessages[mesg];
+ if ( big_reason.size() == 0 )
+ {
+ big_reason = mesg;
+ }
+
+ LLSD args;
+ gDoDisconnect = TRUE;
+
+ if (LLStartUp::getStartupState() < STATE_STARTED)
+ {
+ // Tell users what happened
+ args["ERROR_MESSAGE"] = big_reason;
+ LLNotificationsUtil::add("ErrorMessage", args, LLSD(), &finish_forced_disconnect);
+ }
+ else
+ {
+ args["MESSAGE"] = big_reason;
+ LLNotificationsUtil::add("YouHaveBeenLoggedOut", args, LLSD(), &finish_disconnect );
+ }
+}
+
+void LLAppViewer::badNetworkHandler()
+{
+ // Dump the packet
+ gMessageSystem->dumpPacketToLog();
+
+ // Flush all of our caches on exit in the case of disconnect due to
+ // invalid packets.
+
+ mPurgeOnExit = TRUE;
+
+ std::ostringstream message;
+ message <<
+ "The viewer has detected mangled network data indicative\n"
+ "of a bad upstream network connection or an incomplete\n"
+ "local installation of " << LLAppViewer::instance()->getSecondLifeTitle() << ". \n"
+ " \n"
+ "Try uninstalling and reinstalling to see if this resolves \n"
+ "the issue. \n"
+ " \n"
+ "If the problem continues, see the Tech Support FAQ at: \n"
+ "www.secondlife.com/support";
+ forceDisconnect(message.str());
+
+ LLApp::instance()->writeMiniDump();
+}
+
+// This routine may get called more than once during the shutdown process.
+// This can happen because we need to get the screenshot before the window
+// is destroyed.
+void LLAppViewer::saveFinalSnapshot()
+{
+ if (!mSavedFinalSnapshot && !gNoRender)
+ {
+ gSavedSettings.setVector3d("FocusPosOnLogout", gAgentCamera.calcFocusPositionTargetGlobal());
+ gSavedSettings.setVector3d("CameraPosOnLogout", gAgentCamera.calcCameraPositionTargetGlobal());
+ gViewerWindow->setCursor(UI_CURSOR_WAIT);
+ gAgentCamera.changeCameraToThirdPerson( FALSE ); // don't animate, need immediate switch
+ gSavedSettings.setBOOL("ShowParcelOwners", FALSE);
+ idle();
+
+ std::string snap_filename = gDirUtilp->getLindenUserDir();
+ snap_filename += gDirUtilp->getDirDelimiter();
+ snap_filename += SCREEN_LAST_FILENAME;
+ // use full pixel dimensions of viewer window (not post-scale dimensions)
+ gViewerWindow->saveSnapshot(snap_filename, gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw(), FALSE, TRUE);
+ mSavedFinalSnapshot = TRUE;
+ }
+}
+
+void LLAppViewer::loadNameCache()
+{
+ // display names cache
+ std::string filename =
+ gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
+ LL_INFOS("AvNameCache") << filename << LL_ENDL;
+ llifstream name_cache_stream(filename);
+ if(name_cache_stream.is_open())
+ {
+ LLAvatarNameCache::importFile(name_cache_stream);
+ }
+
+ if (!gCacheName) return;
+
+ std::string name_cache;
+ name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
+ llifstream cache_file(name_cache);
+ if(cache_file.is_open())
+ {
+ if(gCacheName->importFile(cache_file)) return;
+ }
+}
+
+void LLAppViewer::saveNameCache()
+ {
+ // display names cache
+ std::string filename =
+ gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "avatar_name_cache.xml");
+ llofstream name_cache_stream(filename);
+ if(name_cache_stream.is_open())
+ {
+ LLAvatarNameCache::exportFile(name_cache_stream);
+}
+
+ if (!gCacheName) return;
+
+ std::string name_cache;
+ name_cache = gDirUtilp->getExpandedFilename(LL_PATH_CACHE, "name.cache");
+ llofstream cache_file(name_cache);
+ if(cache_file.is_open())
+ {
+ gCacheName->exportFile(cache_file);
+ }
+}
+
+/*! @brief This class is an LLFrameTimer that can be created with
+ an elapsed time that starts counting up from the given value
+ rather than 0.0.
+
+ Otherwise it behaves the same way as LLFrameTimer.
+*/
+class LLFrameStatsTimer : public LLFrameTimer
+{
+public:
+ LLFrameStatsTimer(F64 elapsed_already = 0.0)
+ : LLFrameTimer()
+ {
+ mStartTime -= elapsed_already;
+ }
+};
+
+static LLFastTimer::DeclareTimer FTM_AUDIO_UPDATE("Update Audio");
+static LLFastTimer::DeclareTimer FTM_CLEANUP("Cleanup");
+static LLFastTimer::DeclareTimer FTM_IDLE_CB("Idle Callbacks");
+static LLFastTimer::DeclareTimer FTM_LOD_UPDATE("Update LOD");
+static LLFastTimer::DeclareTimer FTM_OBJECTLIST_UPDATE("Update Objectlist");
+static LLFastTimer::DeclareTimer FTM_REGION_UPDATE("Update Region");
+static LLFastTimer::DeclareTimer FTM_WORLD_UPDATE("Update World");
+static LLFastTimer::DeclareTimer FTM_NETWORK("Network");
+
+///////////////////////////////////////////////////////
+// idle()
+//
+// Called every time the window is not doing anything.
+// Receive packets, update statistics, and schedule a redisplay.
+///////////////////////////////////////////////////////
+void LLAppViewer::idle()
+{
+ LLMemType mt_idle(LLMemType::MTYPE_IDLE);
+ pingMainloopTimeout("Main:Idle");
+
+ // Update frame timers
+ static LLTimer idle_timer;
+
+ LLFrameTimer::updateFrameTime();
+ LLFrameTimer::updateFrameCount();
+ LLEventTimer::updateClass();
+ LLCriticalDamp::updateInterpolants();
+ LLMortician::updateClass();
+ F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
+
+ // Cap out-of-control frame times
+ // Too low because in menus, swapping, debugger, etc.
+ // Too high because idle called with no objects in view, etc.
+ const F32 MIN_FRAME_RATE = 1.f;
+ const F32 MAX_FRAME_RATE = 200.f;
+
+ F32 frame_rate_clamped = 1.f / dt_raw;
+ frame_rate_clamped = llclamp(frame_rate_clamped, MIN_FRAME_RATE, MAX_FRAME_RATE);
+ gFrameDTClamped = 1.f / frame_rate_clamped;
+
+ // Global frame timer
+ // Smoothly weight toward current frame
+ gFPSClamped = (frame_rate_clamped + (4.f * gFPSClamped)) / 5.f;
+
+ F32 qas = gSavedSettings.getF32("QuitAfterSeconds");
+ if (qas > 0.f)
+ {
+ if (gRenderStartTime.getElapsedTimeF32() > qas)
+ {
+ LLAppViewer::instance()->forceQuit();
+ }
+ }
+
+ // debug setting to quit after N seconds of being AFK - 0 to never do this
+ F32 qas_afk = gSavedSettings.getF32("QuitAfterSecondsOfAFK");
+ if (qas_afk > 0.f)
+ {
+ // idle time is more than setting
+ if ( gAwayTriggerTimer.getElapsedTimeF32() > qas_afk )
+ {
+ // go ahead and just quit gracefully
+ LLAppViewer::instance()->requestQuit();
+ }
+ }
+
+ // Must wait until both have avatar object and mute list, so poll
+ // here.
+ request_initial_instant_messages();
+
+ ///////////////////////////////////
+ //
+ // Special case idle if still starting up
+ //
+ if (LLStartUp::getStartupState() < STATE_STARTED)
+ {
+ // Skip rest if idle startup returns false (essentially, no world yet)
+ gGLActive = TRUE;
+ if (!idle_startup())
+ {
+ gGLActive = FALSE;
+ return;
+ }
+ gGLActive = FALSE;
+ }
+
+
+ F32 yaw = 0.f; // radians
+
+ if (!gDisconnected)
+ {
+ LLFastTimer t(FTM_NETWORK);
+ // Update spaceserver timeinfo
+ LLWorld::getInstance()->setSpaceTimeUSec(LLWorld::getInstance()->getSpaceTimeUSec() + (U32)(dt_raw * SEC_TO_MICROSEC));
+
+
+ //////////////////////////////////////
+ //
+ // Update simulator agent state
+ //
+
+ if (gSavedSettings.getBOOL("RotateRight"))
+ {
+ gAgent.moveYaw(-1.f);
+ }
+
+ {
+ LLFastTimer t(FTM_AGENT_AUTOPILOT);
+ // Handle automatic walking towards points
+ gAgentPilot.updateTarget();
+ gAgent.autoPilot(&yaw);
+ }
+
+ static LLFrameTimer agent_update_timer;
+ static U32 last_control_flags;
+
+ // When appropriate, update agent location to the simulator.
+ F32 agent_update_time = agent_update_timer.getElapsedTimeF32();
+ BOOL flags_changed = gAgent.controlFlagsDirty() || (last_control_flags != gAgent.getControlFlags());
+
+ if (flags_changed || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND)))
+ {
+ LLFastTimer t(FTM_AGENT_UPDATE);
+ // Send avatar and camera info
+ last_control_flags = gAgent.getControlFlags();
+ send_agent_update(TRUE);
+ agent_update_timer.reset();
+ }
+ }
+
+ //////////////////////////////////////
+ //
+ // Manage statistics
+ //
+ //
+ {
+ // Initialize the viewer_stats_timer with an already elapsed time
+ // of SEND_STATS_PERIOD so that the initial stats report will
+ // be sent immediately.
+ static LLFrameStatsTimer viewer_stats_timer(SEND_STATS_PERIOD);
+ reset_statistics();
+
+ // Update session stats every large chunk of time
+ // *FIX: (???) SAMANTHA
+ if (viewer_stats_timer.getElapsedTimeF32() >= SEND_STATS_PERIOD && !gDisconnected)
+ {
+ llinfos << "Transmitting sessions stats" << llendl;
+ send_stats();
+ viewer_stats_timer.reset();
+ }
+
+ // Print the object debugging stats
+ static LLFrameTimer object_debug_timer;
+ if (object_debug_timer.getElapsedTimeF32() > 5.f)
+ {
+ object_debug_timer.reset();
+ if (gObjectList.mNumDeadObjectUpdates)
+ {
+ llinfos << "Dead object updates: " << gObjectList.mNumDeadObjectUpdates << llendl;
+ gObjectList.mNumDeadObjectUpdates = 0;
+ }
+ if (gObjectList.mNumUnknownKills)
+ {
+ llinfos << "Kills on unknown objects: " << gObjectList.mNumUnknownKills << llendl;
+ gObjectList.mNumUnknownKills = 0;
+ }
+ if (gObjectList.mNumUnknownUpdates)
+ {
+ llinfos << "Unknown object updates: " << gObjectList.mNumUnknownUpdates << llendl;
+ gObjectList.mNumUnknownUpdates = 0;
+ }
+
+ // ViewerMetrics FPS piggy-backing on the debug timer.
+ // The 5-second interval is nice for this purpose. If the object debug
+ // bit moves or is disabled, please give this a suitable home.
+ LLViewerAssetStatsFF::record_fps_main(gFPSClamped);
+ }
+ }
+
+ if (!gDisconnected)
+ {
+ LLFastTimer t(FTM_NETWORK);
+
+ ////////////////////////////////////////////////
+ //
+ // Network processing
+ //
+ // NOTE: Starting at this point, we may still have pointers to "dead" objects
+ // floating throughout the various object lists.
+ //
+ idleNameCache();
+
+ idleNetwork();
+
+
+ // Check for away from keyboard, kick idle agents.
+ idle_afk_check();
+
+ // Update statistics for this frame
+ update_statistics(gFrameCount);
+ }
+
+ ////////////////////////////////////////
+ //
+ // Handle the regular UI idle callbacks as well as
+ // hover callbacks
+ //
+
+ {
+// LLFastTimer t(FTM_IDLE_CB);
+
+ // Do event notifications if necessary. Yes, we may want to move this elsewhere.
+ gEventNotifier.update();
+
+ gIdleCallbacks.callFunctions();
+ gInventory.idleNotifyObservers();
+ }
+
+ // Metrics logging (LLViewerAssetStats, etc.)
+ {
+ static LLTimer report_interval;
+
+ // *TODO: Add configuration controls for this
+ if (report_interval.getElapsedTimeF32() >= app_metrics_interval)
+ {
+ metricsSend(! gDisconnected);
+ report_interval.reset();
+ }
+ }
+
+ if (gDisconnected)
+ {
+ return;
+ }
+
+ gViewerWindow->updateUI();
+
+ ///////////////////////////////////////
+ // Agent and camera movement
+ //
+ LLCoordGL current_mouse = gViewerWindow->getCurrentMouse();
+
+ {
+ // After agent and camera moved, figure out if we need to
+ // deselect objects.
+ LLSelectMgr::getInstance()->deselectAllIfTooFar();
+
+ }
+
+ {
+ // Handle pending gesture processing
+ static LLFastTimer::DeclareTimer ftm("Agent Position");
+ LLFastTimer t(ftm);
+ LLGestureMgr::instance().update();
+
+ gAgent.updateAgentPosition(gFrameDTClamped, yaw, current_mouse.mX, current_mouse.mY);
+ }
+
+ {
+ LLFastTimer t(FTM_OBJECTLIST_UPDATE);
+
+ if (!(logoutRequestSent() && hasSavedFinalSnapshot()))
+ {
+ gObjectList.update(gAgent, *LLWorld::getInstance());
+ }
+ }
+
+ //////////////////////////////////////
+ //
+ // Deletes objects...
+ // Has to be done after doing idleUpdates (which can kill objects)
+ //
+
+ {
+ LLFastTimer t(FTM_CLEANUP);
+ gObjectList.cleanDeadObjects();
+ LLDrawable::cleanupDeadDrawables();
+ }
+
+ //
+ // After this point, in theory we should never see a dead object
+ // in the various object/drawable lists.
+ //
+
+ //////////////////////////////////////
+ //
+ // Update/send HUD effects
+ //
+ // At this point, HUD effects may clean up some references to
+ // dead objects.
+ //
+
+ {
+ static LLFastTimer::DeclareTimer ftm("HUD Effects");
+ LLFastTimer t(ftm);
+ LLSelectMgr::getInstance()->updateEffects();
+ LLHUDManager::getInstance()->cleanupEffects();
+ LLHUDManager::getInstance()->sendEffects();
+ }
+
+ ////////////////////////////////////////
+ //
+ // Unpack layer data that we've received
+ //
+
+ {
+ LLFastTimer t(FTM_NETWORK);
+ gVLManager.unpackData();
+ }
+
+ /////////////////////////
+ //
+ // Update surfaces, and surface textures as well.
+ //
+
+ LLWorld::getInstance()->updateVisibilities();
+ {
+ const F32 max_region_update_time = .001f; // 1ms
+ LLFastTimer t(FTM_REGION_UPDATE);
+ LLWorld::getInstance()->updateRegions(max_region_update_time);
+ }
+
+ /////////////////////////
+ //
+ // Update weather effects
+ //
+ if (!gNoRender)
+ {
+ LLWorld::getInstance()->updateClouds(gFrameDTClamped);
+ gSky.propagateHeavenlyBodies(gFrameDTClamped); // moves sun, moon, and planets
+
+ // Update wind vector
+ LLVector3 wind_position_region;
+ static LLVector3 average_wind;
+
+ LLViewerRegion *regionp;
+ regionp = LLWorld::getInstance()->resolveRegionGlobal(wind_position_region, gAgent.getPositionGlobal()); // puts agent's local coords into wind_position
+ if (regionp)
+ {
+ gWindVec = regionp->mWind.getVelocity(wind_position_region);
+
+ // Compute average wind and use to drive motion of water
+
+ average_wind = regionp->mWind.getAverage();
+ F32 cloud_density = regionp->mCloudLayer.getDensityRegion(wind_position_region);
+
+ gSky.setCloudDensityAtAgent(cloud_density);
+ gSky.setWind(average_wind);
+ //LLVOWater::setWind(average_wind);
+ }
+ else
+ {
+ gWindVec.setVec(0.0f, 0.0f, 0.0f);
+ }
+ }
+
+ //////////////////////////////////////
+ //
+ // Sort and cull in the new renderer are moved to pipeline.cpp
+ // Here, particles are updated and drawables are moved.
+ //
+
+ if (!gNoRender)
+ {
+ LLFastTimer t(FTM_WORLD_UPDATE);
+ gPipeline.updateMove();
+
+ LLWorld::getInstance()->updateParticles();
+ }
+
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ LLViewerJoystick::getInstance()->moveFlycam();
+ }
+ else
+ {
+ if (LLToolMgr::getInstance()->inBuildMode())
+ {
+ LLViewerJoystick::getInstance()->moveObjects();
+ }
+
+ gAgentCamera.updateCamera();
+ }
+
+ // update media focus
+ LLViewerMediaFocus::getInstance()->update();
+
+ // objects and camera should be in sync, do LOD calculations now
+ {
+ LLFastTimer t(FTM_LOD_UPDATE);
+ gObjectList.updateApparentAngles(gAgent);
+ }
+
+ {
+ LLFastTimer t(FTM_AUDIO_UPDATE);
+
+ if (gAudiop)
+ {
+ audio_update_volume(false);
+ audio_update_listener();
+ audio_update_wind(false);
+
+ // this line actually commits the changes we've made to source positions, etc.
+ const F32 max_audio_decode_time = 0.002f; // 2 ms decode time
+ gAudiop->idle(max_audio_decode_time);
+ }
+ }
+
+ // Handle shutdown process, for example,
+ // wait for floaters to close, send quit message,
+ // forcibly quit if it has taken too long
+ if (mQuitRequested)
+ {
+ gGLActive = TRUE;
+ idleShutdown();
+ }
+}
+
+void LLAppViewer::idleShutdown()
+{
+ // Wait for all modal alerts to get resolved
+ if (LLModalDialog::activeCount() > 0)
+ {
+ return;
+ }
+
+ // close IM interface
+ if(gIMMgr)
+ {
+ gIMMgr->disconnectAllSessions();
+ }
+
+ // Wait for all floaters to get resolved
+ if (gFloaterView
+ && !gFloaterView->allChildrenClosed())
+ {
+ return;
+ }
+
+ if (LLSideTray::getInstance()->notifyChildren(LLSD().with("request","wait_quit")))
+ {
+ return;
+ }
+
+
+
+ // ProductEngine: Try moving this code to where we shut down sTextureCache in cleanup()
+ // *TODO: ugly
+ static bool saved_teleport_history = false;
+ if (!saved_teleport_history)
+ {
+ saved_teleport_history = true;
+ LLTeleportHistory::getInstance()->dump();
+ LLLocationHistory::getInstance()->save(); // *TODO: find a better place for doing this
+ return;
+ }
+
+ static bool saved_snapshot = false;
+ if (!saved_snapshot)
+ {
+ saved_snapshot = true;
+ saveFinalSnapshot();
+ return;
+ }
+
+ const F32 SHUTDOWN_UPLOAD_SAVE_TIME = 5.f;
+
+ S32 pending_uploads = gAssetStorage->getNumPendingUploads();
+ if (pending_uploads > 0
+ && gLogoutTimer.getElapsedTimeF32() < SHUTDOWN_UPLOAD_SAVE_TIME
+ && !logoutRequestSent())
+ {
+ static S32 total_uploads = 0;
+ // Sometimes total upload count can change during logout.
+ total_uploads = llmax(total_uploads, pending_uploads);
+ gViewerWindow->setShowProgress(TRUE);
+ S32 finished_uploads = total_uploads - pending_uploads;
+ F32 percent = 100.f * finished_uploads / total_uploads;
+ gViewerWindow->setProgressPercent(percent);
+ gViewerWindow->setProgressString(LLTrans::getString("SavingSettings"));
+ return;
+ }
+
+ // All floaters are closed. Tell server we want to quit.
+ if( !logoutRequestSent() )
+ {
+ sendLogoutRequest();
+
+ // Wait for a LogoutReply message
+ gViewerWindow->setShowProgress(TRUE);
+ gViewerWindow->setProgressPercent(100.f);
+ gViewerWindow->setProgressString(LLTrans::getString("LoggingOut"));
+ return;
+ }
+
+ // Make sure that we quit if we haven't received a reply from the server.
+ if( logoutRequestSent()
+ && gLogoutTimer.getElapsedTimeF32() > gLogoutMaxTime )
+ {
+ forceQuit();
+ return;
+ }
+}
+
+void LLAppViewer::sendLogoutRequest()
+{
+ if(!mLogoutRequestSent)
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessageFast(_PREHASH_LogoutRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ gAgent.sendReliableMessage();
+
+ gLogoutTimer.reset();
+ gLogoutMaxTime = LOGOUT_REQUEST_TIME;
+ mLogoutRequestSent = TRUE;
+
+ if(LLVoiceClient::instanceExists())
+ {
+ LLVoiceClient::getInstance()->leaveChannel();
+ }
+
+ //Set internal status variables and marker files
+ gLogoutInProgress = TRUE;
+ mLogoutMarkerFileName = gDirUtilp->getExpandedFilename(LL_PATH_LOGS,LOGOUT_MARKER_FILE_NAME);
+
+ LLAPRFile outfile ;
+ outfile.open(mLogoutMarkerFileName, LL_APR_W);
+ mLogoutMarkerFile = outfile.getFileHandle() ;
+ if (mLogoutMarkerFile)
+ {
+ llinfos << "Created logout marker file " << mLogoutMarkerFileName << llendl;
+ apr_file_close(mLogoutMarkerFile);
+ }
+ else
+ {
+ llwarns << "Cannot create logout marker file " << mLogoutMarkerFileName << llendl;
+ }
+ }
+}
+
+void LLAppViewer::idleNameCache()
+{
+ // Neither old nor new name cache can function before agent has a region
+ LLViewerRegion* region = gAgent.getRegion();
+ if (!region) return;
+
+ // deal with any queued name requests and replies.
+ gCacheName->processPending();
+
+ // Can't run the new cache until we have the list of capabilities
+ // for the agent region, and can therefore decide whether to use
+ // display names or fall back to the old name system.
+ if (!region->capabilitiesReceived()) return;
+
+ // Agent may have moved to a different region, so need to update cap URL
+ // for name lookups. Can't do this in the cap grant code, as caps are
+ // granted to neighbor regions before the main agent gets there. Can't
+ // do it in the move-into-region code because cap not guaranteed to be
+ // granted yet, for example on teleport.
+ bool had_capability = LLAvatarNameCache::hasNameLookupURL();
+ std::string name_lookup_url;
+ name_lookup_url.reserve(128); // avoid a memory allocation below
+ name_lookup_url = region->getCapability("GetDisplayNames");
+ bool have_capability = !name_lookup_url.empty();
+ if (have_capability)
+ {
+ // we have support for display names, use it
+ U32 url_size = name_lookup_url.size();
+ // capabilities require URLs with slashes before query params:
+ // https://<host>:<port>/cap/<uuid>/?ids=<blah>
+ // but the caps are granted like:
+ // https://<host>:<port>/cap/<uuid>
+ if (url_size > 0 && name_lookup_url[url_size-1] != '/')
+ {
+ name_lookup_url += '/';
+ }
+ LLAvatarNameCache::setNameLookupURL(name_lookup_url);
+ }
+ else
+ {
+ // Display names not available on this region
+ LLAvatarNameCache::setNameLookupURL( std::string() );
+ }
+
+ // Error recovery - did we change state?
+ if (had_capability != have_capability)
+ {
+ // name tags are persistant on screen, so make sure they refresh
+ LLVOAvatar::invalidateNameTags();
+ }
+
+ LLAvatarNameCache::idle();
+}
+
+//
+// Handle messages, and all message related stuff
+//
+
+#define TIME_THROTTLE_MESSAGES
+
+#ifdef TIME_THROTTLE_MESSAGES
+#define CHECK_MESSAGES_DEFAULT_MAX_TIME .020f // 50 ms = 50 fps (just for messages!)
+static F32 CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
+#endif
+
+static LLFastTimer::DeclareTimer FTM_IDLE_NETWORK("Idle Network");
+
+void LLAppViewer::idleNetwork()
+{
+ LLMemType mt_in(LLMemType::MTYPE_IDLE_NETWORK);
+ pingMainloopTimeout("idleNetwork");
+
+ gObjectList.mNumNewObjects = 0;
+ S32 total_decoded = 0;
+
+ if (!gSavedSettings.getBOOL("SpeedTest"))
+ {
+ LLFastTimer t(FTM_IDLE_NETWORK); // decode
+
+ LLTimer check_message_timer;
+ // Read all available packets from network
+ const S64 frame_count = gFrameCount; // U32->S64
+ F32 total_time = 0.0f;
+
+ while (gMessageSystem->checkAllMessages(frame_count, gServicePump))
+ {
+ if (gDoDisconnect)
+ {
+ // We're disconnecting, don't process any more messages from the server
+ // We're usually disconnecting due to either network corruption or a
+ // server going down, so this is OK.
+ break;
+ }
+
+ total_decoded++;
+ gPacketsIn++;
+
+ if (total_decoded > MESSAGE_MAX_PER_FRAME)
+ {
+ break;
+ }
+
+#ifdef TIME_THROTTLE_MESSAGES
+ // Prevent slow packets from completely destroying the frame rate.
+ // This usually happens due to clumps of avatars taking huge amount
+ // of network processing time (which needs to be fixed, but this is
+ // a good limit anyway).
+ total_time = check_message_timer.getElapsedTimeF32();
+ if (total_time >= CheckMessagesMaxTime)
+ break;
+#endif
+ }
+
+ // Handle per-frame message system processing.
+ gMessageSystem->processAcks();
+
+#ifdef TIME_THROTTLE_MESSAGES
+ if (total_time >= CheckMessagesMaxTime)
+ {
+ // Increase CheckMessagesMaxTime so that we will eventually catch up
+ CheckMessagesMaxTime *= 1.035f; // 3.5% ~= x2 in 20 frames, ~8x in 60 frames
+ }
+ else
+ {
+ // Reset CheckMessagesMaxTime to default value
+ CheckMessagesMaxTime = CHECK_MESSAGES_DEFAULT_MAX_TIME;
+ }
+#endif
+
+
+
+ // we want to clear the control after sending out all necessary agent updates
+ gAgent.resetControlFlags();
+
+ // Decode enqueued messages...
+ S32 remaining_possible_decodes = MESSAGE_MAX_PER_FRAME - total_decoded;
+
+ if( remaining_possible_decodes <= 0 )
+ {
+ llinfos << "Maxed out number of messages per frame at " << MESSAGE_MAX_PER_FRAME << llendl;
+ }
+
+ if (gPrintMessagesThisFrame)
+ {
+ llinfos << "Decoded " << total_decoded << " msgs this frame!" << llendl;
+ gPrintMessagesThisFrame = FALSE;
+ }
+ }
+ LLViewerStats::getInstance()->mNumNewObjectsStat.addValue(gObjectList.mNumNewObjects);
+
+ // Retransmit unacknowledged packets.
+ gXferManager->retransmitUnackedPackets();
+ gAssetStorage->checkForTimeouts();
+ gViewerThrottle.updateDynamicThrottle();
+
+ // Check that the circuit between the viewer and the agent's current
+ // region is still alive
+ LLViewerRegion *agent_region = gAgent.getRegion();
+ if (agent_region && (LLStartUp::getStartupState()==STATE_STARTED))
+ {
+ LLUUID this_region_id = agent_region->getRegionID();
+ bool this_region_alive = agent_region->isAlive();
+ if ((mAgentRegionLastAlive && !this_region_alive) // newly dead
+ && (mAgentRegionLastID == this_region_id)) // same region
+ {
+ forceDisconnect(LLTrans::getString("AgentLostConnection"));
+ }
+ mAgentRegionLastID = this_region_id;
+ mAgentRegionLastAlive = this_region_alive;
+ }
+}
+
+void LLAppViewer::disconnectViewer()
+{
+ if (gDisconnected)
+ {
+ return;
+ }
+ //
+ // Cleanup after quitting.
+ //
+ // Save snapshot for next time, if we made it through initialization
+
+ llinfos << "Disconnecting viewer!" << llendl;
+
+ // Dump our frame statistics
+
+ // Remember if we were flying
+ gSavedSettings.setBOOL("FlyingAtExit", gAgent.getFlying() );
+
+ // Un-minimize all windows so they don't get saved minimized
+ if (!gNoRender)
+ {
+ if (gFloaterView)
+ {
+ gFloaterView->restoreAll();
+ }
+ }
+
+ if (LLSelectMgr::getInstance())
+ {
+ LLSelectMgr::getInstance()->deselectAll();
+ }
+
+ // save inventory if appropriate
+ gInventory.cache(gInventory.getRootFolderID(), gAgent.getID());
+ if (gInventory.getLibraryRootFolderID().notNull()
+ && gInventory.getLibraryOwnerID().notNull())
+ {
+ gInventory.cache(
+ gInventory.getLibraryRootFolderID(),
+ gInventory.getLibraryOwnerID());
+ }
+
+ saveNameCache();
+
+ // close inventory interface, close all windows
+ LLFloaterInventory::cleanup();
+
+ gAgentWearables.cleanup();
+ gAgentCamera.cleanup();
+ // Also writes cached agent settings to gSavedSettings
+ gAgent.cleanup();
+
+ // This is where we used to call gObjectList.destroy() and then delete gWorldp.
+ // Now we just ask the LLWorld singleton to cleanly shut down.
+ if(LLWorld::instanceExists())
+ {
+ LLWorld::getInstance()->destroyClass();
+ }
+
+ // call all self-registered classes
+ LLDestroyClassList::instance().fireCallbacks();
+
+ cleanup_xfer_manager();
+ gDisconnected = TRUE;
+
+ // Pass the connection state to LLUrlEntryParcel not to attempt
+ // parcel info requests while disconnected.
+ LLUrlEntryParcel::setDisconnected(gDisconnected);
+}
+
+void LLAppViewer::forceErrorLLError()
+{
+ llerrs << "This is an llerror" << llendl;
+}
+
+void LLAppViewer::forceErrorBreakpoint()
+{
+#ifdef LL_WINDOWS
+ DebugBreak();
+#endif
+ return;
+}
+
+void LLAppViewer::forceErrorBadMemoryAccess()
+{
+ S32* crash = NULL;
+ *crash = 0xDEADBEEF;
+ return;
+}
+
+void LLAppViewer::forceErrorInfiniteLoop()
+{
+ while(true)
+ {
+ ;
+ }
+ return;
+}
+
+void LLAppViewer::forceErrorSoftwareException()
+{
+ // *FIX: Any way to insure it won't be handled?
+ throw;
+}
+
+void LLAppViewer::forceErrorDriverCrash()
+{
+ glDeleteTextures(1, NULL);
+}
+
+void LLAppViewer::initMainloopTimeout(const std::string& state, F32 secs)
+{
+ if(!mMainloopTimeout)
+ {
+ mMainloopTimeout = new LLWatchdogTimeout();
+ resumeMainloopTimeout(state, secs);
+ }
+}
+
+void LLAppViewer::destroyMainloopTimeout()
+{
+ if(mMainloopTimeout)
+ {
+ delete mMainloopTimeout;
+ mMainloopTimeout = NULL;
+ }
+}
+
+void LLAppViewer::resumeMainloopTimeout(const std::string& state, F32 secs)
+{
+ if(mMainloopTimeout)
+ {
+ if(secs < 0.0f)
+ {
+ secs = gSavedSettings.getF32("MainloopTimeoutDefault");
+ }
+
+ mMainloopTimeout->setTimeout(secs);
+ mMainloopTimeout->start(state);
+ }
+}
+
+void LLAppViewer::pauseMainloopTimeout()
+{
+ if(mMainloopTimeout)
+ {
+ mMainloopTimeout->stop();
+ }
+}
+
+void LLAppViewer::pingMainloopTimeout(const std::string& state, F32 secs)
+{
+// if(!restoreErrorTrap())
+// {
+// llwarns << "!!!!!!!!!!!!! Its an error trap!!!!" << state << llendl;
+// }
+
+ if(mMainloopTimeout)
+ {
+ if(secs < 0.0f)
+ {
+ secs = gSavedSettings.getF32("MainloopTimeoutDefault");
+ }
+
+ mMainloopTimeout->setTimeout(secs);
+ mMainloopTimeout->ping(state);
+ }
+}
+
+void LLAppViewer::handleLoginComplete()
+{
+ gLoggedInTime.start();
+ initMainloopTimeout("Mainloop Init");
+
+ // Store some data to DebugInfo in case of a freeze.
+ gDebugInfo["ClientInfo"]["Name"] = LLVersionInfo::getChannel();
+
+ gDebugInfo["ClientInfo"]["MajorVersion"] = LLVersionInfo::getMajor();
+ gDebugInfo["ClientInfo"]["MinorVersion"] = LLVersionInfo::getMinor();
+ gDebugInfo["ClientInfo"]["PatchVersion"] = LLVersionInfo::getPatch();
+ gDebugInfo["ClientInfo"]["BuildVersion"] = LLVersionInfo::getBuild();
+
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if ( parcel && parcel->getMusicURL()[0])
+ {
+ gDebugInfo["ParcelMusicURL"] = parcel->getMusicURL();
+ }
+ if ( parcel && parcel->getMediaURL()[0])
+ {
+ gDebugInfo["ParcelMediaURL"] = parcel->getMediaURL();
+ }
+
+ gDebugInfo["SettingsFilename"] = gSavedSettings.getString("ClientSettingsFile");
+ gDebugInfo["CAFilename"] = gDirUtilp->getCAFile();
+ gDebugInfo["ViewerExePath"] = gDirUtilp->getExecutablePathAndName();
+ gDebugInfo["CurrentPath"] = gDirUtilp->getCurPath();
+
+ if(gAgent.getRegion())
+ {
+ gDebugInfo["CurrentSimHost"] = gAgent.getRegionHost().getHostName();
+ gDebugInfo["CurrentRegion"] = gAgent.getRegion()->getName();
+ }
+
+ if(LLAppViewer::instance()->mMainloopTimeout)
+ {
+ gDebugInfo["MainloopTimeoutState"] = LLAppViewer::instance()->mMainloopTimeout->getState();
+ }
+
+ mOnLoginCompleted();
+
+ writeDebugInfo();
+}
+
+// *TODO - generalize this and move DSO wrangling to a helper class -brad
+void LLAppViewer::loadEventHostModule(S32 listen_port)
+{
+ std::string dso_name =
+#if LL_WINDOWS
+ "lleventhost.dll";
+#elif LL_DARWIN
+ "liblleventhost.dylib";
+#else
+ "liblleventhost.so";
+#endif
+
+ std::string dso_path = gDirUtilp->findFile(dso_name,
+ gDirUtilp->getAppRODataDir(),
+ gDirUtilp->getExecutableDir());
+
+ if(dso_path == "")
+ {
+ llerrs << "QAModeEventHost requested but module \"" << dso_name << "\" not found!" << llendl;
+ return;
+ }
+
+ LL_INFOS("eventhost") << "Found lleventhost at '" << dso_path << "'" << LL_ENDL;
+#if ! defined(LL_WINDOWS)
+ {
+ std::string outfile("/tmp/lleventhost.file.out");
+ std::string command("file '" + dso_path + "' > '" + outfile + "' 2>&1");
+ int rc = system(command.c_str());
+ if (rc != 0)
+ {
+ LL_WARNS("eventhost") << command << " ==> " << rc << ':' << LL_ENDL;
+ }
+ else
+ {
+ LL_INFOS("eventhost") << command << ':' << LL_ENDL;
+ }
+ {
+ std::ifstream reader(outfile.c_str());
+ std::string line;
+ while (std::getline(reader, line))
+ {
+ size_t len = line.length();
+ if (len && line[len-1] == '\n')
+ line.erase(len-1);
+ LL_INFOS("eventhost") << line << LL_ENDL;
+ }
+ }
+ remove(outfile.c_str());
+ }
+#endif // LL_WINDOWS
+
+ apr_dso_handle_t * eventhost_dso_handle = NULL;
+ apr_pool_t * eventhost_dso_memory_pool = NULL;
+
+ //attempt to load the shared library
+ apr_pool_create(&eventhost_dso_memory_pool, NULL);
+ apr_status_t rv = apr_dso_load(&eventhost_dso_handle,
+ dso_path.c_str(),
+ eventhost_dso_memory_pool);
+ llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));
+ llassert_always(eventhost_dso_handle != NULL);
+
+ int (*ll_plugin_start_func)(LLSD const &) = NULL;
+ rv = apr_dso_sym((apr_dso_handle_sym_t*)&ll_plugin_start_func, eventhost_dso_handle, "ll_plugin_start");
+
+ llassert_always(! ll_apr_warn_status(rv, eventhost_dso_handle));
+ llassert_always(ll_plugin_start_func != NULL);
+
+ LLSD args;
+ args["listen_port"] = listen_port;
+
+ int status = ll_plugin_start_func(args);
+
+ if(status != 0)
+ {
+ llerrs << "problem loading eventhost plugin, status: " << status << llendl;
+ }
+
+ mPlugins.insert(eventhost_dso_handle);
+}
+
+void LLAppViewer::launchUpdater()
+{
+ LLSD query_map = LLSD::emptyMap();
+ // *TODO place os string in a global constant
+#if LL_WINDOWS
+ query_map["os"] = "win";
+#elif LL_DARWIN
+ query_map["os"] = "mac";
+#elif LL_LINUX
+ query_map["os"] = "lnx";
+#elif LL_SOLARIS
+ query_map["os"] = "sol";
+#endif
+ // *TODO change userserver to be grid on both viewer and sim, since
+ // userserver no longer exists.
+ query_map["userserver"] = LLGridManager::getInstance()->getGridLabel();
+ query_map["channel"] = LLVersionInfo::getChannel();
+ // *TODO constantize this guy
+ // *NOTE: This URL is also used in win_setup/lldownloader.cpp
+ LLURI update_url = LLURI::buildHTTP("secondlife.com", 80, "update.php", query_map);
+
+ if(LLAppViewer::sUpdaterInfo)
+ {
+ delete LLAppViewer::sUpdaterInfo;
+ }
+ LLAppViewer::sUpdaterInfo = new LLAppViewer::LLUpdaterInfo() ;
+
+ // if a sim name was passed in via command line parameter (typically through a SLURL)
+ if ( LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION )
+ {
+ // record the location to start at next time
+ gSavedSettings.setString( "NextLoginLocation", LLStartUp::getStartSLURL().getSLURLString());
+ };
+
+#if LL_WINDOWS
+ LLAppViewer::sUpdaterInfo->mUpdateExePath = gDirUtilp->getTempFilename();
+ if (LLAppViewer::sUpdaterInfo->mUpdateExePath.empty())
+ {
+ delete LLAppViewer::sUpdaterInfo ;
+ LLAppViewer::sUpdaterInfo = NULL ;
+
+ // We're hosed, bail
+ LL_WARNS("AppInit") << "LLDir::getTempFilename() failed" << LL_ENDL;
+ return;
+ }
+
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += ".exe";
+
+ std::string updater_source = gDirUtilp->getAppRODataDir();
+ updater_source += gDirUtilp->getDirDelimiter();
+ updater_source += "updater.exe";
+
+ LL_DEBUGS("AppInit") << "Calling CopyFile source: " << updater_source
+ << " dest: " << LLAppViewer::sUpdaterInfo->mUpdateExePath
+ << LL_ENDL;
+
+
+ if (!CopyFileA(updater_source.c_str(), LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), FALSE))
+ {
+ delete LLAppViewer::sUpdaterInfo ;
+ LLAppViewer::sUpdaterInfo = NULL ;
+
+ LL_WARNS("AppInit") << "Unable to copy the updater!" << LL_ENDL;
+
+ return;
+ }
+
+ LLAppViewer::sUpdaterInfo->mParams << "-url \"" << update_url.asString() << "\"";
+
+ LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << " " << LLAppViewer::sUpdaterInfo->mParams.str() << LL_ENDL;
+
+ //Explicitly remove the marker file, otherwise we pass the lock onto the child process and things get weird.
+ LLAppViewer::instance()->removeMarkerFile(); // In case updater fails
+
+ // *NOTE:Mani The updater is spawned as the last thing before the WinMain exit.
+ // see LLAppViewerWin32.cpp
+
+#elif LL_DARWIN
+ LLAppViewer::sUpdaterInfo->mUpdateExePath = "'";
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += gDirUtilp->getAppRODataDir();
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += "/mac-updater.app/Contents/MacOS/mac-updater' -url \"";
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += update_url.asString();
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -name \"";
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += LLAppViewer::instance()->getSecondLifeTitle();
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" -bundleid \"";
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += LL_VERSION_BUNDLE_ID;
+ LLAppViewer::sUpdaterInfo->mUpdateExePath += "\" &";
+
+ LL_DEBUGS("AppInit") << "Calling updater: " << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
+
+ // Run the auto-updater.
+ system(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str()); /* Flawfinder: ignore */
+
+#elif (LL_LINUX || LL_SOLARIS) && LL_GTK
+ // we tell the updater where to find the xml containing string
+ // translations which it can use for its own UI
+ std::string xml_strings_file = "strings.xml";
+ std::vector<std::string> xui_path_vec = LLUI::getXUIPaths();
+ std::string xml_search_paths;
+ std::vector<std::string>::const_iterator iter;
+ // build comma-delimited list of xml paths to pass to updater
+ for (iter = xui_path_vec.begin(); iter != xui_path_vec.end(); )
+ {
+ std::string this_skin_dir = gDirUtilp->getDefaultSkinDir()
+ + gDirUtilp->getDirDelimiter()
+ + (*iter);
+ llinfos << "Got a XUI path: " << this_skin_dir << llendl;
+ xml_search_paths.append(this_skin_dir);
+ ++iter;
+ if (iter != xui_path_vec.end())
+ xml_search_paths.append(","); // comma-delimit
+ }
+ // build the overall command-line to run the updater correctly
+ LLAppViewer::sUpdaterInfo->mUpdateExePath =
+ gDirUtilp->getExecutableDir() + "/" + "linux-updater.bin" +
+ " --url \"" + update_url.asString() + "\"" +
+ " --name \"" + LLAppViewer::instance()->getSecondLifeTitle() + "\"" +
+ " --dest \"" + gDirUtilp->getAppRODataDir() + "\"" +
+ " --stringsdir \"" + xml_search_paths + "\"" +
+ " --stringsfile \"" + xml_strings_file + "\"";
+
+ LL_INFOS("AppInit") << "Calling updater: "
+ << LLAppViewer::sUpdaterInfo->mUpdateExePath << LL_ENDL;
+
+ // *TODO: we could use the gdk equivalent to ensure the updater
+ // gets started on the same screen.
+ GError *error = NULL;
+ if (!g_spawn_command_line_async(LLAppViewer::sUpdaterInfo->mUpdateExePath.c_str(), &error))
+ {
+ llerrs << "Failed to launch updater: "
+ << error->message
+ << llendl;
+ }
+ if (error) {
+ g_error_free(error);
+ }
+#else
+ OSMessageBox(LLTrans::getString("MBNoAutoUpdate"), LLStringUtil::null, OSMB_OK);
+#endif
+
+ // *REMOVE:Mani - Saving for reference...
+ // LLAppViewer::instance()->forceQuit();
+}
+
+
+//virtual
+void LLAppViewer::setMasterSystemAudioMute(bool mute)
+{
+ gSavedSettings.setBOOL("MuteAudio", mute);
+}
+
+//virtual
+bool LLAppViewer::getMasterSystemAudioMute()
+{
+ return gSavedSettings.getBOOL("MuteAudio");
+}
+
+//----------------------------------------------------------------------------
+// Metrics-related methods (static and otherwise)
+//----------------------------------------------------------------------------
+
+/**
+ * LLViewerAssetStats collects data on a per-region (as defined by the agent's
+ * location) so we need to tell it about region changes which become a kind of
+ * hidden variable/global state in the collectors. For collectors not running
+ * on the main thread, we need to send a message to move the data over safely
+ * and cheaply (amortized over a run).
+ */
+void LLAppViewer::metricsUpdateRegion(U64 region_handle)
+{
+ if (0 != region_handle)
+ {
+ LLViewerAssetStatsFF::set_region_main(region_handle);
+ if (LLAppViewer::sTextureFetch)
+ {
+ // Send a region update message into 'thread1' to get the new region.
+ LLAppViewer::sTextureFetch->commandSetRegion(region_handle);
+ }
+ else
+ {
+ // No 'thread1', a.k.a. TextureFetch, so update directly
+ LLViewerAssetStatsFF::set_region_thread1(region_handle);
+ }
+ }
+}
+
+
+/**
+ * Attempts to start a multi-threaded metrics report to be sent back to
+ * the grid for consumption.
+ */
+void LLAppViewer::metricsSend(bool enable_reporting)
+{
+ if (! gViewerAssetStatsMain)
+ return;
+
+ if (LLAppViewer::sTextureFetch)
+ {
+ LLViewerRegion * regionp = gAgent.getRegion();
+
+ if (enable_reporting && regionp)
+ {
+ std::string caps_url = regionp->getCapability("ViewerMetrics");
+
+ // Make a copy of the main stats to send into another thread.
+ // Receiving thread takes ownership.
+ LLViewerAssetStats * main_stats(new LLViewerAssetStats(*gViewerAssetStatsMain));
+
+ // Send a report request into 'thread1' to get the rest of the data
+ // and provide some additional parameters while here.
+ LLAppViewer::sTextureFetch->commandSendMetrics(caps_url,
+ gAgentSessionID,
+ gAgentID,
+ main_stats);
+ main_stats = 0; // Ownership transferred
+ }
+ else
+ {
+ LLAppViewer::sTextureFetch->commandDataBreak();
+ }
+ }
+
+ // Reset even if we can't report. Rather than gather up a huge chunk of
+ // data, we'll keep to our sampling interval and retain the data
+ // resolution in time.
+ gViewerAssetStatsMain->reset();
+}
+
diff --git a/indra/newview/llappviewer.h b/indra/newview/llappviewer.h
index a18e6cbb02..0226211735 100644
--- a/indra/newview/llappviewer.h
+++ b/indra/newview/llappviewer.h
@@ -253,7 +253,7 @@ private:
bool mQuitRequested; // User wants to quit, may have modified documents open.
bool mLogoutRequestSent; // Disconnect message sent to simulator, no longer safe to send messages to the sim.
S32 mYieldTime;
- LLSD mSettingsLocationList;
+ struct SettingsFiles* mSettingsLocationList;
LLWatchdogTimeout* mMainloopTimeout;
diff --git a/indra/newview/llavataractions.cpp b/indra/newview/llavataractions.cpp
index f3f0cde221..afa8b62c74 100755
--- a/indra/newview/llavataractions.cpp
+++ b/indra/newview/llavataractions.cpp
@@ -47,6 +47,7 @@
#include "llfloatergroups.h"
#include "llfloaterreg.h"
#include "llfloaterpay.h"
+#include "llfloaterwebcontent.h"
#include "llfloaterworldmap.h"
#include "llgiveinventory.h"
#include "llinventorybridge.h"
@@ -315,7 +316,7 @@ void LLAvatarActions::showProfile(const LLUUID& id)
std::string agent_name = LLCacheName::buildUsername(full_name);
llinfos << "opening web profile for " << agent_name << llendl;
std::string url = getProfileURL(agent_name);
- LLWeb::loadWebURLInternal(url);
+ LLWeb::loadWebURLInternal(url, "", id.asString());
}
else
{
@@ -336,6 +337,24 @@ void LLAvatarActions::showProfile(const LLUUID& id)
}
}
+//static
+bool LLAvatarActions::profileVisible(const LLUUID& id)
+{
+ LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::findInstance("web_content", id.asString()));
+ return browser && browser->isShown();
+}
+
+
+//static
+void LLAvatarActions::hideProfile(const LLUUID& id)
+{
+ LLFloaterWebContent *browser = dynamic_cast<LLFloaterWebContent*> (LLFloaterReg::findInstance("web_content", id.asString()));
+ if (browser)
+ {
+ browser->closeFloater();
+ }
+}
+
// static
void LLAvatarActions::showOnMap(const LLUUID& id)
{
diff --git a/indra/newview/llavataractions.h b/indra/newview/llavataractions.h
index 2db2918eed..956fed7461 100644
--- a/indra/newview/llavataractions.h
+++ b/indra/newview/llavataractions.h
@@ -93,6 +93,8 @@ public:
* Show avatar profile.
*/
static void showProfile(const LLUUID& id);
+ static void hideProfile(const LLUUID& id);
+ static bool profileVisible(const LLUUID& id);
/**
* Show avatar on world map.
diff --git a/indra/newview/llbottomtray.cpp b/indra/newview/llbottomtray.cpp
index d8ec4b605c..0c0df14ac1 100644
--- a/indra/newview/llbottomtray.cpp
+++ b/indra/newview/llbottomtray.cpp
@@ -1,1833 +1,1850 @@
-/**
- * @file llbottomtray.cpp
- * @brief LLBottomTray class implementation
- *
- * $LicenseInfo:firstyear=2009&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h" // must be first include
-
-#define LLBOTTOMTRAY_CPP
-#include "llbottomtray.h"
-
-// library includes
-#include "llfloaterreg.h"
-#include "llflyoutbutton.h"
-#include "lllayoutstack.h"
-#include "llnotifications.h"
-#include "llnotificationsutil.h"
-#include "lltexteditor.h"
-
-// newview includes
-#include "llagentcamera.h"
-#include "llchiclet.h"
-#include "llfloatercamera.h"
-#include "llhints.h"
-#include "llimfloater.h" // for LLIMFloater
-#include "llnearbychatbar.h"
-#include "llspeakbutton.h"
-#include "llsplitbutton.h"
-#include "llsyswellwindow.h"
-#include "lltoolmgr.h"
-#include "llviewerparcelmgr.h"
-
-#include "llviewerwindow.h"
-#include "llsdserialize.h"
-
-// Distance from mouse down on which drag'n'drop should be started.
-#define DRAG_START_DISTANCE 3
-
-static const std::string SORTING_DATA_FILE_NAME = "bottomtray_buttons_order.xml";
-
-LLDefaultChildRegistry::Register<LLBottomtrayButton> bottomtray_button("bottomtray_button");
-
-// LLBottomtrayButton methods
-
-// virtual
-BOOL LLBottomtrayButton::handleHover(S32 x, S32 y, MASK mask)
-{
- if (mCanDrag)
- {
- // pass hover to bottomtray
- S32 screenX, screenY;
- localPointToScreen(x, y, &screenX, &screenY);
- LLBottomTray::getInstance()->onDraggableButtonHover(screenX, screenY);
-
- return TRUE;
- }
- else
- {
- return LLButton::handleHover(x, y, mask);
- }
-}
-//virtual
-BOOL LLBottomtrayButton::handleMouseUp(S32 x, S32 y, MASK mask)
-{
- if (mCanDrag)
- {
- S32 screenX, screenY;
- localPointToScreen(x, y, &screenX, &screenY);
- // pass mouse up to bottomtray
- LLBottomTray::getInstance()->onDraggableButtonMouseUp(this, screenX, screenY);
- }
- return LLButton::handleMouseUp(x, y, mask);
-}
-//virtual
-BOOL LLBottomtrayButton::handleMouseDown(S32 x, S32 y, MASK mask)
-{
- if (mCanDrag)
- {
- S32 screenX, screenY;
- localPointToScreen(x, y, &screenX, &screenY);
- // pass mouse up to bottomtray
- LLBottomTray::getInstance()->onDraggableButtonMouseDown(this, screenX, screenY);
- }
- return LLButton::handleMouseDown(x, y, mask);
-}
-
-static void update_build_button_enable_state()
-{
- bool can_edit = LLToolMgr::getInstance()->canEdit();
-
- LLBottomTray::getInstance()->getChildView("build_btn")->setEnabled(can_edit);
-}
-
-// Build time optimization, generate extern template once in .cpp file
-template class LLBottomTray* LLSingleton<class LLBottomTray>::getInstance();
-
-namespace
-{
- const std::string& PANEL_CHICLET_NAME = "chiclet_list_panel";
-
- S32 get_panel_min_width(LLLayoutStack* stack, LLView* panel)
- {
- S32 minimal_width = 0;
- llassert(stack);
- if ( stack && panel && panel->getVisible() )
- {
- stack->getPanelMinSize(panel->getName(), &minimal_width);
- }
- return minimal_width;
- }
-
- S32 get_panel_max_width(LLLayoutStack* stack, LLPanel* panel)
- {
- S32 max_width = 0;
- llassert(stack);
- if ( stack && panel && panel->getVisible() )
- {
- stack->getPanelMaxSize(panel->getName(), &max_width);
- }
- return max_width;
- }
-
- S32 get_curr_width(LLUICtrl* ctrl)
- {
- S32 cur_width = 0;
- if ( ctrl && ctrl->getVisible() )
- {
- cur_width = ctrl->getRect().getWidth();
- }
- return cur_width;
- }
-}
-
-class LLBottomTrayLite
- : public LLPanel
-{
-public:
- LLBottomTrayLite()
- : mNearbyChatBar(NULL),
- mChatBarContainer(NULL),
- mGesturePanel(NULL)
- {
- mFactoryMap["chat_bar"] = LLCallbackMap(LLBottomTray::createNearbyChatBar, NULL);
- buildFromFile("panel_bottomtray_lite.xml");
- }
-
- BOOL postBuild()
- {
- mNearbyChatBar = findChild<LLNearbyChatBar>("chat_bar");
- mChatBarContainer = getChild<LLLayoutPanel>("chat_bar_layout_panel");
- mGesturePanel = getChild<LLPanel>("gesture_panel");
-
- // Hide "show_nearby_chat" button
- if (mNearbyChatBar)
- {
- LLLineEditor* chat_box = mNearbyChatBar->getChatBox();
- LLUICtrl* show_btn = mNearbyChatBar->getChild<LLUICtrl>("show_nearby_chat");
- S32 delta_width = show_btn->getRect().getWidth();
- show_btn->setVisible(FALSE);
- chat_box->reshape(chat_box->getRect().getWidth() + delta_width, chat_box->getRect().getHeight());
- }
- return TRUE;
- }
-
- void onFocusLost()
- {
- if (gAgentCamera.cameraMouselook())
- {
- LLBottomTray::getInstance()->setVisible(FALSE);
- }
- }
-
- LLNearbyChatBar* mNearbyChatBar;
- LLLayoutPanel* mChatBarContainer;
- LLPanel* mGesturePanel;
-};
-
-LLBottomTray::LLBottomTray(const LLSD&)
-: mChicletPanel(NULL),
- mSpeakPanel(NULL),
- mSpeakBtn(NULL),
- mNearbyChatBar(NULL),
- mChatBarContainer(NULL),
- mNearbyCharResizeHandlePanel(NULL),
- mToolbarStack(NULL),
- mMovementButton(NULL),
- mResizeState(RS_NORESIZE),
- mBottomTrayContextMenu(NULL),
- mCamButton(NULL),
- mBottomTrayLite(NULL),
- mIsInLiteMode(false),
- mDragStarted(false),
- mDraggedItem(NULL),
- mLandingTab(NULL),
- mCheckForDrag(false)
-{
- // Firstly add ourself to IMSession observers, so we catch session events
- // before chiclets do that.
- LLIMMgr::getInstance()->addSessionObserver(this);
-
- mFactoryMap["chat_bar"] = LLCallbackMap(LLBottomTray::createNearbyChatBar, NULL);
-
- buildFromFile("panel_bottomtray.xml");
-
- LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
-
- //this is to fix a crash that occurs because LLBottomTray is a singleton
- //and thus is deleted at the end of the viewers lifetime, but to be cleanly
- //destroyed LLBottomTray requires some subsystems that are long gone
- //LLUI::getRootView()->addChild(this);
-
- {
- mBottomTrayLite = new LLBottomTrayLite();
- mBottomTrayLite->setFollowsAll();
- mBottomTrayLite->setVisible(FALSE);
- }
-
- mImageDragIndication = LLUI::getUIImage(getString("DragIndicationImageName"));
- mDesiredNearbyChatWidth = mNearbyChatBar ? mNearbyChatBar->getRect().getWidth() : 0;
-}
-
-LLBottomTray::~LLBottomTray()
-{
- if (!LLSingleton<LLIMMgr>::destroyed())
- {
- LLIMMgr::getInstance()->removeSessionObserver(this);
- }
-
- if (mNearbyChatBar)
- {
- // store custom width of chatbar panel.
- S32 custom_width = mChatBarContainer->getRect().getWidth();
- gSavedSettings.setS32("ChatBarCustomWidth", custom_width);
- }
-
- // emulate previous floater behavior to be hidden on startup.
- // override effect of save_visibility=true.
- // this attribute is necessary to button.initial_callback=Button.SetFloaterToggle works properly:
- // i.g when floater changes its visibility - button changes its toggle state.
- getChild<LLUICtrl>("build_btn")->setControlValue(false);
- getChild<LLUICtrl>("search_btn")->setControlValue(false);
- getChild<LLUICtrl>("world_map_btn")->setControlValue(false);
-}
-
-// *TODO Vadim: why void* ?
-void* LLBottomTray::createNearbyChatBar(void* userdata)
-{
- return new LLNearbyChatBar();
-}
-
-LLNearbyChatBar* LLBottomTray::getNearbyChatBar()
-{
- return mIsInLiteMode ? mBottomTrayLite->mNearbyChatBar : mNearbyChatBar;
-}
-
-LLIMChiclet* LLBottomTray::createIMChiclet(const LLUUID& session_id)
-{
- LLIMChiclet::EType im_chiclet_type = LLIMChiclet::getIMSessionType(session_id);
-
- switch (im_chiclet_type)
- {
- case LLIMChiclet::TYPE_IM:
- return getChicletPanel()->createChiclet<LLIMP2PChiclet>(session_id);
- case LLIMChiclet::TYPE_GROUP:
- return getChicletPanel()->createChiclet<LLIMGroupChiclet>(session_id);
- case LLIMChiclet::TYPE_AD_HOC:
- return getChicletPanel()->createChiclet<LLAdHocChiclet>(session_id);
- case LLIMChiclet::TYPE_UNKNOWN:
- break;
- }
-
- return NULL;
-}
-
-//virtual
-void LLBottomTray::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
-{
- if (!getChicletPanel()) return;
-
- LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
- if (!session) return;
-
- // no need to spawn chiclets for participants in P2P calls called through Avaline
- if (session->isP2P() && session->isOtherParticipantAvaline()) return;
-
- if (getChicletPanel()->findChiclet<LLChiclet>(session_id)) return;
-
- LLIMChiclet* chiclet = createIMChiclet(session_id);
- if(chiclet)
- {
- chiclet->setIMSessionName(name);
- chiclet->setOtherParticipantId(other_participant_id);
-
- LLIMFloater::onIMChicletCreated(session_id);
-
- }
- else
- {
- llerrs << "Could not create chiclet" << llendl;
- }
-}
-
-//virtual
-void LLBottomTray::sessionRemoved(const LLUUID& session_id)
-{
- if(getChicletPanel())
- {
- // IM floater should be closed when session removed and associated chiclet closed
- LLIMFloater* iMfloater = LLFloaterReg::findTypedInstance<LLIMFloater>(
- "impanel", session_id);
- if (iMfloater != NULL)
- {
- iMfloater->closeFloater();
- }
-
- getChicletPanel()->removeChiclet(session_id);
- }
-}
-
-void LLBottomTray::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
-{
- //this is only needed in case of outgoing ad-hoc/group chat sessions
- LLChicletPanel* chiclet_panel = getChicletPanel();
- if (chiclet_panel)
- {
- //it should be ad-hoc im chiclet or group im chiclet
- LLChiclet* chiclet = chiclet_panel->findChiclet<LLChiclet>(old_session_id);
- if (chiclet) chiclet->setSessionId(new_session_id);
- }
-}
-
-S32 LLBottomTray::getTotalUnreadIMCount()
-{
- return getChicletPanel()->getTotalUnreadIMCount();
-}
-
-// virtual
-void LLBottomTray::onChange(EStatusType status, const std::string &channelURI, bool proximal)
-{
- // Time it takes to connect to voice channel might be pretty long,
- // so don't expect user login or STATUS_VOICE_ENABLED to be followed by STATUS_JOINED.
- BOOL enable = FALSE;
-
- switch (status)
- {
- // Do not add STATUS_VOICE_ENABLED because voice chat is
- // inactive until STATUS_JOINED
- case STATUS_JOINED:
- enable = TRUE;
- break;
- default:
- enable = FALSE;
- break;
- }
-
- // We have to enable/disable right and left parts of speak button separately (EXT-4648)
- mSpeakBtn->setSpeakBtnEnabled(enable);
- // skipped to avoid button blinking
- if (status != STATUS_JOINING && status!= STATUS_LEFT_CHANNEL)
- {
- mSpeakBtn->setFlyoutBtnEnabled(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking());
- }
-}
-
-void LLBottomTray::onMouselookModeOut()
-{
- mIsInLiteMode = false;
- mBottomTrayLite->setVisible(FALSE);
- mNearbyChatBar->getChatBox()->setText(mBottomTrayLite->mNearbyChatBar->getChatBox()->getText());
- setVisible(TRUE);
-}
-
-void LLBottomTray::onMouselookModeIn()
-{
- setVisible(FALSE);
-
- // Attach the lite bottom tray
- if (getParent() && mBottomTrayLite->getParent() != getParent())
- getParent()->addChild(mBottomTrayLite);
-
- mBottomTrayLite->setShape(getLocalRect());
- mBottomTrayLite->mNearbyChatBar->getChatBox()->setText(mNearbyChatBar->getChatBox()->getText());
- mBottomTrayLite->mGesturePanel->setVisible(gSavedSettings.getBOOL("ShowGestureButton"));
-
- mIsInLiteMode = true;
-}
-
-//virtual
-// setVisible used instead of onVisibilityChange, since LLAgent calls it on entering/leaving mouselook mode.
-// If bottom tray is already visible in mouselook mode, then onVisibilityChange will not be called from setVisible(true),
-void LLBottomTray::setVisible(BOOL visible)
-{
- if (mIsInLiteMode)
- {
- mBottomTrayLite->setVisible(visible);
- }
- else
- {
- LLPanel::setVisible(visible);
- }
- if(visible)
- gFloaterView->setSnapOffsetBottom(getRect().getHeight());
- else
- gFloaterView->setSnapOffsetBottom(0);
-}
-
-S32 LLBottomTray::notifyParent(const LLSD& info)
-{
- if(info.has("well_empty")) // implementation of EXT-3397
- {
- const std::string chiclet_name = info["well_name"];
-
- // only "im_well" or "notification_well" names are expected.
- // They are set in panel_bottomtray.xml in <chiclet_im_well> & <chiclet_notification>
- llassert("im_well" == chiclet_name || "notification_well" == chiclet_name);
-
- BOOL should_be_visible = !info["well_empty"];
- showWellButton("im_well" == chiclet_name ? RS_IM_WELL : RS_NOTIFICATION_WELL, should_be_visible);
- return 1;
- }
-
- if (info.has("action") && info["action"] == "resize")
- {
- const std::string& name = info["view_name"];
-
- // expected only resize of nearby chatbar
- if (mChatBarContainer->getName() != name) return LLPanel::notifyParent(info);
-
- const S32 new_width = info["new_width"];
-
- processChatbarCustomization(new_width);
-
- return 2;
- }
- return LLPanel::notifyParent(info);
-}
-
-void LLBottomTray::showBottomTrayContextMenu(S32 x, S32 y, MASK mask)
-{
- // We should show BottomTrayContextMenu in last turn
- if (mBottomTrayContextMenu && !LLMenuGL::sMenuContainer->getVisibleMenu())
- {
- //there are no other context menu (IM chiclet etc ), so we can show BottomTrayContextMenu
-
- updateContextMenu(x, y, mask);
- mBottomTrayContextMenu->buildDrawLabels();
- mBottomTrayContextMenu->updateParent(LLMenuGL::sMenuContainer);
- LLMenuGL::showPopup(this, mBottomTrayContextMenu, x, y);
-
- }
-}
-
-void LLBottomTray::updateContextMenu(S32 x, S32 y, MASK mask)
-{
- LLUICtrl* edit_box = mNearbyChatBar->getChild<LLUICtrl>("chat_box");
-
- S32 local_x = x - mChatBarContainer->getRect().mLeft - edit_box->getRect().mLeft;
- S32 local_y = y - mChatBarContainer->getRect().mBottom - edit_box->getRect().mBottom;
-
- bool in_edit_box = edit_box->pointInView(local_x, local_y);
-
- mBottomTrayContextMenu->setItemVisible("Separator", in_edit_box);
- mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Cut", in_edit_box);
- mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Copy", in_edit_box);
- mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Paste", in_edit_box);
- mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Delete", in_edit_box);
- mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Select_All", in_edit_box);
-}
-
-void LLBottomTray::showGestureButton(BOOL visible)
-{
- setTrayButtonVisibleIfPossible(RS_BUTTON_GESTURES, visible);
-}
-
-void LLBottomTray::showMoveButton(BOOL visible)
-{
- setTrayButtonVisibleIfPossible(RS_BUTTON_MOVEMENT, visible);
-}
-
-void LLBottomTray::showCameraButton(BOOL visible)
-{
- setTrayButtonVisibleIfPossible(RS_BUTTON_CAMERA, visible);
-}
-
-void LLBottomTray::showSnapshotButton(BOOL visible)
-{
- setTrayButtonVisibleIfPossible(RS_BUTTON_SNAPSHOT, visible);
-}
-
-void LLBottomTray::showSpeakButton(bool visible)
-{
- // Show/hide the button
- setTrayButtonVisible(RS_BUTTON_SPEAK, visible);
-
- // and adjust other panels according to the occupied/freed space.
- const S32 panel_width = mSpeakPanel->getRect().getWidth();
- if (visible)
- {
- processWidthDecreased(-panel_width);
- }
- else
- {
- processWidthIncreased(panel_width);
- }
-}
-
-void LLBottomTray::toggleMovementControls()
-{
- if (mMovementButton)
- mMovementButton->onCommit();
-}
-
-void LLBottomTray::toggleCameraControls()
-{
- if (mCamButton)
- mCamButton->onCommit();
-}
-
-BOOL LLBottomTray::postBuild()
-{
- LLHints::registerHintTarget("bottom_tray", LLView::getHandle());
- LLHints::registerHintTarget("dest_guide_btn", getChild<LLUICtrl>("destination_btn")->getHandle());
- LLHints::registerHintTarget("avatar_picker_btn", getChild<LLUICtrl>("avatar_btn")->getHandle());
-
- LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("NearbyChatBar.Action", boost::bind(&LLBottomTray::onContextMenuItemClicked, this, _2));
- LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("NearbyChatBar.EnableMenuItem", boost::bind(&LLBottomTray::onContextMenuItemEnabled, this, _2));
-
- mBottomTrayContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_bottomtray.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
- gMenuHolder->addChild(mBottomTrayContextMenu);
-
- mNearbyChatBar = findChild<LLNearbyChatBar>("chat_bar");
- LLHints::registerHintTarget("chat_bar", mNearbyChatBar->LLView::getHandle());
-
- mChatBarContainer = getChild<LLLayoutPanel>("chat_bar_layout_panel");
- mNearbyCharResizeHandlePanel = getChild<LLPanel>("chat_bar_resize_handle_panel");
-
- mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
- mMovementButton = getChild<LLButton>("movement_btn");
- LLHints::registerHintTarget("move_btn", mMovementButton->getHandle());
- mCamButton = getChild<LLButton>("camera_btn");
- setRightMouseDownCallback(boost::bind(&LLBottomTray::showBottomTrayContextMenu,this, _2, _3,_4));
-
- mSpeakPanel = getChild<LLPanel>("speak_panel");
- mSpeakBtn = getChild<LLSpeakButton>("talk");
-
- // Both parts of speak button should be initially disabled because
- // it takes some time between logging in to world and connecting to voice channel.
- mSpeakBtn->setSpeakBtnEnabled(false);
- mSpeakBtn->setFlyoutBtnEnabled(false);
-
- // Localization tool doesn't understand custom buttons like <talk_button>
- mSpeakBtn->setSpeakToolTip( getString("SpeakBtnToolTip") );
- mSpeakBtn->setShowToolTip( getString("VoiceControlBtnToolTip") );
-
- // Registering Chat Bar to receive Voice client status change notifications.
- LLVoiceClient::getInstance()->addObserver(this);
-
- mNearbyChatBar->getChatBox()->setContextMenu(NULL);
-
- mChicletPanel = getChild<LLChicletPanel>("chiclet_list");
-
- initResizeStateContainers();
-
- setButtonsControlsAndListeners();
-
- initButtonsVisibility();
-
- // update wells visibility:
- showWellButton(RS_IM_WELL, !LLIMWellWindow::getInstance()->isWindowEmpty());
- showWellButton(RS_NOTIFICATION_WELL, !LLNotificationWellWindow::getInstance()->isWindowEmpty());
-
- loadButtonsOrder();
-
- LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(boost::bind(&update_build_button_enable_state));
-
- return TRUE;
-}
-
-//Drag-n-drop
-
-void LLBottomTray::onDraggableButtonMouseDown(LLUICtrl* ctrl, S32 x, S32 y)
-{
- if (ctrl == NULL) return;
- LLView* parent_view = ctrl->getParent();
- if(parent_view != NULL)
- {
- // we actually drag'n'drop panel (not button) in code, so have to find a parent
- // of button which called this method on mouse down.
- LLPanel* parent = dynamic_cast<LLPanel*>(parent_view);
- // It may happen that we clicked not usual button, but button inside widget(speak, gesture)
- // so we'll need to get a level higher to reach layout panel as a parent.
- if(parent == NULL) parent = dynamic_cast<LLPanel*>(parent_view->getParent());
- if (parent && parent->getVisible())
- {
- mDraggedItem = parent;
- mCheckForDrag = true;
- mStartX = x;
- mStartY = y;
- }
- }
-}
-
-LLPanel* LLBottomTray::findChildPanelByLocalCoords(S32 x, S32 y)
-{
- LLPanel* ctrl = 0;
- S32 screenX, screenY;
- const child_list_t* list = mToolbarStack->getChildList();
-
- localPointToScreen(x, y, &screenX, &screenY);
-
- // look for a child panel which contains the point (screenX, screenY) in it's rectangle
- for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i)
- {
- LLRect rect;
- localRectToScreen((*i)->getRect(), &rect);
-
- if (rect.pointInRect(screenX, screenY))
- {
- ctrl = dynamic_cast<LLPanel*>(*i);
- break;
- }
- }
-
- return ctrl;
-}
-
-void LLBottomTray::onDraggableButtonHover(S32 x, S32 y)
-{
- // if mouse down on draggable item was done, check whether we should start DnD
- if (mCheckForDrag)
- {
- // Start drag'n'drop if mouse cursor was dragged away frome mouse down location enough
- if(sqrt((float)((mStartX-x)*(mStartX-x)+(mStartY-y)*(mStartY-y))) > DRAG_START_DISTANCE)
- {
- mDragStarted = true;
- mCheckForDrag = false;
- }
- }
- if (mDragStarted)
- {
- // Check whether the cursor is over draggable area, find which panel it is and set is as
- // landing tab for drag'n'drop
- if(isCursorOverDraggableArea(x, y))
- {
- LLPanel* panel = findChildPanelByLocalCoords(x,y);
- if (panel && panel != mDraggedItem) mLandingTab = panel;
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROWDRAG);
- }
- else
- {
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_NO);
- }
- }
- else
- {
- // Reset cursor in case you move your mouse from the drag handle to a button.
- getWindow()->setCursor(UI_CURSOR_ARROW);
-
- }
-}
-
-bool LLBottomTray::isCursorOverDraggableArea(S32 x, S32 y)
-{
- // Draggable area lasts from the nearby chat input resize handle
- // to the chiclet area (exlusively).
- bool result = getRect().pointInRect(x, y);
- result = result && mNearbyCharResizeHandlePanel->calcScreenRect().mRight < x;
- result = result && mChicletPanel->calcScreenRect().mRight > x;
- return result;
-}
-
-void LLBottomTray::updateButtonsOrdersAfterDnD()
-{
- // *TODO: change implementation of this method to support simplify it
- // (and according to future possible changes in the way button order is saved between sessions).
- state_object_map_t::const_iterator it = mStateProcessedObjectMap.begin();
- state_object_map_t::const_iterator it_end = mStateProcessedObjectMap.end();
- EResizeState dragged_state = RS_NORESIZE;
- EResizeState landing_state = RS_NORESIZE;
- bool landing_state_found = false;
- // Find states for dragged item and landing tab
- for (; it != it_end; ++it)
- {
- if (it->second == mDraggedItem)
- {
- dragged_state = it->first;
- }
- else if (it->second == mLandingTab)
- {
- landing_state = it->first;
- landing_state_found = true;
- }
- }
-
- if (dragged_state == RS_NORESIZE)
- {
- llwarns << "Cannot determine what button is being dragged" << llendl;
- llassert(dragged_state != RS_NORESIZE);
- return;
- }
-
- lldebugs << "Will place " << resizeStateToString(dragged_state)
- << " before " << resizeStateToString(landing_state) << llendl;
-
- // Update order of buttons according to drag'n'drop
- mButtonsOrder.erase(std::find(mButtonsOrder.begin(), mButtonsOrder.end(), dragged_state));
- if (!landing_state_found && mLandingTab == getChild<LLPanel>(PANEL_CHICLET_NAME))
- {
- mButtonsOrder.push_back(dragged_state);
- }
- else
- {
- if (!landing_state_found) landing_state = RS_BUTTON_SPEAK; // just a random fallback
- mButtonsOrder.insert(std::find(mButtonsOrder.begin(), mButtonsOrder.end(), landing_state), dragged_state);
- }
-
- // Synchronize button process order with their order
- resize_state_vec_t::const_iterator it1 = mButtonsOrder.begin();
- const resize_state_vec_t::const_iterator it_end1 = mButtonsOrder.end();
- resize_state_vec_t::iterator it2 = mButtonsProcessOrder.begin();
- for (; it1 != it_end1; ++it1)
- {
- // Skip Speak because it is not in mButtonsProcessOrder(it's the reason why mButtonsOrder was introduced).
- // If any other draggable items will be added to bottomtray later, they should also be skipped here.
- if (*it1 != RS_BUTTON_SPEAK)
- {
- *it2 = *it1;
- ++it2;
- }
- }
-
- saveButtonsOrder();
-}
-
-void LLBottomTray::saveButtonsOrder()
-{
- std::string user_dir = gDirUtilp->getLindenUserDir();
- if (user_dir.empty()) return;
-
- std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME);
- LLSD settings_llsd;
- int i = 0;
- const resize_state_vec_t::const_iterator it_end = mButtonsOrder.end();
- // we use numbers as keys for map which is saved in file and contains resize states as its values
- for (resize_state_vec_t::const_iterator it = mButtonsOrder.begin(); it != it_end; ++it, i++)
- {
- std::string str = llformat("%d", i);
- settings_llsd[str] = *it;
- }
- llofstream file;
- file.open(filename);
- LLSDSerialize::toPrettyXML(settings_llsd, file);
-}
-
-void LLBottomTray::loadButtonsOrder()
-{
- // load per-resident sorting information
- std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME);
-
- LLSD settings_llsd;
- llifstream file;
- file.open(filename);
- if (!file.is_open()) return;
-
- LLSDSerialize::fromXML(settings_llsd, file);
-
-
- mButtonsOrder.clear();
- mButtonsProcessOrder.clear();
- int i = 0;
- // getting button order from file
- for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
- iter != settings_llsd.endMap(); ++iter, ++i)
- {
- std::string str = llformat("%d", i);
- EResizeState state = (EResizeState)settings_llsd[str].asInteger();
- mButtonsOrder.push_back(state);
- // RS_BUTTON_SPEAK is skipped, because it shouldn't be in mButtonsProcessOrder (it does not hide or shrink).
- if (state != RS_BUTTON_SPEAK)
- {
- mButtonsProcessOrder.push_back(state);
- }
- }
-
- // There are other panels in layout stack order of which is not saved. Also, panels order of which is saved,
- // are already in layout stack but in wrong order. The most convenient way to place them is moving them
- // to front one by one (because in this case we don't have to pass the panel before which we want to insert our
- // panel to movePanel()). So panels are moved in order from the end of mButtonsOrder vector(reverse iterator is used).
- const resize_state_vec_t::const_reverse_iterator it_end = mButtonsOrder.rend();
- // placing panels in layout stack according to button order which we loaded in previous for
- for (resize_state_vec_t::const_reverse_iterator it = mButtonsOrder.rbegin(); it != it_end; ++it, ++i)
- {
- LLPanel* panel_to_move = getButtonPanel(*it);
- mToolbarStack->movePanel(panel_to_move, NULL, true); // prepend
- }
- // Nearbychat is not stored in order settings file, but it must be the first of the panels, so moving it
- // (along with its drag handle) manually here.
- mToolbarStack->movePanel(getChild<LLLayoutPanel>("chat_bar_resize_handle_panel"), NULL, true);
- mToolbarStack->movePanel(mChatBarContainer, NULL, true);
-}
-
-void LLBottomTray::onDraggableButtonMouseUp(LLUICtrl* ctrl, S32 x, S32 y)
-{
- //if mouse up happened over area where drop is possible, change order of buttons
- if (mLandingTab != NULL && mDraggedItem != NULL && mDragStarted)
- {
- if(isCursorOverDraggableArea(x, y))
- {
- // change order of panels in layout stack
- mToolbarStack->movePanel(mDraggedItem, (LLPanel*)mLandingTab);
- // change order of buttons in order vectors
- updateButtonsOrdersAfterDnD();
- }
- }
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
- mDragStarted = false;
- mDraggedItem = NULL;
- mLandingTab = NULL;
- mCheckForDrag = false;
-}
-
-void LLBottomTray::draw()
-{
- LLPanel::draw();
- if (mLandingTab)
- {
- static S32 w = mImageDragIndication->getWidth();
- static S32 h = mImageDragIndication->getHeight();
- LLRect rect = mLandingTab->calcScreenRect();
- mImageDragIndication->draw(rect.mLeft - w/2, rect.getHeight(), w, h);
- }
-}
-
-bool LLBottomTray::onContextMenuItemEnabled(const LLSD& userdata)
-{
- std::string item = userdata.asString();
- LLLineEditor* edit_box = mNearbyChatBar->findChild<LLLineEditor>("chat_box");
-
- if (item == "can_cut")
- {
- return edit_box->canCut();
- }
- else if (item == "can_copy")
- {
- return edit_box->canCopy();
- }
- else if (item == "can_paste")
- {
- return edit_box->canPaste();
- }
- else if (item == "can_delete")
- {
- return edit_box->canDoDelete();
- }
- else if (item == "can_select_all")
- {
- return edit_box->canSelectAll() && (edit_box->getLength()>0);
- }
- return true;
-}
-
-
-void LLBottomTray::onContextMenuItemClicked(const LLSD& userdata)
-{
- std::string item = userdata.asString();
- LLLineEditor* edit_box = mNearbyChatBar->findChild<LLLineEditor>("chat_box");
-
- if (item == "cut")
- {
- edit_box->cut();
- }
- else if (item == "copy")
- {
- edit_box->copy();
- }
- else if (item == "paste")
- {
- edit_box->paste();
- edit_box->setFocus(TRUE);
- }
- else if (item == "delete")
- {
- edit_box->doDelete();
- }
- else if (item == "select_all")
- {
- edit_box->selectAll();
- }
-}
-
-void LLBottomTray::log(LLView* panel, const std::string& descr)
-{
- if (NULL == panel) return;
- LLView* layout = panel->getParent();
- lldebugs << descr << ": "
- << "panel: " << panel->getName()
- << ", rect: " << panel->getRect()
-
-
- << "layout: " << layout->getName()
- << ", rect: " << layout->getRect()
- << llendl
- ;
-}
-
-void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
-{
- static S32 debug_calling_number = 0;
- lldebugs << "**************************************** " << ++debug_calling_number << llendl;
-
- S32 current_width = getRect().getWidth();
- S32 delta_width = width - current_width;
- lldebugs << "Reshaping: "
- << ", width: " << width
- << ", cur width: " << current_width
- << ", delta_width: " << delta_width
- << ", called_from_parent: " << called_from_parent
- << llendl;
-
- if (mNearbyChatBar) log(mNearbyChatBar, "before");
- if (mChicletPanel) log(mChicletPanel, "before");
-
- // stores width size on which bottom tray is less than width required by its children. EXT-991
- static S32 extra_shrink_width = 0;
- bool should_be_reshaped = true;
-
- if (mChicletPanel && mToolbarStack && mNearbyChatBar)
- {
- // Firstly, update layout stack to ensure we deal with correct panel sizes.
- {
- BOOL saved_anim = mToolbarStack->getAnimate();
- // Set chiclet panel to be autoresized by default.
- mToolbarStack->updatePanelAutoResize(PANEL_CHICLET_NAME, TRUE);
- // Disable animation to prevent layout updating in several frames.
- mToolbarStack->setAnimate(FALSE);
- // Force the updating of layout to reset panels collapse factor.
- mToolbarStack->updateLayout();
- // Restore animate state.
- mToolbarStack->setAnimate(saved_anim);
- }
-
- // bottom tray is narrowed
- if (delta_width < 0)
- {
- if (extra_shrink_width > 0)
- {
- // is world rect was extra shrunk and decreasing again only update this value
- // to delta_width negative
- extra_shrink_width -= delta_width; // use "-=" because delta_width is negative
- should_be_reshaped = false;
- }
- else
- {
- extra_shrink_width = processWidthDecreased(delta_width);
-
- // increase new width to extra_shrink_width value to not reshape less than bottom tray minimum
- width += extra_shrink_width;
- }
- }
- // bottom tray is widen
- else
- {
- if (extra_shrink_width > delta_width)
- {
- // Less than minimum width is more than increasing (delta_width)
- // only reduce it value and make no reshape
- extra_shrink_width -= delta_width;
- should_be_reshaped = false;
- }
- else
- {
- if (extra_shrink_width > 0)
- {
- // If we have some extra shrink width let's reduce delta_width & width
- delta_width -= extra_shrink_width;
- width -= extra_shrink_width;
- extra_shrink_width = 0;
- }
- processWidthIncreased(delta_width);
- }
- }
- }
-
- if (should_be_reshaped)
- {
- lldebugs << "Reshape all children with width: " << width << llendl;
- LLPanel::reshape(width, height, called_from_parent);
- }
-
- if (mNearbyChatBar) log(mNearbyChatBar, "after");
- if (mChicletPanel) log(mChicletPanel, "after");
-
-
- // Restore width of the chatbar on first reshape.
- // we can not to do this from postBuild because reshape is called from parent view on startup
- // creation after it and reset width according to resize logic.
- static bool needs_restore_custom_state = true;
- if (mChatBarContainer && needs_restore_custom_state)
- {
- // restore custom width of chatbar panel.
- S32 new_width = gSavedSettings.getS32("ChatBarCustomWidth");
- if (new_width > 0)
- {
- mDesiredNearbyChatWidth = new_width;
- processChatbarCustomization(new_width);
- mChatBarContainer->reshape(new_width, mChatBarContainer->getRect().getHeight());
- }
- needs_restore_custom_state = false;
- }
-
-}
-
-S32 LLBottomTray::processWidthDecreased(S32 delta_width)
-{
- bool still_should_be_processed = true;
-
- const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
- const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
-
- // There are four steps of processing width decrease. If in one of them required width was reached,
- // further are not needed.
- // 1. Decreasing width of chiclet panel.
- if (chiclet_panel_width > chiclet_panel_min_width)
- {
- // we have some space to decrease chiclet panel
- S32 panel_delta_min = chiclet_panel_width - chiclet_panel_min_width;
-
- S32 delta_panel = llmin(-delta_width, panel_delta_min);
-
- lldebugs << "delta_width: " << delta_width
- << ", panel_delta_min: " << panel_delta_min
- << ", delta_panel: " << delta_panel
- << llendl;
-
- // is chiclet panel width enough to process resizing?
- delta_width += panel_delta_min;
-
- still_should_be_processed = delta_width < 0;
-
- mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - delta_panel, mChicletPanel->getParent()->getRect().getHeight());
- log(mChicletPanel, "after processing panel decreasing via chiclet panel");
-
- lldebugs << "RS_CHICLET_PANEL"
- << ", delta_width: " << delta_width
- << llendl;
- }
-
- S32 buttons_freed_width = 0;
- // 2. Decreasing width of buttons.
- if (still_should_be_processed)
- {
- processShrinkButtons(delta_width, buttons_freed_width);
- }
- // 3. Decreasing width of nearby chat.
- const S32 chatbar_panel_min_width = get_panel_min_width(mToolbarStack, mChatBarContainer);
- const S32 chatbar_panel_width = mChatBarContainer->getRect().getWidth();
- if (still_should_be_processed && chatbar_panel_width > chatbar_panel_min_width)
- {
- // we have some space to decrease chatbar panel
- S32 panel_delta_min = chatbar_panel_width - chatbar_panel_min_width;
-
- S32 delta_panel = llmin(-delta_width, panel_delta_min);
-
- // whether chatbar panel width is enough to process resizing?
- delta_width += panel_delta_min;
-
- still_should_be_processed = delta_width < 0;
-
- // chatbar should only be shrunk here, not stretched
- if(delta_panel > 0)
- {
- mChatBarContainer->reshape(mNearbyChatBar->getRect().getWidth() - delta_panel, mChatBarContainer->getRect().getHeight());
- }
-
- log(mNearbyChatBar, "after processing panel decreasing via nearby chatbar panel");
-
- lldebugs << "RS_CHATBAR_INPUT"
- << ", delta_panel: " << delta_panel
- << ", delta_width: " << delta_width
- << llendl;
- }
-
- S32 extra_shrink_width = 0;
- // 4. Hiding buttons if needed.
- if (still_should_be_processed)
- {
- processHideButtons(delta_width, buttons_freed_width);
-
- if (delta_width < 0)
- {
- extra_shrink_width = -delta_width;
- llwarns << "There is no enough width to reshape all children: "
- << extra_shrink_width << llendl;
- }
-
- if (buttons_freed_width > 0)
- {
- S32 nearby_needed_width = mDesiredNearbyChatWidth - mNearbyChatBar->getRect().getWidth();
- if (nearby_needed_width > 0)
- {
- S32 compensative_width = nearby_needed_width > buttons_freed_width ? buttons_freed_width : nearby_needed_width;
- log(mNearbyChatBar, "before applying compensative width");
- mChatBarContainer->reshape(mChatBarContainer->getRect().getWidth() + compensative_width, mChatBarContainer->getRect().getHeight() );
- log(mNearbyChatBar, "after applying compensative width");
- lldebugs << buttons_freed_width << llendl;
- }
- }
- }
-
- return extra_shrink_width;
-}
-
-void LLBottomTray::processWidthIncreased(S32 delta_width)
-{
- if (delta_width <= 0) return;
-
- const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
- static const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
-
- const S32 available_width_chiclet = chiclet_panel_width - chiclet_panel_min_width;
-
- // how many room we have to show hidden buttons
- S32 total_available_width = delta_width + available_width_chiclet;
-
- lldebugs << "Processing extending, available width:"
- << ", chiclets - " << available_width_chiclet
- << ", total - " << total_available_width
- << llendl;
-
- S32 available_width = total_available_width;
-
- processShowButtons(available_width);
-
- // if we have to show/extend some buttons but resized delta width is not enough...
- S32 processed_width = total_available_width - available_width;
- if (processed_width > delta_width)
- {
- // ... let's shrink nearby chat & chiclet panels
- S32 required_to_process_width = processed_width;
-
- // 1. use delta width of resizing
- required_to_process_width -= delta_width;
-
- // 2. use width available via decreasing of chiclet panel
- if (required_to_process_width > 0)
- {
- mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - required_to_process_width, mChicletPanel->getParent()->getRect().getHeight());
- log(mChicletPanel, "after applying compensative width for chiclets: ");
- lldebugs << required_to_process_width << llendl;
- }
-
- }
-
- // shown buttons take some space, rest should be processed by nearby chatbar & chiclet panels
- delta_width -= processed_width;
-
-
- // how many space can nearby chatbar take?
- S32 chatbar_panel_width_ = mChatBarContainer->getRect().getWidth();
- if (delta_width > 0 && chatbar_panel_width_ < mDesiredNearbyChatWidth)
- {
- S32 delta_panel_max = mDesiredNearbyChatWidth - chatbar_panel_width_;
- S32 delta_panel = llmin(delta_width, delta_panel_max);
- lldebugs << "Unprocesed delta width: " << delta_width
- << ", can be applied to chatbar: " << delta_panel_max
- << ", will be applied: " << delta_panel
- << llendl;
-
- delta_width -= delta_panel_max;
- mChatBarContainer->reshape(chatbar_panel_width_ + delta_panel, mChatBarContainer->getRect().getHeight());
- log(mNearbyChatBar, "applied unprocessed delta width");
- }
- if (delta_width > 0)
- {
- processExtendButtons(delta_width);
- }
-}
-
-void LLBottomTray::processShowButtons(S32& available_width)
-{
- // process buttons from left to right
- resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
- const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
-
- for (; it != it_end; ++it)
- {
- // is there available space?
- if (available_width <= 0) break;
-
- // try to show next button
- processShowButton(*it, available_width);
- }
-}
-
-bool LLBottomTray::processShowButton(EResizeState shown_object_type, S32& available_width)
-{
- lldebugs << "Trying to show object type: " << shown_object_type << llendl;
-
- LLPanel* panel = getButtonPanel(shown_object_type);
- if (NULL == panel)
- {
- lldebugs << "There is no object to process for state: " << shown_object_type << llendl;
- return false;
- }
- bool can_be_shown = canButtonBeShown(shown_object_type);
- if (can_be_shown)
- {
- //validate if we have enough room to show this button
- const S32 required_width = panel->getRect().getWidth();
- can_be_shown = available_width >= required_width;
- if (can_be_shown)
- {
- available_width -= required_width;
-
- setTrayButtonVisible(shown_object_type, true);
-
- lldebugs << "processed object type: " << shown_object_type
- << ", rest available width: " << available_width
- << llendl;
- mResizeState &= ~shown_object_type;
- }
- }
- return can_be_shown;
-}
-
-void LLBottomTray::processHideButtons(S32& required_width, S32& buttons_freed_width)
-{
- // process buttons from right to left
- resize_state_vec_t::const_reverse_iterator it = mButtonsProcessOrder.rbegin();
- const resize_state_vec_t::const_reverse_iterator it_end = mButtonsProcessOrder.rend();
-
- for (; it != it_end; ++it)
- {
- // is it still necessary to hide a button?
- if (required_width >= 0) break;
-
- // try to hide next button
- processHideButton(*it, required_width, buttons_freed_width);
- }
-}
-
-void LLBottomTray::processHideButton(EResizeState processed_object_type, S32& required_width, S32& buttons_freed_width)
-{
- lldebugs << "Trying to hide object type: " << processed_object_type << llendl;
- LLPanel* panel = getButtonPanel(processed_object_type);
- if (NULL == panel)
- {
- lldebugs << "There is no object to process for state: " << processed_object_type << llendl;
- return;
- }
-
- if (panel->getVisible())
- {
- required_width += panel->getRect().getWidth();
-
- if (required_width > 0)
- {
- buttons_freed_width += required_width;
- }
-
- setTrayButtonVisible(processed_object_type, false);
-
- mResizeState |= processed_object_type;
-
- lldebugs << "processing object type: " << processed_object_type
- << ", buttons_freed_width: " << buttons_freed_width
- << llendl;
- }
-}
-
-void LLBottomTray::processShrinkButtons(S32& required_width, S32& buttons_freed_width)
-{
- // process buttons from right to left
- resize_state_vec_t::const_reverse_iterator it = mButtonsProcessOrder.rbegin();
- const resize_state_vec_t::const_reverse_iterator it_end = mButtonsProcessOrder.rend();
-
- // iterate through buttons in the mButtonsProcessOrder first
- for (; it != it_end; ++it)
- {
- // is it still necessary to hide a button?
- if (required_width >= 0) break;
-
- // try to shrink next button
- processShrinkButton(*it, required_width);
- }
-
- // then shrink Speak button
- if (required_width < 0)
- {
- S32 panel_min_width = 0;
- std::string panel_name = mSpeakPanel->getName();
- bool success = mToolbarStack->getPanelMinSize(panel_name, &panel_min_width);
- if (!success)
- {
- lldebugs << "Panel was not found to get its min width: " << panel_name << llendl;
- }
- else
- {
- S32 panel_width = mSpeakPanel->getRect().getWidth();
- S32 possible_shrink_width = panel_width - panel_min_width;
-
- if (possible_shrink_width > 0)
- {
- mSpeakBtn->setLabelVisible(false);
- mSpeakPanel->reshape(panel_width - possible_shrink_width, mSpeakPanel->getRect().getHeight());
-
- required_width += possible_shrink_width;
-
- if (required_width > 0)
- {
- buttons_freed_width += required_width;
- }
-
- lldebugs << "Shrunk Speak button panel: " << panel_name
- << ", shrunk width: " << possible_shrink_width
- << ", rest width to process: " << required_width
- << llendl;
- }
- }
- }
-}
-
-void LLBottomTray::processShrinkButton(EResizeState processed_object_type, S32& required_width)
-{
- LLPanel* panel = getButtonPanel(processed_object_type);
- if (NULL == panel)
- {
- lldebugs << "There is no object to process for type: " << processed_object_type << llendl;
- return;
- }
-
- if (panel->getVisible())
- {
- S32 panel_width = panel->getRect().getWidth();
- S32 panel_min_width = 0;
- std::string panel_name = panel->getName();
- bool success = mToolbarStack->getPanelMinSize(panel_name, &panel_min_width);
- S32 possible_shrink_width = panel_width - panel_min_width;
-
- if (!success)
- {
- lldebugs << "Panel was not found to get its min width: " << panel_name << llendl;
- }
- // we have some space to free by shrinking the button
- else if (possible_shrink_width > 0)
- {
- // let calculate real width to shrink
-
- // 1. apply all possible width
- required_width += possible_shrink_width;
-
- // 2. it it is too much...
- if (required_width > 0)
- {
- // reduce applied shrunk width to the excessive value.
- possible_shrink_width -= required_width;
- required_width = 0;
- }
- panel->reshape(panel_width - possible_shrink_width, panel->getRect().getHeight());
-
- lldebugs << "Shrunk panel: " << panel_name
- << ", shrunk width: " << possible_shrink_width
- << ", rest width to process: " << required_width
- << llendl;
- }
- }
-}
-
-
-void LLBottomTray::processExtendButtons(S32& available_width)
-{
- // do not allow extending any buttons if we have some buttons hidden via resize
- if (mResizeState & RS_BUTTONS_CAN_BE_HIDDEN) return;
-
- // process buttons from left to right
- resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
- const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
-
- // iterate through buttons in the mButtonsProcessOrder first
- for (; it != it_end; ++it)
- {
- // is there available space?
- if (available_width <= 0) break;
-
- // try to extend next button
- processExtendButton(*it, available_width);
- }
-
- const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
- static const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
- const S32 available_width_chiclet = chiclet_panel_width - chiclet_panel_min_width;
-
- // then try to extend Speak button
- if (available_width > 0 || available_width_chiclet > 0)
- {
- S32 panel_max_width = mObjectDefaultWidthMap[RS_BUTTON_SPEAK];
- S32 panel_width = mSpeakPanel->getRect().getWidth();
- S32 possible_extend_width = panel_max_width - panel_width;
-
- if (possible_extend_width >= 0 && possible_extend_width <= available_width + available_width_chiclet) // HACK: this button doesn't change size so possible_extend_width will be 0
- {
- mSpeakBtn->setLabelVisible(true);
- mSpeakPanel->reshape(panel_max_width, mSpeakPanel->getRect().getHeight());
- log(mSpeakBtn, "speak button is extended");
-
- if( available_width > possible_extend_width)
- {
- available_width -= possible_extend_width;
- }
- else
- {
- S32 required_width = possible_extend_width - available_width;
- available_width = 0;
- mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - required_width, mChicletPanel->getParent()->getRect().getHeight());
- }
- lldebugs << "Extending Speak button panel: " << mSpeakPanel->getName()
- << ", extended width: " << possible_extend_width
- << ", rest width to process: " << available_width
- << llendl;
- }
- }
-}
-
-void LLBottomTray::processExtendButton(EResizeState processed_object_type, S32& available_width)
-{
- LLPanel* panel = getButtonPanel(processed_object_type);
- if (NULL == panel)
- {
- lldebugs << "There is no object to process for type: " << processed_object_type << llendl;
- return;
- }
-
- if (!panel->getVisible()) return;
-
- S32 panel_max_width = mObjectDefaultWidthMap[processed_object_type];
- S32 panel_width = panel->getRect().getWidth();
- S32 possible_extend_width = panel_max_width - panel_width;
-
- if (possible_extend_width > 0)
- {
- // let calculate real width to extend
-
- // 1. apply all possible width
- available_width -= possible_extend_width;
-
- // 2. it it is too much...
- if (available_width < 0)
- {
- // reduce applied extended width to the excessive value.
- possible_extend_width += available_width;
- available_width = 0;
- }
- panel->reshape(panel_width + possible_extend_width, panel->getRect().getHeight());
-
- lldebugs << "Extending panel: " << panel->getName()
- << ", extended width: " << possible_extend_width
- << ", rest width to process: " << available_width
- << llendl;
- }
-}
-
-bool LLBottomTray::canButtonBeShown(EResizeState processed_object_type) const
-{
- // 0. Check if passed button was previously hidden on resize
- bool can_be_shown = mResizeState & processed_object_type;
- if (can_be_shown)
- {
- // Yes, it was. Lets now check that all buttons before it (that can be hidden on resize)
- // are already shown
-
- // process buttons in direct order (from left to right)
- resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
- const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
-
- // 1. Find and accumulate all buttons types before one passed into the method.
- MASK buttons_before_mask = RS_NORESIZE;
- for (; it != it_end; ++it)
- {
- const EResizeState button_type = *it;
- if (button_type == processed_object_type) break;
-
- buttons_before_mask |= button_type;
- }
-
- // 2. Check if some previous buttons are still hidden on resize
- can_be_shown = !(buttons_before_mask & mResizeState);
- }
- return can_be_shown;
-}
-
-void LLBottomTray::initResizeStateContainers()
-{
- // init map with objects should be processed for each type
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SPEAK, getChild<LLPanel>("speak_panel")));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_GESTURES, getChild<LLPanel>("gesture_panel")));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_MOVEMENT, getChild<LLPanel>("movement_panel")));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_CAMERA, getChild<LLPanel>("cam_panel")));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SNAPSHOT, getChild<LLPanel>("snapshot_panel")));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_BUILD, getChild<LLPanel>("build_btn_panel")));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SEARCH, getChild<LLPanel>("search_btn_panel")));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_WORLD_MAP, getChild<LLPanel>("world_map_btn_panel")));
- mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_MINI_MAP, getChild<LLPanel>("mini_map_btn_panel")));
-
- // init an order of processed buttons
- mButtonsProcessOrder.push_back(RS_BUTTON_GESTURES);
- mButtonsProcessOrder.push_back(RS_BUTTON_MOVEMENT);
- mButtonsProcessOrder.push_back(RS_BUTTON_CAMERA);
- mButtonsProcessOrder.push_back(RS_BUTTON_SNAPSHOT);
- mButtonsProcessOrder.push_back(RS_BUTTON_BUILD);
- mButtonsProcessOrder.push_back(RS_BUTTON_SEARCH);
- mButtonsProcessOrder.push_back(RS_BUTTON_WORLD_MAP);
- mButtonsProcessOrder.push_back(RS_BUTTON_MINI_MAP);
-
- mButtonsOrder.push_back(RS_BUTTON_SPEAK);
- mButtonsOrder.insert(mButtonsOrder.end(), mButtonsProcessOrder.begin(), mButtonsProcessOrder.end());
-
- // init default widths
-
- // process buttons that can be hidden on resize...
- resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
- const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
-
- for (; it != it_end; ++it)
- {
- const EResizeState button_type = *it;
- // is there an appropriate object?
- LLPanel* button_panel = getButtonPanel(button_type);
- if (!button_panel) continue;
-
- // set default width for it.
- mObjectDefaultWidthMap[button_type] = button_panel->getRect().getWidth();
- }
-
- // ... and add Speak button because it also can be shrunk.
- mObjectDefaultWidthMap[RS_BUTTON_SPEAK] = mSpeakPanel->getRect().getWidth();
-}
-
-// this method must be called before restoring of the chat entry field on startup
-// because it resets chatbar's width according to resize logic.
-void LLBottomTray::initButtonsVisibility()
-{
- setVisibleAndFitWidths(RS_BUTTON_SPEAK, gSavedSettings.getBOOL("EnableVoiceChat"));
- setVisibleAndFitWidths(RS_BUTTON_GESTURES, gSavedSettings.getBOOL("ShowGestureButton"));
- setVisibleAndFitWidths(RS_BUTTON_MOVEMENT, gSavedSettings.getBOOL("ShowMoveButton"));
- setVisibleAndFitWidths(RS_BUTTON_CAMERA, gSavedSettings.getBOOL("ShowCameraButton"));
- setVisibleAndFitWidths(RS_BUTTON_SNAPSHOT, gSavedSettings.getBOOL("ShowSnapshotButton"));
- setVisibleAndFitWidths(RS_BUTTON_BUILD, gSavedSettings.getBOOL("ShowBuildButton"));
- setVisibleAndFitWidths(RS_BUTTON_SEARCH, gSavedSettings.getBOOL("ShowSearchButton"));
- setVisibleAndFitWidths(RS_BUTTON_WORLD_MAP, gSavedSettings.getBOOL("ShowWorldMapButton"));
- setVisibleAndFitWidths(RS_BUTTON_MINI_MAP, gSavedSettings.getBOOL("ShowMiniMapButton"));
-}
-
-void LLBottomTray::setButtonsControlsAndListeners()
-{
- gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SPEAK, _2));
- gSavedSettings.getControl("ShowGestureButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_GESTURES, _2));
- gSavedSettings.getControl("ShowMoveButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_MOVEMENT, _2));
- gSavedSettings.getControl("ShowCameraButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_CAMERA, _2));
- gSavedSettings.getControl("ShowSnapshotButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SNAPSHOT, _2));
- gSavedSettings.getControl("ShowBuildButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_BUILD, _2));
- gSavedSettings.getControl("ShowSearchButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SEARCH, _2));
- gSavedSettings.getControl("ShowWorldMapButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_WORLD_MAP, _2));
- gSavedSettings.getControl("ShowMiniMapButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_MINI_MAP, _2));
-
-
- LLButton* build_btn = getChild<LLButton>("build_btn");
- // set control name for Build button. It is not enough to link it with Button.SetFloaterToggle in xml
- std::string vis_control_name = LLFloaterReg::declareVisibilityControl("build");
- // Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
- build_btn->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));
-}
-
-bool LLBottomTray::toggleShowButton(LLBottomTray::EResizeState button_type, const LLSD& new_visibility)
-{
- if (LLBottomTray::instanceExists())
- {
- LLBottomTray::getInstance()->setTrayButtonVisibleIfPossible(button_type, new_visibility.asBoolean());
- }
- return true;
-}
-
-void LLBottomTray::setTrayButtonVisible(EResizeState shown_object_type, bool visible)
-{
- LLPanel* panel = getButtonPanel(shown_object_type);
- if (NULL == panel)
- {
- lldebugs << "There is no object to show for state: " << shown_object_type << llendl;
- return;
- }
-
- panel->setVisible(visible);
-}
-
-void LLBottomTray::setTrayButtonVisibleIfPossible(EResizeState shown_object_type, bool visible, bool raise_notification)
-{
- if (!setVisibleAndFitWidths(shown_object_type, visible) && visible && raise_notification)
- {
- LLNotificationsUtil::add("BottomTrayButtonCanNotBeShown",
- LLSD(),
- LLSD(),
- LLNotificationFunctorRegistry::instance().DONOTHING);
- }
-}
-
-bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible)
-{
- // The Speak button is treated specially: if voice is enabled,
- // the button should be displayed no matter how much space we've got.
- if (object_type == RS_BUTTON_SPEAK)
- {
- showSpeakButton(visible);
- return true;
- }
-
- LLPanel* cur_panel = getButtonPanel(object_type);
- if (NULL == cur_panel)
- {
- lldebugs << "There is no object to process for state: " << object_type << llendl;
- return false;
- }
-
- bool is_set = true;
-
- if (visible)
- {
- // Assume that only chiclet panel can be auto-resized
- const S32 available_width =
- mChicletPanel->getParent()->getRect().getWidth() - mChicletPanel->getMinWidth();
-
- S32 preferred_width = mObjectDefaultWidthMap[object_type];
- S32 current_width = cur_panel->getRect().getWidth();
- S32 result_width = 0;
- bool decrease_width = false;
-
- // Mark this button to be shown
- mResizeState |= object_type;
-
- if (preferred_width > 0 && available_width >= preferred_width)
- {
- result_width = preferred_width;
- }
- else if (available_width >= current_width)
- {
- result_width = current_width;
- }
- else
- {
- // Calculate the possible shrunk width as difference between current and minimal widths
- const S32 chatbar_shrunk_width =
- mChatBarContainer->getRect().getWidth() - get_panel_min_width(mToolbarStack, mChatBarContainer);
-
- S32 sum_of_min_widths = get_panel_min_width(mToolbarStack, mSpeakPanel);
- S32 sum_of_curr_widths = get_curr_width(mSpeakPanel);
-
- resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
- const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
-
- for (; it != it_end; ++it)
- {
- LLPanel* cur_panel = getButtonPanel(*it);
- sum_of_min_widths += get_panel_min_width(mToolbarStack, cur_panel);
- sum_of_curr_widths += get_curr_width(cur_panel);
- }
-
- const S32 possible_shrunk_width =
- chatbar_shrunk_width + (sum_of_curr_widths - sum_of_min_widths);
-
- // Minimal width of current panel
- S32 minimal_width = 0;
- mToolbarStack->getPanelMinSize(cur_panel->getName(), &minimal_width);
-
- if ( (available_width + possible_shrunk_width) >= minimal_width)
- {
- // There is enough space for minimal width, but set the result_width
- // to preferred_width so buttons widths decreasing will be done in predefined order
- result_width = (preferred_width > 0) ? preferred_width : current_width;
- decrease_width = true;
- }
- else
- {
- // Nothing can be done, give up...
- return false;
- }
- }
-
- if (result_width != current_width)
- {
- cur_panel->reshape(result_width, cur_panel->getRect().getHeight());
- current_width = result_width;
- }
-
- is_set = processShowButton(object_type, current_width);
-
- // Shrink buttons if needed
- if (is_set && decrease_width)
- {
- processWidthDecreased( -result_width);
- }
- }
- else
- {
- const S32 delta_width = get_curr_width(cur_panel);
-
- setTrayButtonVisible(object_type, false);
-
- // Mark button NOT to show while future bottom tray extending
- mResizeState &= ~object_type;
-
- // Extend other buttons if need
- if (delta_width)
- {
- processWidthIncreased(delta_width);
- }
- }
- return is_set;
-}
-
-LLPanel* LLBottomTray::getButtonPanel(EResizeState button_type)
-{
- // Don't use the operator[] because it inserts a NULL value if the key is not found.
- if (mStateProcessedObjectMap.count(button_type) == 0)
- {
- llwarns << "Cannot find a panel for " << resizeStateToString(button_type) << llendl;
- llassert(mStateProcessedObjectMap.count(button_type) == 1);
- return NULL;
- }
-
- return mStateProcessedObjectMap[button_type];
-}
-
-void LLBottomTray::showWellButton(EResizeState object_type, bool visible)
-{
- llassert( ((RS_NOTIFICATION_WELL | RS_IM_WELL) & object_type) == object_type );
-
- const std::string panel_name = RS_IM_WELL == object_type ? "im_well_panel" : "notification_well_panel";
-
- LLView * panel = getChild<LLView>(panel_name);
-
- // if necessary visibility is set nothing to do here
- if (panel->getVisible() == (BOOL)visible) return;
-
- S32 panel_width = panel->getRect().getWidth();
- panel->setVisible(visible);
-
- if (visible)
- {
- // method assumes that input param is a negative value
- processWidthDecreased(-panel_width);
- }
- else
- {
- processWidthIncreased(panel_width);
- }
-}
-
-void LLBottomTray::processChatbarCustomization(S32 new_width)
-{
- if (NULL == mNearbyChatBar) return;
-
- const S32 delta_width = mChatBarContainer->getRect().getWidth() - new_width;
-
- if (delta_width == 0) return;
-
- mDesiredNearbyChatWidth = new_width;
-
- LLView * chiclet_layout_panel = mChicletPanel->getParent();
- const S32 chiclet_min_width = get_panel_min_width(mToolbarStack, chiclet_layout_panel);
- const S32 chiclet_panel_width = chiclet_layout_panel->getRect().getWidth();
- const S32 available_chiclet_shrink_width = chiclet_panel_width - chiclet_min_width;
- llassert(available_chiclet_shrink_width >= 0);
-
- if (delta_width > 0) // panel gets narrowly
- {
- S32 total_possible_width = delta_width + available_chiclet_shrink_width;
- processShowButtons(total_possible_width);
- processExtendButtons(total_possible_width);
- }
- // here (delta_width < 0) // panel gets wider
- else //if (-delta_width > available_chiclet_shrink_width)
- {
- S32 required_width = delta_width + available_chiclet_shrink_width;
- S32 buttons_freed_width = 0;
- processShrinkButtons(required_width, buttons_freed_width);
- processHideButtons(required_width, buttons_freed_width);
- }
-}
-
-// static
-std::string LLBottomTray::resizeStateToString(EResizeState state)
-{
- switch (state)
- {
- case RS_NORESIZE: return "RS_NORESIZE";
- case RS_CHICLET_PANEL: return "RS_CHICLET_PANEL";
- case RS_CHATBAR_INPUT: return "RS_CHATBAR_INPUT";
- case RS_BUTTON_SNAPSHOT: return "RS_BUTTON_SNAPSHOT";
- case RS_BUTTON_CAMERA: return "RS_BUTTON_CAMERA";
- case RS_BUTTON_MOVEMENT: return "RS_BUTTON_MOVEMENT";
- case RS_BUTTON_GESTURES: return "RS_BUTTON_GESTURES";
- case RS_BUTTON_SPEAK: return "RS_BUTTON_SPEAK";
- case RS_IM_WELL: return "RS_IM_WELL";
- case RS_NOTIFICATION_WELL: return "RS_NOTIFICATION_WELL";
- case RS_BUTTON_BUILD: return "RS_BUTTON_BUILD";
- case RS_BUTTON_SEARCH: return "RS_BUTTON_SEARCH";
- case RS_BUTTON_WORLD_MAP: return "RS_BUTTON_WORLD_MAP";
- case RS_BUTTON_MINI_MAP: return "RS_BUTTON_MINI_MAP";
- case RS_BUTTONS_CAN_BE_HIDDEN: return "RS_BUTTONS_CAN_BE_HIDDEN";
- // No default to track additions.
- }
- return "UNKNOWN_BUTTON";
-}
-
-//EOF
+/**
+ * @file llbottomtray.cpp
+ * @brief LLBottomTray class implementation
+ *
+ * $LicenseInfo:firstyear=2009&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h" // must be first include
+
+#define LLBOTTOMTRAY_CPP
+#include "llbottomtray.h"
+
+// library includes
+#include "llfloaterreg.h"
+#include "llflyoutbutton.h"
+#include "lllayoutstack.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+#include "lltexteditor.h"
+
+// newview includes
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llavataractions.h"
+#include "llchiclet.h"
+#include "llfloatercamera.h"
+#include "llhints.h"
+#include "llimfloater.h" // for LLIMFloater
+#include "llnearbychatbar.h"
+#include "llsidetray.h"
+#include "llspeakbutton.h"
+#include "llsplitbutton.h"
+#include "llsyswellwindow.h"
+#include "lltoolmgr.h"
+#include "llviewerparcelmgr.h"
+
+#include "llviewerwindow.h"
+#include "llsdserialize.h"
+
+// Distance from mouse down on which drag'n'drop should be started.
+#define DRAG_START_DISTANCE 3
+
+static const std::string SORTING_DATA_FILE_NAME = "bottomtray_buttons_order.xml";
+
+LLDefaultChildRegistry::Register<LLBottomtrayButton> bottomtray_button("bottomtray_button");
+
+// LLBottomtrayButton methods
+
+// virtual
+BOOL LLBottomtrayButton::handleHover(S32 x, S32 y, MASK mask)
+{
+ if (mCanDrag)
+ {
+ // pass hover to bottomtray
+ S32 screenX, screenY;
+ localPointToScreen(x, y, &screenX, &screenY);
+ LLBottomTray::getInstance()->onDraggableButtonHover(screenX, screenY);
+
+ return TRUE;
+ }
+ else
+ {
+ return LLButton::handleHover(x, y, mask);
+ }
+}
+//virtual
+BOOL LLBottomtrayButton::handleMouseUp(S32 x, S32 y, MASK mask)
+{
+ if (mCanDrag)
+ {
+ S32 screenX, screenY;
+ localPointToScreen(x, y, &screenX, &screenY);
+ // pass mouse up to bottomtray
+ LLBottomTray::getInstance()->onDraggableButtonMouseUp(this, screenX, screenY);
+ }
+ return LLButton::handleMouseUp(x, y, mask);
+}
+//virtual
+BOOL LLBottomtrayButton::handleMouseDown(S32 x, S32 y, MASK mask)
+{
+ if (mCanDrag)
+ {
+ S32 screenX, screenY;
+ localPointToScreen(x, y, &screenX, &screenY);
+ // pass mouse up to bottomtray
+ LLBottomTray::getInstance()->onDraggableButtonMouseDown(this, screenX, screenY);
+ }
+ return LLButton::handleMouseDown(x, y, mask);
+}
+
+static void update_build_button_enable_state()
+{
+ bool can_edit = LLToolMgr::getInstance()->canEdit();
+
+ LLBottomTray::getInstance()->getChildView("build_btn")->setEnabled(can_edit);
+}
+
+// Build time optimization, generate extern template once in .cpp file
+template class LLBottomTray* LLSingleton<class LLBottomTray>::getInstance();
+
+namespace
+{
+ const std::string& PANEL_CHICLET_NAME = "chiclet_list_panel";
+
+ S32 get_panel_min_width(LLLayoutStack* stack, LLView* panel)
+ {
+ S32 minimal_width = 0;
+ llassert(stack);
+ if ( stack && panel && panel->getVisible() )
+ {
+ stack->getPanelMinSize(panel->getName(), &minimal_width);
+ }
+ return minimal_width;
+ }
+
+ S32 get_panel_max_width(LLLayoutStack* stack, LLPanel* panel)
+ {
+ S32 max_width = 0;
+ llassert(stack);
+ if ( stack && panel && panel->getVisible() )
+ {
+ stack->getPanelMaxSize(panel->getName(), &max_width);
+ }
+ return max_width;
+ }
+
+ S32 get_curr_width(LLUICtrl* ctrl)
+ {
+ S32 cur_width = 0;
+ if ( ctrl && ctrl->getVisible() )
+ {
+ cur_width = ctrl->getRect().getWidth();
+ }
+ return cur_width;
+ }
+}
+
+class LLBottomTrayLite
+ : public LLPanel
+{
+public:
+ LLBottomTrayLite()
+ : mNearbyChatBar(NULL),
+ mChatBarContainer(NULL),
+ mGesturePanel(NULL)
+ {
+ mFactoryMap["chat_bar"] = LLCallbackMap(LLBottomTray::createNearbyChatBar, NULL);
+ buildFromFile("panel_bottomtray_lite.xml");
+ }
+
+ BOOL postBuild()
+ {
+ mNearbyChatBar = findChild<LLNearbyChatBar>("chat_bar");
+ mChatBarContainer = getChild<LLLayoutPanel>("chat_bar_layout_panel");
+ mGesturePanel = getChild<LLPanel>("gesture_panel");
+
+ // Hide "show_nearby_chat" button
+ if (mNearbyChatBar)
+ {
+ LLLineEditor* chat_box = mNearbyChatBar->getChatBox();
+ LLUICtrl* show_btn = mNearbyChatBar->getChild<LLUICtrl>("show_nearby_chat");
+ S32 delta_width = show_btn->getRect().getWidth();
+ show_btn->setVisible(FALSE);
+ chat_box->reshape(chat_box->getRect().getWidth() + delta_width, chat_box->getRect().getHeight());
+ }
+ return TRUE;
+ }
+
+ void onFocusLost()
+ {
+ if (gAgentCamera.cameraMouselook())
+ {
+ LLBottomTray::getInstance()->setVisible(FALSE);
+ }
+ }
+
+ LLNearbyChatBar* mNearbyChatBar;
+ LLLayoutPanel* mChatBarContainer;
+ LLPanel* mGesturePanel;
+};
+
+LLBottomTray::LLBottomTray(const LLSD&)
+: mChicletPanel(NULL),
+ mSpeakPanel(NULL),
+ mSpeakBtn(NULL),
+ mNearbyChatBar(NULL),
+ mChatBarContainer(NULL),
+ mNearbyCharResizeHandlePanel(NULL),
+ mToolbarStack(NULL),
+ mMovementButton(NULL),
+ mResizeState(RS_NORESIZE),
+ mBottomTrayContextMenu(NULL),
+ mCamButton(NULL),
+ mBottomTrayLite(NULL),
+ mIsInLiteMode(false),
+ mDragStarted(false),
+ mDraggedItem(NULL),
+ mLandingTab(NULL),
+ mCheckForDrag(false)
+{
+ // Firstly add ourself to IMSession observers, so we catch session events
+ // before chiclets do that.
+ LLIMMgr::getInstance()->addSessionObserver(this);
+
+ mFactoryMap["chat_bar"] = LLCallbackMap(LLBottomTray::createNearbyChatBar, NULL);
+
+ buildFromFile("panel_bottomtray.xml");
+
+ LLUICtrl::CommitCallbackRegistry::defaultRegistrar().add("CameraPresets.ChangeView", boost::bind(&LLFloaterCamera::onClickCameraItem, _2));
+
+ //this is to fix a crash that occurs because LLBottomTray is a singleton
+ //and thus is deleted at the end of the viewers lifetime, but to be cleanly
+ //destroyed LLBottomTray requires some subsystems that are long gone
+ //LLUI::getRootView()->addChild(this);
+
+ {
+ mBottomTrayLite = new LLBottomTrayLite();
+ mBottomTrayLite->setFollowsAll();
+ mBottomTrayLite->setVisible(FALSE);
+ }
+
+ mImageDragIndication = LLUI::getUIImage(getString("DragIndicationImageName"));
+ mDesiredNearbyChatWidth = mNearbyChatBar ? mNearbyChatBar->getRect().getWidth() : 0;
+}
+
+LLBottomTray::~LLBottomTray()
+{
+ if (!LLSingleton<LLIMMgr>::destroyed())
+ {
+ LLIMMgr::getInstance()->removeSessionObserver(this);
+ }
+
+ if (mNearbyChatBar)
+ {
+ // store custom width of chatbar panel.
+ S32 custom_width = mChatBarContainer->getRect().getWidth();
+ gSavedSettings.setS32("ChatBarCustomWidth", custom_width);
+ }
+
+ // emulate previous floater behavior to be hidden on startup.
+ // override effect of save_visibility=true.
+ // this attribute is necessary to button.initial_callback=Button.SetFloaterToggle works properly:
+ // i.g when floater changes its visibility - button changes its toggle state.
+ getChild<LLUICtrl>("build_btn")->setControlValue(false);
+ getChild<LLUICtrl>("search_btn")->setControlValue(false);
+ getChild<LLUICtrl>("world_map_btn")->setControlValue(false);
+}
+
+// *TODO Vadim: why void* ?
+void* LLBottomTray::createNearbyChatBar(void* userdata)
+{
+ return new LLNearbyChatBar();
+}
+
+LLNearbyChatBar* LLBottomTray::getNearbyChatBar()
+{
+ return mIsInLiteMode ? mBottomTrayLite->mNearbyChatBar : mNearbyChatBar;
+}
+
+LLIMChiclet* LLBottomTray::createIMChiclet(const LLUUID& session_id)
+{
+ LLIMChiclet::EType im_chiclet_type = LLIMChiclet::getIMSessionType(session_id);
+
+ switch (im_chiclet_type)
+ {
+ case LLIMChiclet::TYPE_IM:
+ return getChicletPanel()->createChiclet<LLIMP2PChiclet>(session_id);
+ case LLIMChiclet::TYPE_GROUP:
+ return getChicletPanel()->createChiclet<LLIMGroupChiclet>(session_id);
+ case LLIMChiclet::TYPE_AD_HOC:
+ return getChicletPanel()->createChiclet<LLAdHocChiclet>(session_id);
+ case LLIMChiclet::TYPE_UNKNOWN:
+ break;
+ }
+
+ return NULL;
+}
+
+//virtual
+void LLBottomTray::sessionAdded(const LLUUID& session_id, const std::string& name, const LLUUID& other_participant_id)
+{
+ if (!getChicletPanel()) return;
+
+ LLIMModel::LLIMSession* session = LLIMModel::getInstance()->findIMSession(session_id);
+ if (!session) return;
+
+ // no need to spawn chiclets for participants in P2P calls called through Avaline
+ if (session->isP2P() && session->isOtherParticipantAvaline()) return;
+
+ if (getChicletPanel()->findChiclet<LLChiclet>(session_id)) return;
+
+ LLIMChiclet* chiclet = createIMChiclet(session_id);
+ if(chiclet)
+ {
+ chiclet->setIMSessionName(name);
+ chiclet->setOtherParticipantId(other_participant_id);
+
+ LLIMFloater::onIMChicletCreated(session_id);
+
+ }
+ else
+ {
+ llerrs << "Could not create chiclet" << llendl;
+ }
+}
+
+//virtual
+void LLBottomTray::sessionRemoved(const LLUUID& session_id)
+{
+ if(getChicletPanel())
+ {
+ // IM floater should be closed when session removed and associated chiclet closed
+ LLIMFloater* iMfloater = LLFloaterReg::findTypedInstance<LLIMFloater>(
+ "impanel", session_id);
+ if (iMfloater != NULL)
+ {
+ iMfloater->closeFloater();
+ }
+
+ getChicletPanel()->removeChiclet(session_id);
+ }
+}
+
+void LLBottomTray::sessionIDUpdated(const LLUUID& old_session_id, const LLUUID& new_session_id)
+{
+ //this is only needed in case of outgoing ad-hoc/group chat sessions
+ LLChicletPanel* chiclet_panel = getChicletPanel();
+ if (chiclet_panel)
+ {
+ //it should be ad-hoc im chiclet or group im chiclet
+ LLChiclet* chiclet = chiclet_panel->findChiclet<LLChiclet>(old_session_id);
+ if (chiclet) chiclet->setSessionId(new_session_id);
+ }
+}
+
+S32 LLBottomTray::getTotalUnreadIMCount()
+{
+ return getChicletPanel()->getTotalUnreadIMCount();
+}
+
+// virtual
+void LLBottomTray::onChange(EStatusType status, const std::string &channelURI, bool proximal)
+{
+ // Time it takes to connect to voice channel might be pretty long,
+ // so don't expect user login or STATUS_VOICE_ENABLED to be followed by STATUS_JOINED.
+ BOOL enable = FALSE;
+
+ switch (status)
+ {
+ // Do not add STATUS_VOICE_ENABLED because voice chat is
+ // inactive until STATUS_JOINED
+ case STATUS_JOINED:
+ enable = TRUE;
+ break;
+ default:
+ enable = FALSE;
+ break;
+ }
+
+ // We have to enable/disable right and left parts of speak button separately (EXT-4648)
+ mSpeakBtn->setSpeakBtnEnabled(enable);
+ // skipped to avoid button blinking
+ if (status != STATUS_JOINING && status!= STATUS_LEFT_CHANNEL)
+ {
+ mSpeakBtn->setFlyoutBtnEnabled(LLVoiceClient::getInstance()->voiceEnabled() && LLVoiceClient::getInstance()->isVoiceWorking());
+ }
+}
+
+void LLBottomTray::onMouselookModeOut()
+{
+ mIsInLiteMode = false;
+ mBottomTrayLite->setVisible(FALSE);
+ mNearbyChatBar->getChatBox()->setText(mBottomTrayLite->mNearbyChatBar->getChatBox()->getText());
+ setVisible(TRUE);
+}
+
+void LLBottomTray::onMouselookModeIn()
+{
+ setVisible(FALSE);
+
+ // Attach the lite bottom tray
+ if (getParent() && mBottomTrayLite->getParent() != getParent())
+ getParent()->addChild(mBottomTrayLite);
+
+ mBottomTrayLite->setShape(getLocalRect());
+ mBottomTrayLite->mNearbyChatBar->getChatBox()->setText(mNearbyChatBar->getChatBox()->getText());
+ mBottomTrayLite->mGesturePanel->setVisible(gSavedSettings.getBOOL("ShowGestureButton"));
+
+ mIsInLiteMode = true;
+}
+
+//virtual
+// setVisible used instead of onVisibilityChange, since LLAgent calls it on entering/leaving mouselook mode.
+// If bottom tray is already visible in mouselook mode, then onVisibilityChange will not be called from setVisible(true),
+void LLBottomTray::setVisible(BOOL visible)
+{
+ if (mIsInLiteMode)
+ {
+ mBottomTrayLite->setVisible(visible);
+ }
+ else
+ {
+ LLPanel::setVisible(visible);
+ }
+}
+
+S32 LLBottomTray::notifyParent(const LLSD& info)
+{
+ if(info.has("well_empty")) // implementation of EXT-3397
+ {
+ const std::string chiclet_name = info["well_name"];
+
+ // only "im_well" or "notification_well" names are expected.
+ // They are set in panel_bottomtray.xml in <chiclet_im_well> & <chiclet_notification>
+ llassert("im_well" == chiclet_name || "notification_well" == chiclet_name);
+
+ BOOL should_be_visible = !info["well_empty"];
+ showWellButton("im_well" == chiclet_name ? RS_IM_WELL : RS_NOTIFICATION_WELL, should_be_visible);
+ return 1;
+ }
+
+ if (info.has("action") && info["action"] == "resize")
+ {
+ const std::string& name = info["view_name"];
+
+ // expected only resize of nearby chatbar
+ if (mChatBarContainer->getName() != name) return LLPanel::notifyParent(info);
+
+ const S32 new_width = info["new_width"];
+
+ processChatbarCustomization(new_width);
+
+ return 2;
+ }
+ return LLPanel::notifyParent(info);
+}
+
+void LLBottomTray::showBottomTrayContextMenu(S32 x, S32 y, MASK mask)
+{
+ // We should show BottomTrayContextMenu in last turn
+ if (mBottomTrayContextMenu && !LLMenuGL::sMenuContainer->getVisibleMenu())
+ {
+ //there are no other context menu (IM chiclet etc ), so we can show BottomTrayContextMenu
+
+ updateContextMenu(x, y, mask);
+ mBottomTrayContextMenu->buildDrawLabels();
+ mBottomTrayContextMenu->updateParent(LLMenuGL::sMenuContainer);
+ LLMenuGL::showPopup(this, mBottomTrayContextMenu, x, y);
+
+ }
+}
+
+void LLBottomTray::updateContextMenu(S32 x, S32 y, MASK mask)
+{
+ LLUICtrl* edit_box = mNearbyChatBar->getChild<LLUICtrl>("chat_box");
+
+ S32 local_x = x - mChatBarContainer->getRect().mLeft - edit_box->getRect().mLeft;
+ S32 local_y = y - mChatBarContainer->getRect().mBottom - edit_box->getRect().mBottom;
+
+ bool in_edit_box = edit_box->pointInView(local_x, local_y);
+
+ mBottomTrayContextMenu->setItemVisible("Separator", in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Cut", in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Copy", in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Paste", in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Delete", in_edit_box);
+ mBottomTrayContextMenu->setItemVisible("NearbyChatBar_Select_All", in_edit_box);
+}
+
+void LLBottomTray::showGestureButton(BOOL visible)
+{
+ setTrayButtonVisibleIfPossible(RS_BUTTON_GESTURES, visible);
+}
+
+void LLBottomTray::showMoveButton(BOOL visible)
+{
+ setTrayButtonVisibleIfPossible(RS_BUTTON_MOVEMENT, visible);
+}
+
+void LLBottomTray::showCameraButton(BOOL visible)
+{
+ setTrayButtonVisibleIfPossible(RS_BUTTON_CAMERA, visible);
+}
+
+void LLBottomTray::showSnapshotButton(BOOL visible)
+{
+ setTrayButtonVisibleIfPossible(RS_BUTTON_SNAPSHOT, visible);
+}
+
+void LLBottomTray::showSpeakButton(bool visible)
+{
+ // Show/hide the button
+ setTrayButtonVisible(RS_BUTTON_SPEAK, visible);
+
+ // and adjust other panels according to the occupied/freed space.
+ const S32 panel_width = mSpeakPanel->getRect().getWidth();
+ if (visible)
+ {
+ processWidthDecreased(-panel_width);
+ }
+ else
+ {
+ processWidthIncreased(panel_width);
+ }
+}
+
+void LLBottomTray::toggleMovementControls()
+{
+ if (mMovementButton)
+ mMovementButton->onCommit();
+}
+
+void LLBottomTray::toggleCameraControls()
+{
+ if (mCamButton)
+ mCamButton->onCommit();
+}
+
+BOOL LLBottomTray::postBuild()
+{
+ LLHints::registerHintTarget("bottom_tray", LLView::getHandle());
+ LLHints::registerHintTarget("dest_guide_btn", getChild<LLUICtrl>("destination_btn")->getHandle());
+ LLHints::registerHintTarget("avatar_picker_btn", getChild<LLUICtrl>("avatar_btn")->getHandle());
+
+ LLUICtrl::CommitCallbackRegistry::currentRegistrar().add("NearbyChatBar.Action", boost::bind(&LLBottomTray::onContextMenuItemClicked, this, _2));
+ LLUICtrl::EnableCallbackRegistry::currentRegistrar().add("NearbyChatBar.EnableMenuItem", boost::bind(&LLBottomTray::onContextMenuItemEnabled, this, _2));
+
+ mBottomTrayContextMenu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_bottomtray.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ gMenuHolder->addChild(mBottomTrayContextMenu);
+
+ mNearbyChatBar = findChild<LLNearbyChatBar>("chat_bar");
+ LLHints::registerHintTarget("chat_bar", mNearbyChatBar->LLView::getHandle());
+
+ mChatBarContainer = getChild<LLLayoutPanel>("chat_bar_layout_panel");
+ mNearbyCharResizeHandlePanel = getChild<LLPanel>("chat_bar_resize_handle_panel");
+
+ mToolbarStack = getChild<LLLayoutStack>("toolbar_stack");
+ mMovementButton = getChild<LLButton>("movement_btn");
+ LLHints::registerHintTarget("move_btn", mMovementButton->getHandle());
+ mCamButton = getChild<LLButton>("camera_btn");
+ setRightMouseDownCallback(boost::bind(&LLBottomTray::showBottomTrayContextMenu,this, _2, _3,_4));
+
+ mSpeakPanel = getChild<LLPanel>("speak_panel");
+ mSpeakBtn = getChild<LLSpeakButton>("talk");
+
+ // Both parts of speak button should be initially disabled because
+ // it takes some time between logging in to world and connecting to voice channel.
+ mSpeakBtn->setSpeakBtnEnabled(false);
+ mSpeakBtn->setFlyoutBtnEnabled(false);
+
+ // Localization tool doesn't understand custom buttons like <talk_button>
+ mSpeakBtn->setSpeakToolTip( getString("SpeakBtnToolTip") );
+ mSpeakBtn->setShowToolTip( getString("VoiceControlBtnToolTip") );
+
+ // Registering Chat Bar to receive Voice client status change notifications.
+ LLVoiceClient::getInstance()->addObserver(this);
+
+ mNearbyChatBar->getChatBox()->setContextMenu(NULL);
+
+ mChicletPanel = getChild<LLChicletPanel>("chiclet_list");
+
+ initResizeStateContainers();
+
+ setButtonsControlsAndListeners();
+
+ initButtonsVisibility();
+
+ // update wells visibility:
+ showWellButton(RS_IM_WELL, !LLIMWellWindow::getInstance()->isWindowEmpty());
+ showWellButton(RS_NOTIFICATION_WELL, !LLNotificationWellWindow::getInstance()->isWindowEmpty());
+
+ loadButtonsOrder();
+
+ LLViewerParcelMgr::getInstance()->addAgentParcelChangedCallback(boost::bind(&update_build_button_enable_state));
+
+ return TRUE;
+}
+
+//Drag-n-drop
+
+void LLBottomTray::onDraggableButtonMouseDown(LLUICtrl* ctrl, S32 x, S32 y)
+{
+ if (ctrl == NULL) return;
+ LLView* parent_view = ctrl->getParent();
+ if(parent_view != NULL)
+ {
+ // we actually drag'n'drop panel (not button) in code, so have to find a parent
+ // of button which called this method on mouse down.
+ LLPanel* parent = dynamic_cast<LLPanel*>(parent_view);
+ // It may happen that we clicked not usual button, but button inside widget(speak, gesture)
+ // so we'll need to get a level higher to reach layout panel as a parent.
+ if(parent == NULL) parent = dynamic_cast<LLPanel*>(parent_view->getParent());
+ if (parent && parent->getVisible())
+ {
+ mDraggedItem = parent;
+ mCheckForDrag = true;
+ mStartX = x;
+ mStartY = y;
+ }
+ }
+}
+
+LLPanel* LLBottomTray::findChildPanelByLocalCoords(S32 x, S32 y)
+{
+ LLPanel* ctrl = 0;
+ S32 screenX, screenY;
+ const child_list_t* list = mToolbarStack->getChildList();
+
+ localPointToScreen(x, y, &screenX, &screenY);
+
+ // look for a child panel which contains the point (screenX, screenY) in it's rectangle
+ for (child_list_const_iter_t i = list->begin(); i != list->end(); ++i)
+ {
+ LLRect rect;
+ localRectToScreen((*i)->getRect(), &rect);
+
+ if (rect.pointInRect(screenX, screenY))
+ {
+ ctrl = dynamic_cast<LLPanel*>(*i);
+ break;
+ }
+ }
+
+ return ctrl;
+}
+
+void LLBottomTray::onDraggableButtonHover(S32 x, S32 y)
+{
+ // if mouse down on draggable item was done, check whether we should start DnD
+ if (mCheckForDrag)
+ {
+ // Start drag'n'drop if mouse cursor was dragged away frome mouse down location enough
+ if(sqrt((float)((mStartX-x)*(mStartX-x)+(mStartY-y)*(mStartY-y))) > DRAG_START_DISTANCE)
+ {
+ mDragStarted = true;
+ mCheckForDrag = false;
+ }
+ }
+ if (mDragStarted)
+ {
+ // Check whether the cursor is over draggable area, find which panel it is and set is as
+ // landing tab for drag'n'drop
+ if(isCursorOverDraggableArea(x, y))
+ {
+ LLPanel* panel = findChildPanelByLocalCoords(x,y);
+ if (panel && panel != mDraggedItem) mLandingTab = panel;
+ gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROWDRAG);
+ }
+ else
+ {
+ gViewerWindow->getWindow()->setCursor(UI_CURSOR_NO);
+ }
+ }
+ else
+ {
+ // Reset cursor in case you move your mouse from the drag handle to a button.
+ getWindow()->setCursor(UI_CURSOR_ARROW);
+
+ }
+}
+
+bool LLBottomTray::isCursorOverDraggableArea(S32 x, S32 y)
+{
+ // Draggable area lasts from the nearby chat input resize handle
+ // to the chiclet area (exlusively).
+ bool result = getRect().pointInRect(x, y);
+ result = result && mNearbyCharResizeHandlePanel->calcScreenRect().mRight < x;
+ result = result && mChicletPanel->calcScreenRect().mRight > x;
+ return result;
+}
+
+void LLBottomTray::updateButtonsOrdersAfterDnD()
+{
+ // *TODO: change implementation of this method to support simplify it
+ // (and according to future possible changes in the way button order is saved between sessions).
+ state_object_map_t::const_iterator it = mStateProcessedObjectMap.begin();
+ state_object_map_t::const_iterator it_end = mStateProcessedObjectMap.end();
+ EResizeState dragged_state = RS_NORESIZE;
+ EResizeState landing_state = RS_NORESIZE;
+ bool landing_state_found = false;
+ // Find states for dragged item and landing tab
+ for (; it != it_end; ++it)
+ {
+ if (it->second == mDraggedItem)
+ {
+ dragged_state = it->first;
+ }
+ else if (it->second == mLandingTab)
+ {
+ landing_state = it->first;
+ landing_state_found = true;
+ }
+ }
+
+ if (dragged_state == RS_NORESIZE)
+ {
+ llwarns << "Cannot determine what button is being dragged" << llendl;
+ llassert(dragged_state != RS_NORESIZE);
+ return;
+ }
+
+ lldebugs << "Will place " << resizeStateToString(dragged_state)
+ << " before " << resizeStateToString(landing_state) << llendl;
+
+ // Update order of buttons according to drag'n'drop
+ mButtonsOrder.erase(std::find(mButtonsOrder.begin(), mButtonsOrder.end(), dragged_state));
+ if (!landing_state_found && mLandingTab == getChild<LLPanel>(PANEL_CHICLET_NAME))
+ {
+ mButtonsOrder.push_back(dragged_state);
+ }
+ else
+ {
+ if (!landing_state_found) landing_state = RS_BUTTON_SPEAK; // just a random fallback
+ mButtonsOrder.insert(std::find(mButtonsOrder.begin(), mButtonsOrder.end(), landing_state), dragged_state);
+ }
+
+ // Synchronize button process order with their order
+ resize_state_vec_t::const_iterator it1 = mButtonsOrder.begin();
+ const resize_state_vec_t::const_iterator it_end1 = mButtonsOrder.end();
+ resize_state_vec_t::iterator it2 = mButtonsProcessOrder.begin();
+ for (; it1 != it_end1; ++it1)
+ {
+ // Skip Speak because it is not in mButtonsProcessOrder(it's the reason why mButtonsOrder was introduced).
+ // If any other draggable items will be added to bottomtray later, they should also be skipped here.
+ if (*it1 != RS_BUTTON_SPEAK)
+ {
+ *it2 = *it1;
+ ++it2;
+ }
+ }
+
+ saveButtonsOrder();
+}
+
+void LLBottomTray::saveButtonsOrder()
+{
+ std::string user_dir = gDirUtilp->getLindenUserDir();
+ if (user_dir.empty()) return;
+
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME);
+ LLSD settings_llsd;
+ int i = 0;
+ const resize_state_vec_t::const_iterator it_end = mButtonsOrder.end();
+ // we use numbers as keys for map which is saved in file and contains resize states as its values
+ for (resize_state_vec_t::const_iterator it = mButtonsOrder.begin(); it != it_end; ++it, i++)
+ {
+ std::string str = llformat("%d", i);
+ settings_llsd[str] = *it;
+ }
+ llofstream file;
+ file.open(filename);
+ LLSDSerialize::toPrettyXML(settings_llsd, file);
+}
+
+void LLBottomTray::loadButtonsOrder()
+{
+ // load per-resident sorting information
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT, SORTING_DATA_FILE_NAME);
+
+ LLSD settings_llsd;
+ llifstream file;
+ file.open(filename);
+ if (!file.is_open()) return;
+
+ LLSDSerialize::fromXML(settings_llsd, file);
+
+
+ mButtonsOrder.clear();
+ mButtonsProcessOrder.clear();
+ int i = 0;
+ // getting button order from file
+ for (LLSD::map_const_iterator iter = settings_llsd.beginMap();
+ iter != settings_llsd.endMap(); ++iter, ++i)
+ {
+ std::string str = llformat("%d", i);
+ EResizeState state = (EResizeState)settings_llsd[str].asInteger();
+ mButtonsOrder.push_back(state);
+ // RS_BUTTON_SPEAK is skipped, because it shouldn't be in mButtonsProcessOrder (it does not hide or shrink).
+ if (state != RS_BUTTON_SPEAK)
+ {
+ mButtonsProcessOrder.push_back(state);
+ }
+ }
+
+ // There are other panels in layout stack order of which is not saved. Also, panels order of which is saved,
+ // are already in layout stack but in wrong order. The most convenient way to place them is moving them
+ // to front one by one (because in this case we don't have to pass the panel before which we want to insert our
+ // panel to movePanel()). So panels are moved in order from the end of mButtonsOrder vector(reverse iterator is used).
+ const resize_state_vec_t::const_reverse_iterator it_end = mButtonsOrder.rend();
+ // placing panels in layout stack according to button order which we loaded in previous for
+ for (resize_state_vec_t::const_reverse_iterator it = mButtonsOrder.rbegin(); it != it_end; ++it, ++i)
+ {
+ LLPanel* panel_to_move = getButtonPanel(*it);
+ mToolbarStack->movePanel(panel_to_move, NULL, true); // prepend
+ }
+ // Nearbychat is not stored in order settings file, but it must be the first of the panels, so moving it
+ // (along with its drag handle) manually here.
+ mToolbarStack->movePanel(getChild<LLLayoutPanel>("chat_bar_resize_handle_panel"), NULL, true);
+ mToolbarStack->movePanel(mChatBarContainer, NULL, true);
+}
+
+void LLBottomTray::onDraggableButtonMouseUp(LLUICtrl* ctrl, S32 x, S32 y)
+{
+ //if mouse up happened over area where drop is possible, change order of buttons
+ if (mLandingTab != NULL && mDraggedItem != NULL && mDragStarted)
+ {
+ if(isCursorOverDraggableArea(x, y))
+ {
+ // change order of panels in layout stack
+ mToolbarStack->movePanel(mDraggedItem, (LLPanel*)mLandingTab);
+ // change order of buttons in order vectors
+ updateButtonsOrdersAfterDnD();
+ }
+ }
+ gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
+ mDragStarted = false;
+ mDraggedItem = NULL;
+ mLandingTab = NULL;
+ mCheckForDrag = false;
+}
+
+void LLBottomTray::draw()
+{
+ LLPanel::draw();
+ if (mLandingTab)
+ {
+ static S32 w = mImageDragIndication->getWidth();
+ static S32 h = mImageDragIndication->getHeight();
+ LLRect rect = mLandingTab->calcScreenRect();
+ mImageDragIndication->draw(rect.mLeft - w/2, rect.getHeight(), w, h);
+ }
+ getChild<LLButton>("show_profile_btn")->setToggleState(LLAvatarActions::profileVisible(gAgent.getID()));
+
+ LLPanel* panel = LLSideTray::getInstance()->getPanel("panel_people");
+ if (panel && panel->isInVisibleChain())
+ {
+ getChild<LLButton>("show_people_button")->setToggleState(true);
+ }
+ else
+ {
+ getChild<LLButton>("show_people_button")->setToggleState(false);
+ }
+
+ LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser"));
+ bool help_floater_visible = (help_browser && help_browser->isInVisibleChain());
+
+ getChild<LLButton>("show_help_btn")->setToggleState(help_floater_visible);
+
+
+}
+
+bool LLBottomTray::onContextMenuItemEnabled(const LLSD& userdata)
+{
+ std::string item = userdata.asString();
+ LLLineEditor* edit_box = mNearbyChatBar->findChild<LLLineEditor>("chat_box");
+
+ if (item == "can_cut")
+ {
+ return edit_box->canCut();
+ }
+ else if (item == "can_copy")
+ {
+ return edit_box->canCopy();
+ }
+ else if (item == "can_paste")
+ {
+ return edit_box->canPaste();
+ }
+ else if (item == "can_delete")
+ {
+ return edit_box->canDoDelete();
+ }
+ else if (item == "can_select_all")
+ {
+ return edit_box->canSelectAll() && (edit_box->getLength()>0);
+ }
+ return true;
+}
+
+
+void LLBottomTray::onContextMenuItemClicked(const LLSD& userdata)
+{
+ std::string item = userdata.asString();
+ LLLineEditor* edit_box = mNearbyChatBar->findChild<LLLineEditor>("chat_box");
+
+ if (item == "cut")
+ {
+ edit_box->cut();
+ }
+ else if (item == "copy")
+ {
+ edit_box->copy();
+ }
+ else if (item == "paste")
+ {
+ edit_box->paste();
+ edit_box->setFocus(TRUE);
+ }
+ else if (item == "delete")
+ {
+ edit_box->doDelete();
+ }
+ else if (item == "select_all")
+ {
+ edit_box->selectAll();
+ }
+}
+
+void LLBottomTray::log(LLView* panel, const std::string& descr)
+{
+ if (NULL == panel) return;
+ LLView* layout = panel->getParent();
+ lldebugs << descr << ": "
+ << "panel: " << panel->getName()
+ << ", rect: " << panel->getRect()
+
+
+ << "layout: " << layout->getName()
+ << ", rect: " << layout->getRect()
+ << llendl
+ ;
+}
+
+void LLBottomTray::reshape(S32 width, S32 height, BOOL called_from_parent)
+{
+ static S32 debug_calling_number = 0;
+ lldebugs << "**************************************** " << ++debug_calling_number << llendl;
+
+ S32 current_width = getRect().getWidth();
+ S32 delta_width = width - current_width;
+ lldebugs << "Reshaping: "
+ << ", width: " << width
+ << ", cur width: " << current_width
+ << ", delta_width: " << delta_width
+ << ", called_from_parent: " << called_from_parent
+ << llendl;
+
+ if (mNearbyChatBar) log(mNearbyChatBar, "before");
+ if (mChicletPanel) log(mChicletPanel, "before");
+
+ // stores width size on which bottom tray is less than width required by its children. EXT-991
+ static S32 extra_shrink_width = 0;
+ bool should_be_reshaped = true;
+
+ if (mChicletPanel && mToolbarStack && mNearbyChatBar)
+ {
+ // Firstly, update layout stack to ensure we deal with correct panel sizes.
+ {
+ BOOL saved_anim = mToolbarStack->getAnimate();
+ // Set chiclet panel to be autoresized by default.
+ mToolbarStack->updatePanelAutoResize(PANEL_CHICLET_NAME, TRUE);
+ // Disable animation to prevent layout updating in several frames.
+ mToolbarStack->setAnimate(FALSE);
+ // Force the updating of layout to reset panels collapse factor.
+ mToolbarStack->updateLayout();
+ // Restore animate state.
+ mToolbarStack->setAnimate(saved_anim);
+ }
+
+ // bottom tray is narrowed
+ if (delta_width < 0)
+ {
+ if (extra_shrink_width > 0)
+ {
+ // is world rect was extra shrunk and decreasing again only update this value
+ // to delta_width negative
+ extra_shrink_width -= delta_width; // use "-=" because delta_width is negative
+ should_be_reshaped = false;
+ }
+ else
+ {
+ extra_shrink_width = processWidthDecreased(delta_width);
+
+ // increase new width to extra_shrink_width value to not reshape less than bottom tray minimum
+ width += extra_shrink_width;
+ }
+ }
+ // bottom tray is widen
+ else
+ {
+ if (extra_shrink_width > delta_width)
+ {
+ // Less than minimum width is more than increasing (delta_width)
+ // only reduce it value and make no reshape
+ extra_shrink_width -= delta_width;
+ should_be_reshaped = false;
+ }
+ else
+ {
+ if (extra_shrink_width > 0)
+ {
+ // If we have some extra shrink width let's reduce delta_width & width
+ delta_width -= extra_shrink_width;
+ width -= extra_shrink_width;
+ extra_shrink_width = 0;
+ }
+ processWidthIncreased(delta_width);
+ }
+ }
+ }
+
+ if (should_be_reshaped)
+ {
+ lldebugs << "Reshape all children with width: " << width << llendl;
+ LLPanel::reshape(width, height, called_from_parent);
+ }
+
+ if (mNearbyChatBar) log(mNearbyChatBar, "after");
+ if (mChicletPanel) log(mChicletPanel, "after");
+
+
+ // Restore width of the chatbar on first reshape.
+ // we can not to do this from postBuild because reshape is called from parent view on startup
+ // creation after it and reset width according to resize logic.
+ static bool needs_restore_custom_state = true;
+ if (mChatBarContainer && needs_restore_custom_state)
+ {
+ // restore custom width of chatbar panel.
+ S32 new_width = gSavedSettings.getS32("ChatBarCustomWidth");
+ if (new_width > 0)
+ {
+ mDesiredNearbyChatWidth = new_width;
+ processChatbarCustomization(new_width);
+ mChatBarContainer->reshape(new_width, mChatBarContainer->getRect().getHeight());
+ }
+ needs_restore_custom_state = false;
+ }
+
+}
+
+S32 LLBottomTray::processWidthDecreased(S32 delta_width)
+{
+ bool still_should_be_processed = true;
+
+ const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
+ const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
+
+ // There are four steps of processing width decrease. If in one of them required width was reached,
+ // further are not needed.
+ // 1. Decreasing width of chiclet panel.
+ if (chiclet_panel_width > chiclet_panel_min_width)
+ {
+ // we have some space to decrease chiclet panel
+ S32 panel_delta_min = chiclet_panel_width - chiclet_panel_min_width;
+
+ S32 delta_panel = llmin(-delta_width, panel_delta_min);
+
+ lldebugs << "delta_width: " << delta_width
+ << ", panel_delta_min: " << panel_delta_min
+ << ", delta_panel: " << delta_panel
+ << llendl;
+
+ // is chiclet panel width enough to process resizing?
+ delta_width += panel_delta_min;
+
+ still_should_be_processed = delta_width < 0;
+
+ mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - delta_panel, mChicletPanel->getParent()->getRect().getHeight());
+ log(mChicletPanel, "after processing panel decreasing via chiclet panel");
+
+ lldebugs << "RS_CHICLET_PANEL"
+ << ", delta_width: " << delta_width
+ << llendl;
+ }
+
+ S32 buttons_freed_width = 0;
+ // 2. Decreasing width of buttons.
+ if (still_should_be_processed)
+ {
+ processShrinkButtons(delta_width, buttons_freed_width);
+ }
+ // 3. Decreasing width of nearby chat.
+ const S32 chatbar_panel_min_width = get_panel_min_width(mToolbarStack, mChatBarContainer);
+ const S32 chatbar_panel_width = mChatBarContainer->getRect().getWidth();
+ if (still_should_be_processed && chatbar_panel_width > chatbar_panel_min_width)
+ {
+ // we have some space to decrease chatbar panel
+ S32 panel_delta_min = chatbar_panel_width - chatbar_panel_min_width;
+
+ S32 delta_panel = llmin(-delta_width, panel_delta_min);
+
+ // whether chatbar panel width is enough to process resizing?
+ delta_width += panel_delta_min;
+
+ still_should_be_processed = delta_width < 0;
+
+ // chatbar should only be shrunk here, not stretched
+ if(delta_panel > 0)
+ {
+ mChatBarContainer->reshape(mNearbyChatBar->getRect().getWidth() - delta_panel, mChatBarContainer->getRect().getHeight());
+ }
+
+ log(mNearbyChatBar, "after processing panel decreasing via nearby chatbar panel");
+
+ lldebugs << "RS_CHATBAR_INPUT"
+ << ", delta_panel: " << delta_panel
+ << ", delta_width: " << delta_width
+ << llendl;
+ }
+
+ S32 extra_shrink_width = 0;
+ // 4. Hiding buttons if needed.
+ if (still_should_be_processed)
+ {
+ processHideButtons(delta_width, buttons_freed_width);
+
+ if (delta_width < 0)
+ {
+ extra_shrink_width = -delta_width;
+ llwarns << "There is no enough width to reshape all children: "
+ << extra_shrink_width << llendl;
+ }
+
+ if (buttons_freed_width > 0)
+ {
+ S32 nearby_needed_width = mDesiredNearbyChatWidth - mNearbyChatBar->getRect().getWidth();
+ if (nearby_needed_width > 0)
+ {
+ S32 compensative_width = nearby_needed_width > buttons_freed_width ? buttons_freed_width : nearby_needed_width;
+ log(mNearbyChatBar, "before applying compensative width");
+ mChatBarContainer->reshape(mChatBarContainer->getRect().getWidth() + compensative_width, mChatBarContainer->getRect().getHeight() );
+ log(mNearbyChatBar, "after applying compensative width");
+ lldebugs << buttons_freed_width << llendl;
+ }
+ }
+ }
+
+ return extra_shrink_width;
+}
+
+void LLBottomTray::processWidthIncreased(S32 delta_width)
+{
+ if (delta_width <= 0) return;
+
+ const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
+ static const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
+
+ const S32 available_width_chiclet = chiclet_panel_width - chiclet_panel_min_width;
+
+ // how many room we have to show hidden buttons
+ S32 total_available_width = delta_width + available_width_chiclet;
+
+ lldebugs << "Processing extending, available width:"
+ << ", chiclets - " << available_width_chiclet
+ << ", total - " << total_available_width
+ << llendl;
+
+ S32 available_width = total_available_width;
+
+ processShowButtons(available_width);
+
+ // if we have to show/extend some buttons but resized delta width is not enough...
+ S32 processed_width = total_available_width - available_width;
+ if (processed_width > delta_width)
+ {
+ // ... let's shrink nearby chat & chiclet panels
+ S32 required_to_process_width = processed_width;
+
+ // 1. use delta width of resizing
+ required_to_process_width -= delta_width;
+
+ // 2. use width available via decreasing of chiclet panel
+ if (required_to_process_width > 0)
+ {
+ mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - required_to_process_width, mChicletPanel->getParent()->getRect().getHeight());
+ log(mChicletPanel, "after applying compensative width for chiclets: ");
+ lldebugs << required_to_process_width << llendl;
+ }
+
+ }
+
+ // shown buttons take some space, rest should be processed by nearby chatbar & chiclet panels
+ delta_width -= processed_width;
+
+
+ // how many space can nearby chatbar take?
+ S32 chatbar_panel_width_ = mChatBarContainer->getRect().getWidth();
+ if (delta_width > 0 && chatbar_panel_width_ < mDesiredNearbyChatWidth)
+ {
+ S32 delta_panel_max = mDesiredNearbyChatWidth - chatbar_panel_width_;
+ S32 delta_panel = llmin(delta_width, delta_panel_max);
+ lldebugs << "Unprocesed delta width: " << delta_width
+ << ", can be applied to chatbar: " << delta_panel_max
+ << ", will be applied: " << delta_panel
+ << llendl;
+
+ delta_width -= delta_panel_max;
+ mChatBarContainer->reshape(chatbar_panel_width_ + delta_panel, mChatBarContainer->getRect().getHeight());
+ log(mNearbyChatBar, "applied unprocessed delta width");
+ }
+ if (delta_width > 0)
+ {
+ processExtendButtons(delta_width);
+ }
+}
+
+void LLBottomTray::processShowButtons(S32& available_width)
+{
+ // process buttons from left to right
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+ for (; it != it_end; ++it)
+ {
+ // is there available space?
+ if (available_width <= 0) break;
+
+ // try to show next button
+ processShowButton(*it, available_width);
+ }
+}
+
+bool LLBottomTray::processShowButton(EResizeState shown_object_type, S32& available_width)
+{
+ lldebugs << "Trying to show object type: " << shown_object_type << llendl;
+
+ LLPanel* panel = getButtonPanel(shown_object_type);
+ if (NULL == panel)
+ {
+ lldebugs << "There is no object to process for state: " << shown_object_type << llendl;
+ return false;
+ }
+ bool can_be_shown = canButtonBeShown(shown_object_type);
+ if (can_be_shown)
+ {
+ //validate if we have enough room to show this button
+ const S32 required_width = panel->getRect().getWidth();
+ can_be_shown = available_width >= required_width;
+ if (can_be_shown)
+ {
+ available_width -= required_width;
+
+ setTrayButtonVisible(shown_object_type, true);
+
+ lldebugs << "processed object type: " << shown_object_type
+ << ", rest available width: " << available_width
+ << llendl;
+ mResizeState &= ~shown_object_type;
+ }
+ }
+ return can_be_shown;
+}
+
+void LLBottomTray::processHideButtons(S32& required_width, S32& buttons_freed_width)
+{
+ // process buttons from right to left
+ resize_state_vec_t::const_reverse_iterator it = mButtonsProcessOrder.rbegin();
+ const resize_state_vec_t::const_reverse_iterator it_end = mButtonsProcessOrder.rend();
+
+ for (; it != it_end; ++it)
+ {
+ // is it still necessary to hide a button?
+ if (required_width >= 0) break;
+
+ // try to hide next button
+ processHideButton(*it, required_width, buttons_freed_width);
+ }
+}
+
+void LLBottomTray::processHideButton(EResizeState processed_object_type, S32& required_width, S32& buttons_freed_width)
+{
+ lldebugs << "Trying to hide object type: " << processed_object_type << llendl;
+ LLPanel* panel = getButtonPanel(processed_object_type);
+ if (NULL == panel)
+ {
+ lldebugs << "There is no object to process for state: " << processed_object_type << llendl;
+ return;
+ }
+
+ if (panel->getVisible())
+ {
+ required_width += panel->getRect().getWidth();
+
+ if (required_width > 0)
+ {
+ buttons_freed_width += required_width;
+ }
+
+ setTrayButtonVisible(processed_object_type, false);
+
+ mResizeState |= processed_object_type;
+
+ lldebugs << "processing object type: " << processed_object_type
+ << ", buttons_freed_width: " << buttons_freed_width
+ << llendl;
+ }
+}
+
+void LLBottomTray::processShrinkButtons(S32& required_width, S32& buttons_freed_width)
+{
+ // process buttons from right to left
+ resize_state_vec_t::const_reverse_iterator it = mButtonsProcessOrder.rbegin();
+ const resize_state_vec_t::const_reverse_iterator it_end = mButtonsProcessOrder.rend();
+
+ // iterate through buttons in the mButtonsProcessOrder first
+ for (; it != it_end; ++it)
+ {
+ // is it still necessary to hide a button?
+ if (required_width >= 0) break;
+
+ // try to shrink next button
+ processShrinkButton(*it, required_width);
+ }
+
+ // then shrink Speak button
+ if (required_width < 0)
+ {
+ S32 panel_min_width = 0;
+ std::string panel_name = mSpeakPanel->getName();
+ bool success = mToolbarStack->getPanelMinSize(panel_name, &panel_min_width);
+ if (!success)
+ {
+ lldebugs << "Panel was not found to get its min width: " << panel_name << llendl;
+ }
+ else
+ {
+ S32 panel_width = mSpeakPanel->getRect().getWidth();
+ S32 possible_shrink_width = panel_width - panel_min_width;
+
+ if (possible_shrink_width > 0)
+ {
+ mSpeakBtn->setLabelVisible(false);
+ mSpeakPanel->reshape(panel_width - possible_shrink_width, mSpeakPanel->getRect().getHeight());
+
+ required_width += possible_shrink_width;
+
+ if (required_width > 0)
+ {
+ buttons_freed_width += required_width;
+ }
+
+ lldebugs << "Shrunk Speak button panel: " << panel_name
+ << ", shrunk width: " << possible_shrink_width
+ << ", rest width to process: " << required_width
+ << llendl;
+ }
+ }
+ }
+}
+
+void LLBottomTray::processShrinkButton(EResizeState processed_object_type, S32& required_width)
+{
+ LLPanel* panel = getButtonPanel(processed_object_type);
+ if (NULL == panel)
+ {
+ lldebugs << "There is no object to process for type: " << processed_object_type << llendl;
+ return;
+ }
+
+ if (panel->getVisible())
+ {
+ S32 panel_width = panel->getRect().getWidth();
+ S32 panel_min_width = 0;
+ std::string panel_name = panel->getName();
+ bool success = mToolbarStack->getPanelMinSize(panel_name, &panel_min_width);
+ S32 possible_shrink_width = panel_width - panel_min_width;
+
+ if (!success)
+ {
+ lldebugs << "Panel was not found to get its min width: " << panel_name << llendl;
+ }
+ // we have some space to free by shrinking the button
+ else if (possible_shrink_width > 0)
+ {
+ // let calculate real width to shrink
+
+ // 1. apply all possible width
+ required_width += possible_shrink_width;
+
+ // 2. it it is too much...
+ if (required_width > 0)
+ {
+ // reduce applied shrunk width to the excessive value.
+ possible_shrink_width -= required_width;
+ required_width = 0;
+ }
+ panel->reshape(panel_width - possible_shrink_width, panel->getRect().getHeight());
+
+ lldebugs << "Shrunk panel: " << panel_name
+ << ", shrunk width: " << possible_shrink_width
+ << ", rest width to process: " << required_width
+ << llendl;
+ }
+ }
+}
+
+
+void LLBottomTray::processExtendButtons(S32& available_width)
+{
+ // do not allow extending any buttons if we have some buttons hidden via resize
+ if (mResizeState & RS_BUTTONS_CAN_BE_HIDDEN) return;
+
+ // process buttons from left to right
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+ // iterate through buttons in the mButtonsProcessOrder first
+ for (; it != it_end; ++it)
+ {
+ // is there available space?
+ if (available_width <= 0) break;
+
+ // try to extend next button
+ processExtendButton(*it, available_width);
+ }
+
+ const S32 chiclet_panel_width = mChicletPanel->getParent()->getRect().getWidth();
+ static const S32 chiclet_panel_min_width = mChicletPanel->getMinWidth();
+ const S32 available_width_chiclet = chiclet_panel_width - chiclet_panel_min_width;
+
+ // then try to extend Speak button
+ if (available_width > 0 || available_width_chiclet > 0)
+ {
+ S32 panel_max_width = mObjectDefaultWidthMap[RS_BUTTON_SPEAK];
+ S32 panel_width = mSpeakPanel->getRect().getWidth();
+ S32 possible_extend_width = panel_max_width - panel_width;
+
+ if (possible_extend_width >= 0 && possible_extend_width <= available_width + available_width_chiclet) // HACK: this button doesn't change size so possible_extend_width will be 0
+ {
+ mSpeakBtn->setLabelVisible(true);
+ mSpeakPanel->reshape(panel_max_width, mSpeakPanel->getRect().getHeight());
+ log(mSpeakBtn, "speak button is extended");
+
+ if( available_width > possible_extend_width)
+ {
+ available_width -= possible_extend_width;
+ }
+ else
+ {
+ S32 required_width = possible_extend_width - available_width;
+ available_width = 0;
+ mChicletPanel->getParent()->reshape(mChicletPanel->getParent()->getRect().getWidth() - required_width, mChicletPanel->getParent()->getRect().getHeight());
+ }
+ lldebugs << "Extending Speak button panel: " << mSpeakPanel->getName()
+ << ", extended width: " << possible_extend_width
+ << ", rest width to process: " << available_width
+ << llendl;
+ }
+ }
+}
+
+void LLBottomTray::processExtendButton(EResizeState processed_object_type, S32& available_width)
+{
+ LLPanel* panel = getButtonPanel(processed_object_type);
+ if (NULL == panel)
+ {
+ lldebugs << "There is no object to process for type: " << processed_object_type << llendl;
+ return;
+ }
+
+ if (!panel->getVisible()) return;
+
+ S32 panel_max_width = mObjectDefaultWidthMap[processed_object_type];
+ S32 panel_width = panel->getRect().getWidth();
+ S32 possible_extend_width = panel_max_width - panel_width;
+
+ if (possible_extend_width > 0)
+ {
+ // let calculate real width to extend
+
+ // 1. apply all possible width
+ available_width -= possible_extend_width;
+
+ // 2. it it is too much...
+ if (available_width < 0)
+ {
+ // reduce applied extended width to the excessive value.
+ possible_extend_width += available_width;
+ available_width = 0;
+ }
+ panel->reshape(panel_width + possible_extend_width, panel->getRect().getHeight());
+
+ lldebugs << "Extending panel: " << panel->getName()
+ << ", extended width: " << possible_extend_width
+ << ", rest width to process: " << available_width
+ << llendl;
+ }
+}
+
+bool LLBottomTray::canButtonBeShown(EResizeState processed_object_type) const
+{
+ // 0. Check if passed button was previously hidden on resize
+ bool can_be_shown = mResizeState & processed_object_type;
+ if (can_be_shown)
+ {
+ // Yes, it was. Lets now check that all buttons before it (that can be hidden on resize)
+ // are already shown
+
+ // process buttons in direct order (from left to right)
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+ // 1. Find and accumulate all buttons types before one passed into the method.
+ MASK buttons_before_mask = RS_NORESIZE;
+ for (; it != it_end; ++it)
+ {
+ const EResizeState button_type = *it;
+ if (button_type == processed_object_type) break;
+
+ buttons_before_mask |= button_type;
+ }
+
+ // 2. Check if some previous buttons are still hidden on resize
+ can_be_shown = !(buttons_before_mask & mResizeState);
+ }
+ return can_be_shown;
+}
+
+void LLBottomTray::initResizeStateContainers()
+{
+ // init map with objects should be processed for each type
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SPEAK, getChild<LLPanel>("speak_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_GESTURES, getChild<LLPanel>("gesture_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_MOVEMENT, getChild<LLPanel>("movement_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_CAMERA, getChild<LLPanel>("cam_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SNAPSHOT, getChild<LLPanel>("snapshot_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_BUILD, getChild<LLPanel>("build_btn_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_SEARCH, getChild<LLPanel>("search_btn_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_WORLD_MAP, getChild<LLPanel>("world_map_btn_panel")));
+ mStateProcessedObjectMap.insert(std::make_pair(RS_BUTTON_MINI_MAP, getChild<LLPanel>("mini_map_btn_panel")));
+
+ // init an order of processed buttons
+ mButtonsProcessOrder.push_back(RS_BUTTON_GESTURES);
+ mButtonsProcessOrder.push_back(RS_BUTTON_MOVEMENT);
+ mButtonsProcessOrder.push_back(RS_BUTTON_CAMERA);
+ mButtonsProcessOrder.push_back(RS_BUTTON_SNAPSHOT);
+ mButtonsProcessOrder.push_back(RS_BUTTON_BUILD);
+ mButtonsProcessOrder.push_back(RS_BUTTON_SEARCH);
+ mButtonsProcessOrder.push_back(RS_BUTTON_WORLD_MAP);
+ mButtonsProcessOrder.push_back(RS_BUTTON_MINI_MAP);
+
+ mButtonsOrder.push_back(RS_BUTTON_SPEAK);
+ mButtonsOrder.insert(mButtonsOrder.end(), mButtonsProcessOrder.begin(), mButtonsProcessOrder.end());
+
+ // init default widths
+
+ // process buttons that can be hidden on resize...
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+ for (; it != it_end; ++it)
+ {
+ const EResizeState button_type = *it;
+ // is there an appropriate object?
+ LLPanel* button_panel = getButtonPanel(button_type);
+ if (!button_panel) continue;
+
+ // set default width for it.
+ mObjectDefaultWidthMap[button_type] = button_panel->getRect().getWidth();
+ }
+
+ // ... and add Speak button because it also can be shrunk.
+ mObjectDefaultWidthMap[RS_BUTTON_SPEAK] = mSpeakPanel->getRect().getWidth();
+}
+
+// this method must be called before restoring of the chat entry field on startup
+// because it resets chatbar's width according to resize logic.
+void LLBottomTray::initButtonsVisibility()
+{
+ setVisibleAndFitWidths(RS_BUTTON_SPEAK, gSavedSettings.getBOOL("EnableVoiceChat"));
+ setVisibleAndFitWidths(RS_BUTTON_GESTURES, gSavedSettings.getBOOL("ShowGestureButton"));
+ setVisibleAndFitWidths(RS_BUTTON_MOVEMENT, gSavedSettings.getBOOL("ShowMoveButton"));
+ setVisibleAndFitWidths(RS_BUTTON_CAMERA, gSavedSettings.getBOOL("ShowCameraButton"));
+ setVisibleAndFitWidths(RS_BUTTON_SNAPSHOT, gSavedSettings.getBOOL("ShowSnapshotButton"));
+ setVisibleAndFitWidths(RS_BUTTON_BUILD, gSavedSettings.getBOOL("ShowBuildButton"));
+ setVisibleAndFitWidths(RS_BUTTON_SEARCH, gSavedSettings.getBOOL("ShowSearchButton"));
+ setVisibleAndFitWidths(RS_BUTTON_WORLD_MAP, gSavedSettings.getBOOL("ShowWorldMapButton"));
+ setVisibleAndFitWidths(RS_BUTTON_MINI_MAP, gSavedSettings.getBOOL("ShowMiniMapButton"));
+}
+
+void LLBottomTray::setButtonsControlsAndListeners()
+{
+ gSavedSettings.getControl("EnableVoiceChat")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SPEAK, _2));
+ gSavedSettings.getControl("ShowGestureButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_GESTURES, _2));
+ gSavedSettings.getControl("ShowMoveButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_MOVEMENT, _2));
+ gSavedSettings.getControl("ShowCameraButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_CAMERA, _2));
+ gSavedSettings.getControl("ShowSnapshotButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SNAPSHOT, _2));
+ gSavedSettings.getControl("ShowBuildButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_BUILD, _2));
+ gSavedSettings.getControl("ShowSearchButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_SEARCH, _2));
+ gSavedSettings.getControl("ShowWorldMapButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_WORLD_MAP, _2));
+ gSavedSettings.getControl("ShowMiniMapButton")->getSignal()->connect(boost::bind(&LLBottomTray::toggleShowButton, RS_BUTTON_MINI_MAP, _2));
+
+
+ LLButton* build_btn = getChild<LLButton>("build_btn");
+ // set control name for Build button. It is not enough to link it with Button.SetFloaterToggle in xml
+ std::string vis_control_name = LLFloaterReg::declareVisibilityControl("build");
+ // Set the button control value (toggle state) to the floater visibility control (Sets the value as well)
+ build_btn->setControlVariable(LLFloater::getControlGroup()->getControl(vis_control_name));
+}
+
+bool LLBottomTray::toggleShowButton(LLBottomTray::EResizeState button_type, const LLSD& new_visibility)
+{
+ if (LLBottomTray::instanceExists())
+ {
+ LLBottomTray::getInstance()->setTrayButtonVisibleIfPossible(button_type, new_visibility.asBoolean());
+ }
+ return true;
+}
+
+void LLBottomTray::setTrayButtonVisible(EResizeState shown_object_type, bool visible)
+{
+ LLPanel* panel = getButtonPanel(shown_object_type);
+ if (NULL == panel)
+ {
+ lldebugs << "There is no object to show for state: " << shown_object_type << llendl;
+ return;
+ }
+
+ panel->setVisible(visible);
+}
+
+void LLBottomTray::setTrayButtonVisibleIfPossible(EResizeState shown_object_type, bool visible, bool raise_notification)
+{
+ if (!setVisibleAndFitWidths(shown_object_type, visible) && visible && raise_notification)
+ {
+ LLNotificationsUtil::add("BottomTrayButtonCanNotBeShown",
+ LLSD(),
+ LLSD(),
+ LLNotificationFunctorRegistry::instance().DONOTHING);
+ }
+}
+
+bool LLBottomTray::setVisibleAndFitWidths(EResizeState object_type, bool visible)
+{
+ // The Speak button is treated specially: if voice is enabled,
+ // the button should be displayed no matter how much space we've got.
+ if (object_type == RS_BUTTON_SPEAK)
+ {
+ showSpeakButton(visible);
+ return true;
+ }
+
+ LLPanel* cur_panel = getButtonPanel(object_type);
+ if (NULL == cur_panel)
+ {
+ lldebugs << "There is no object to process for state: " << object_type << llendl;
+ return false;
+ }
+
+ bool is_set = true;
+
+ if (visible)
+ {
+ // Assume that only chiclet panel can be auto-resized
+ const S32 available_width =
+ mChicletPanel->getParent()->getRect().getWidth() - mChicletPanel->getMinWidth();
+
+ S32 preferred_width = mObjectDefaultWidthMap[object_type];
+ S32 current_width = cur_panel->getRect().getWidth();
+ S32 result_width = 0;
+ bool decrease_width = false;
+
+ // Mark this button to be shown
+ mResizeState |= object_type;
+
+ if (preferred_width > 0 && available_width >= preferred_width)
+ {
+ result_width = preferred_width;
+ }
+ else if (available_width >= current_width)
+ {
+ result_width = current_width;
+ }
+ else
+ {
+ // Calculate the possible shrunk width as difference between current and minimal widths
+ const S32 chatbar_shrunk_width =
+ mChatBarContainer->getRect().getWidth() - get_panel_min_width(mToolbarStack, mChatBarContainer);
+
+ S32 sum_of_min_widths = get_panel_min_width(mToolbarStack, mSpeakPanel);
+ S32 sum_of_curr_widths = get_curr_width(mSpeakPanel);
+
+ resize_state_vec_t::const_iterator it = mButtonsProcessOrder.begin();
+ const resize_state_vec_t::const_iterator it_end = mButtonsProcessOrder.end();
+
+ for (; it != it_end; ++it)
+ {
+ LLPanel* cur_panel = getButtonPanel(*it);
+ sum_of_min_widths += get_panel_min_width(mToolbarStack, cur_panel);
+ sum_of_curr_widths += get_curr_width(cur_panel);
+ }
+
+ const S32 possible_shrunk_width =
+ chatbar_shrunk_width + (sum_of_curr_widths - sum_of_min_widths);
+
+ // Minimal width of current panel
+ S32 minimal_width = 0;
+ mToolbarStack->getPanelMinSize(cur_panel->getName(), &minimal_width);
+
+ if ( (available_width + possible_shrunk_width) >= minimal_width)
+ {
+ // There is enough space for minimal width, but set the result_width
+ // to preferred_width so buttons widths decreasing will be done in predefined order
+ result_width = (preferred_width > 0) ? preferred_width : current_width;
+ decrease_width = true;
+ }
+ else
+ {
+ // Nothing can be done, give up...
+ return false;
+ }
+ }
+
+ if (result_width != current_width)
+ {
+ cur_panel->reshape(result_width, cur_panel->getRect().getHeight());
+ current_width = result_width;
+ }
+
+ is_set = processShowButton(object_type, current_width);
+
+ // Shrink buttons if needed
+ if (is_set && decrease_width)
+ {
+ processWidthDecreased( -result_width);
+ }
+ }
+ else
+ {
+ const S32 delta_width = get_curr_width(cur_panel);
+
+ setTrayButtonVisible(object_type, false);
+
+ // Mark button NOT to show while future bottom tray extending
+ mResizeState &= ~object_type;
+
+ // Extend other buttons if need
+ if (delta_width)
+ {
+ processWidthIncreased(delta_width);
+ }
+ }
+ return is_set;
+}
+
+LLPanel* LLBottomTray::getButtonPanel(EResizeState button_type)
+{
+ // Don't use the operator[] because it inserts a NULL value if the key is not found.
+ if (mStateProcessedObjectMap.count(button_type) == 0)
+ {
+ llwarns << "Cannot find a panel for " << resizeStateToString(button_type) << llendl;
+ llassert(mStateProcessedObjectMap.count(button_type) == 1);
+ return NULL;
+ }
+
+ return mStateProcessedObjectMap[button_type];
+}
+
+void LLBottomTray::showWellButton(EResizeState object_type, bool visible)
+{
+ llassert( ((RS_NOTIFICATION_WELL | RS_IM_WELL) & object_type) == object_type );
+
+ const std::string panel_name = RS_IM_WELL == object_type ? "im_well_panel" : "notification_well_panel";
+
+ LLView * panel = getChild<LLView>(panel_name);
+
+ // if necessary visibility is set nothing to do here
+ if (panel->getVisible() == (BOOL)visible) return;
+
+ S32 panel_width = panel->getRect().getWidth();
+ panel->setVisible(visible);
+
+ if (visible)
+ {
+ // method assumes that input param is a negative value
+ processWidthDecreased(-panel_width);
+ }
+ else
+ {
+ processWidthIncreased(panel_width);
+ }
+}
+
+void LLBottomTray::processChatbarCustomization(S32 new_width)
+{
+ if (NULL == mNearbyChatBar) return;
+
+ const S32 delta_width = mChatBarContainer->getRect().getWidth() - new_width;
+
+ if (delta_width == 0) return;
+
+ mDesiredNearbyChatWidth = new_width;
+
+ LLView * chiclet_layout_panel = mChicletPanel->getParent();
+ const S32 chiclet_min_width = get_panel_min_width(mToolbarStack, chiclet_layout_panel);
+ const S32 chiclet_panel_width = chiclet_layout_panel->getRect().getWidth();
+ const S32 available_chiclet_shrink_width = chiclet_panel_width - chiclet_min_width;
+ llassert(available_chiclet_shrink_width >= 0);
+
+ if (delta_width > 0) // panel gets narrowly
+ {
+ S32 total_possible_width = delta_width + available_chiclet_shrink_width;
+ processShowButtons(total_possible_width);
+ processExtendButtons(total_possible_width);
+ }
+ // here (delta_width < 0) // panel gets wider
+ else //if (-delta_width > available_chiclet_shrink_width)
+ {
+ S32 required_width = delta_width + available_chiclet_shrink_width;
+ S32 buttons_freed_width = 0;
+ processShrinkButtons(required_width, buttons_freed_width);
+ processHideButtons(required_width, buttons_freed_width);
+ }
+}
+
+// static
+std::string LLBottomTray::resizeStateToString(EResizeState state)
+{
+ switch (state)
+ {
+ case RS_NORESIZE: return "RS_NORESIZE";
+ case RS_CHICLET_PANEL: return "RS_CHICLET_PANEL";
+ case RS_CHATBAR_INPUT: return "RS_CHATBAR_INPUT";
+ case RS_BUTTON_SNAPSHOT: return "RS_BUTTON_SNAPSHOT";
+ case RS_BUTTON_CAMERA: return "RS_BUTTON_CAMERA";
+ case RS_BUTTON_MOVEMENT: return "RS_BUTTON_MOVEMENT";
+ case RS_BUTTON_GESTURES: return "RS_BUTTON_GESTURES";
+ case RS_BUTTON_SPEAK: return "RS_BUTTON_SPEAK";
+ case RS_IM_WELL: return "RS_IM_WELL";
+ case RS_NOTIFICATION_WELL: return "RS_NOTIFICATION_WELL";
+ case RS_BUTTON_BUILD: return "RS_BUTTON_BUILD";
+ case RS_BUTTON_SEARCH: return "RS_BUTTON_SEARCH";
+ case RS_BUTTON_WORLD_MAP: return "RS_BUTTON_WORLD_MAP";
+ case RS_BUTTON_MINI_MAP: return "RS_BUTTON_MINI_MAP";
+ case RS_BUTTONS_CAN_BE_HIDDEN: return "RS_BUTTONS_CAN_BE_HIDDEN";
+ // No default to track additions.
+ }
+ return "UNKNOWN_BUTTON";
+}
+
+//EOF
diff --git a/indra/newview/llchathistory.cpp b/indra/newview/llchathistory.cpp
index 5ff22f89ab..d4ec377e03 100644
--- a/indra/newview/llchathistory.cpp
+++ b/indra/newview/llchathistory.cpp
@@ -138,10 +138,7 @@ public:
if (level == "profile")
{
- LLSD params;
- params["object_id"] = getAvatarId();
-
- LLFloaterReg::showInstance("inspect_object", params);
+ LLFloaterReg::showInstance("inspect_remote_object", mObjectData);
}
else if (level == "block")
{
@@ -229,7 +226,7 @@ public:
if (mSourceType == CHAT_SOURCE_OBJECT)
{
- LLFloaterReg::showInstance("inspect_object", LLSD().with("object_id", mAvatarID));
+ LLFloaterReg::showInstance("inspect_remote_object", mObjectData);
}
else if (mSourceType == CHAT_SOURCE_AGENT)
{
@@ -251,7 +248,7 @@ public:
const LLUUID& getAvatarId () const { return mAvatarID;}
- void setup(const LLChat& chat,const LLStyle::Params& style_params)
+ void setup(const LLChat& chat, const LLStyle::Params& style_params, const LLSD& args)
{
mAvatarID = chat.mFromID;
mSessionID = chat.mSessionID;
@@ -332,7 +329,8 @@ public:
setTimeField(chat);
-
+
+ // Set up the icon.
LLAvatarIconCtrl* icon = getChild<LLAvatarIconCtrl>("avatar_icon");
if(mSourceType != CHAT_SOURCE_AGENT || mAvatarID.isNull())
@@ -352,6 +350,30 @@ public:
case CHAT_SOURCE_UNKNOWN:
icon->setValue(LLSD("Unknown_Icon"));
}
+
+ // In case the message came from an object, save the object info
+ // to be able properly show its profile.
+ if ( chat.mSourceType == CHAT_SOURCE_OBJECT)
+ {
+ std::string slurl = args["slurl"].asString();
+ if (slurl.empty())
+ {
+ LLViewerRegion *region = LLWorld::getInstance()->getRegionFromPosAgent(chat.mPosAgent);
+ if(region)
+ {
+ LLSLURL region_slurl(region->getName(), chat.mPosAgent);
+ slurl = region_slurl.getLocationString();
+ }
+ }
+
+ LLSD payload;
+ payload["object_id"] = chat.mFromID;
+ payload["name"] = chat.mFromName;
+ payload["owner_id"] = chat.mOwnerID;
+ payload["slurl"] = LLWeb::escapeURL(slurl);
+
+ mObjectData = payload;
+ }
}
/*virtual*/ void draw()
@@ -540,6 +562,7 @@ protected:
static LLUICtrl* sInfoCtrl;
LLUUID mAvatarID;
+ LLSD mObjectData;
EChatSourceType mSourceType;
std::string mFrom;
LLUUID mSessionID;
@@ -649,10 +672,10 @@ LLView* LLChatHistory::getSeparator()
return separator;
}
-LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params)
+LLView* LLChatHistory::getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args)
{
LLChatHistoryHeader* header = LLChatHistoryHeader::createInstance(mMessageHeaderFilename);
- header->setup(chat,style_params);
+ header->setup(chat, style_params, args);
return header;
}
@@ -834,7 +857,7 @@ void LLChatHistory::appendMessage(const LLChat& chat, const LLSD &args, const LL
}
else
{
- view = getHeader(chat, style_params);
+ view = getHeader(chat, style_params, args);
if (mEditor->getText().size() == 0)
p.top_pad = 0;
else
diff --git a/indra/newview/llchathistory.h b/indra/newview/llchathistory.h
index ac48d7bf29..28344e6a10 100644
--- a/indra/newview/llchathistory.h
+++ b/indra/newview/llchathistory.h
@@ -94,7 +94,7 @@ class LLChatHistory : public LLUICtrl
* Builds a message header.
* @return pointer to LLView header object.
*/
- LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params);
+ LLView* getHeader(const LLChat& chat,const LLStyle::Params& style_params, const LLSD& args);
void onClickMoreText();
diff --git a/indra/newview/llcommandhandler.cpp b/indra/newview/llcommandhandler.cpp
index 360ba080ac..1b6ba02aac 100755
--- a/indra/newview/llcommandhandler.cpp
+++ b/indra/newview/llcommandhandler.cpp
@@ -35,7 +35,7 @@
// system includes
#include <boost/tokenizer.hpp>
-#define THROTTLE_PERIOD 15 // required secs between throttled commands
+#define THROTTLE_PERIOD 5 // required secs between throttled commands
static LLCommandDispatcherListener sCommandDispatcherListener;
diff --git a/indra/newview/llfirstuse.cpp b/indra/newview/llfirstuse.cpp
index 4d252dc662..e319418def 100644
--- a/indra/newview/llfirstuse.cpp
+++ b/indra/newview/llfirstuse.cpp
@@ -41,36 +41,35 @@
// static
-//std::set<std::string> LLFirstUse::sConfigVariables;
-std::set<std::string> LLFirstUse::sConfigVariablesEnabled;
+std::set<std::string> LLFirstUse::sConfigVariables;
// static
-//void LLFirstUse::addConfigVariable(const std::string& var)
-//{
-// sConfigVariables.insert(var);
-//}
+void LLFirstUse::addConfigVariable(const std::string& var)
+{
+ sConfigVariables.insert(var);
+}
// static
-//void LLFirstUse::disableFirstUse()
-//{
-// // Set all first-use warnings to disabled
-// for (std::set<std::string>::iterator iter = sConfigVariables.begin();
-// iter != sConfigVariables.end(); ++iter)
-// {
-// gWarningSettings.setBOOL(*iter, FALSE);
-// }
-//}
+void LLFirstUse::disableFirstUse()
+{
+ // Set all first-use warnings to disabled
+ for (std::set<std::string>::iterator iter = sConfigVariables.begin();
+ iter != sConfigVariables.end(); ++iter)
+ {
+ gWarningSettings.setBOOL(*iter, FALSE);
+ }
+}
// static
-//void LLFirstUse::resetFirstUse()
-//{
-// // Set all first-use warnings to disabled
-// for (std::set<std::string>::iterator iter = sConfigVariables.begin();
-// iter != sConfigVariables.end(); ++iter)
-// {
-// gWarningSettings.setBOOL(*iter, TRUE);
-// }
-//}
+void LLFirstUse::resetFirstUse()
+{
+ // Set all first-use warnings to disabled
+ for (std::set<std::string>::iterator iter = sConfigVariables.begin();
+ iter != sConfigVariables.end(); ++iter)
+ {
+ gWarningSettings.setBOOL(*iter, TRUE);
+ }
+}
// static
void LLFirstUse::otherAvatarChatFirst(bool enable)
@@ -104,13 +103,6 @@ void LLFirstUse::notUsingDestinationGuide(bool enable)
firstUseNotification("FirstNotUseDestinationGuide", enable, "HintDestinationGuide", LLSD(), LLSD().with("target", "dest_guide_btn").with("direction", "top"));
}
-void LLFirstUse::notUsingAvatarPicker(bool enable)
-{
- // not doing this yet
- firstUseNotification("FirstNotUseAvatarPicker", enable, "HintAvatarPicker", LLSD(), LLSD().with("target", "avatar_picker_btn").with("direction", "top"));
-}
-
-
// static
void LLFirstUse::notUsingSidePanel(bool enable)
{
@@ -152,21 +144,13 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl
if (enable)
{
- if(sConfigVariablesEnabled.find(control_var) != sConfigVariablesEnabled.end())
- {
- return ; //already added
- }
-
if (gSavedSettings.getBOOL("EnableUIHints"))
{
LL_DEBUGS("LLFirstUse") << "Trigger first use notification " << notification_name << LL_ENDL;
// if notification doesn't already exist and this notification hasn't been disabled...
if (gWarningSettings.getBOOL(control_var))
- {
- sConfigVariablesEnabled.insert(control_var) ;
-
- // create new notification
+ { // create new notification
LLNotifications::instance().add(LLNotification::Params().name(notification_name).substitutions(args).payload(payload.with("control_var", control_var)));
}
}
@@ -178,6 +162,7 @@ void LLFirstUse::firstUseNotification(const std::string& control_var, bool enabl
// redundantly clear settings var here, in case there are no notifications to cancel
gWarningSettings.setBOOL(control_var, FALSE);
}
+
}
// static
diff --git a/indra/newview/llfirstuse.h b/indra/newview/llfirstuse.h
index 489f58626a..42b2ec0c60 100644
--- a/indra/newview/llfirstuse.h
+++ b/indra/newview/llfirstuse.h
@@ -78,16 +78,15 @@ class LLFirstUse
public:
// Add a config variable to be reset on resetFirstUse()
- //static void addConfigVariable(const std::string& var);
+ static void addConfigVariable(const std::string& var);
// Sets all controls back to show the dialogs.
- //static void disableFirstUse();
- //static void resetFirstUse();
+ static void disableFirstUse();
+ static void resetFirstUse();
static void otherAvatarChatFirst(bool enable = true);
static void sit(bool enable = true);
static void notUsingDestinationGuide(bool enable = true);
- static void notUsingAvatarPicker(bool enable = true);
static void notUsingSidePanel(bool enable = true);
static void notMoving(bool enable = true);
static void viewPopup(bool enable = true);
@@ -98,8 +97,7 @@ public:
protected:
static void firstUseNotification(const std::string& control_var, bool enable, const std::string& notification_name, LLSD args = LLSD(), LLSD payload = LLSD());
- //static std::set<std::string> sConfigVariables;
- static std::set<std::string> sConfigVariablesEnabled;
+ static std::set<std::string> sConfigVariables;
static void init();
static bool processNotification(const LLSD& notify);
diff --git a/indra/newview/llfloatermap.cpp b/indra/newview/llfloatermap.cpp
index 80920c80d6..45d1cc2b53 100644
--- a/indra/newview/llfloatermap.cpp
+++ b/indra/newview/llfloatermap.cpp
@@ -83,8 +83,14 @@ LLFloaterMap::~LLFloaterMap()
BOOL LLFloaterMap::postBuild()
{
mMap = getChild<LLNetMap>("Net Map");
- mMap->setToolTipMsg(gSavedSettings.getBOOL("DoubleClickTeleport") ?
- getString("AltToolTipMsg") : getString("ToolTipMsg"));
+ if (gSavedSettings.getBOOL("DoubleClickTeleport"))
+ {
+ mMap->setToolTipMsg(getString("AltToolTipMsg"));
+ }
+ else if (gSavedSettings.getBOOL("DoubleClickShowWorldMap"))
+ {
+ mMap->setToolTipMsg(getString("ToolTipMsg"));
+ }
sendChildToBack(mMap);
mTextBoxNorth = getChild<LLTextBox> ("floater_map_north");
@@ -150,7 +156,7 @@ BOOL LLFloaterMap::handleDoubleClick(S32 x, S32 y, MASK mask)
// If DoubleClickTeleport is on, double clicking the minimap will teleport there
gAgent.teleportViaLocationLookAt(pos_global);
}
- else
+ else if (gSavedSettings.getBOOL("DoubleClickShowWorldMap"))
{
LLFloaterReg::showInstance("world_map");
}
diff --git a/indra/newview/llfloatersidetraytab.cpp b/indra/newview/llfloatersidetraytab.cpp
index f13b4db3a0..94407e6da0 100644
--- a/indra/newview/llfloatersidetraytab.cpp
+++ b/indra/newview/llfloatersidetraytab.cpp
@@ -30,6 +30,7 @@
// newview includes
#include "lltransientfloatermgr.h"
+#include "llsidetray.h"
LLFloaterSideTrayTab::LLFloaterSideTrayTab(const LLSD& key, const Params& params)
: LLFloater(key, params)
@@ -43,3 +44,8 @@ LLFloaterSideTrayTab::~LLFloaterSideTrayTab()
{
LLTransientFloaterMgr::getInstance()->removeControlView(LLTransientFloaterMgr::GLOBAL, this);
}
+
+void LLFloaterSideTrayTab::onClose(bool app_quitting)
+{
+ LLSideTray::getInstance()->setTabDocked(getName(), true);
+}
diff --git a/indra/newview/llfloatersidetraytab.h b/indra/newview/llfloatersidetraytab.h
index e47f82e8ba..89f2444a0e 100644
--- a/indra/newview/llfloatersidetraytab.h
+++ b/indra/newview/llfloatersidetraytab.h
@@ -42,6 +42,8 @@ class LLFloaterSideTrayTab : public LLFloater
public:
LLFloaterSideTrayTab(const LLSD& key, const Params& params = getDefaultParams());
~LLFloaterSideTrayTab();
+
+ void onClose(bool app_quitting);
};
#endif // LL_LLFLOATERSIDETRAYTAB_H
diff --git a/indra/newview/llfloaterworldmap.cpp b/indra/newview/llfloaterworldmap.cpp
index 017cd2fc49..03cf0332a9 100755
--- a/indra/newview/llfloaterworldmap.cpp
+++ b/indra/newview/llfloaterworldmap.cpp
@@ -110,6 +110,12 @@ public:
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableWorldMap"))
+ {
+ LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
if (params.size() == 0)
{
// support the secondlife:///app/worldmap SLapp
@@ -142,6 +148,12 @@ public:
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableWorldMap"))
+ {
+ LLNotificationsUtil::add("NoWorldMap", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
//Make sure we have some parameters
if (params.size() == 0)
{
diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp
index 5393678a6b..7c56e610ce 100644
--- a/indra/newview/llgroupactions.cpp
+++ b/indra/newview/llgroupactions.cpp
@@ -53,6 +53,12 @@ public:
bool handle(const LLSD& tokens, const LLSD& query_map,
LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableGroupInfo"))
+ {
+ LLNotificationsUtil::add("NoGroupInfo", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
if (tokens.size() < 1)
{
return false;
diff --git a/indra/newview/llhudeffectblob.cpp b/indra/newview/llhudeffectblob.cpp
new file mode 100644
index 0000000000..26e8251899
--- /dev/null
+++ b/indra/newview/llhudeffectblob.cpp
@@ -0,0 +1,78 @@
+/**
+ * @file llhudeffecttrail.cpp
+ * @brief LLHUDEffectSpiral class implementation
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llhudeffectblob.h"
+
+#include "llagent.h"
+#include "llviewercamera.h"
+#include "llrendersphere.h"
+
+LLHUDEffectBlob::LLHUDEffectBlob(const U8 type)
+: LLHUDEffect(type),
+ mPixelSize(10)
+{
+ mTimer.start();
+}
+
+LLHUDEffectBlob::~LLHUDEffectBlob()
+{
+}
+
+void LLHUDEffectBlob::render()
+{
+ F32 time = mTimer.getElapsedTimeF32();
+ if (mDuration < time)
+ {
+ markDead();
+ }
+
+ LLVector3 pos_agent = gAgent.getPosAgentFromGlobal(mPositionGlobal);
+
+ LLVector3 pixel_up, pixel_right;
+
+ LLViewerCamera::instance().getPixelVectors(pos_agent, pixel_up, pixel_right);
+
+ LLGLSPipelineAlpha gls_pipeline_alpha;
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ LLColor4U color = mColor;
+ color.mV[VALPHA] = (U8)clamp_rescale(time, 0.f, mDuration, 255.f, 0.f);
+ glColor4ubv(color.mV);
+
+ glPushMatrix();
+ glTranslatef(pos_agent.mV[0], pos_agent.mV[1], pos_agent.mV[2]);
+ F32 scale = pixel_up.magVec() * (F32)mPixelSize;
+ glScalef(scale, scale, scale);
+ gSphere.render(0);
+ glPopMatrix();
+}
+
+void LLHUDEffectBlob::renderForTimer()
+{
+}
+
diff --git a/indra/newview/llhudeffectblob.h b/indra/newview/llhudeffectblob.h
new file mode 100644
index 0000000000..5b0703cdaa
--- /dev/null
+++ b/indra/newview/llhudeffectblob.h
@@ -0,0 +1,50 @@
+/**
+ * @file llhudeffectblob.h
+ * @brief LLHUDEffectBlob class definition
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#ifndef LL_LLHUDEFFECTBLOB_H
+#define LL_LLHUDEFFECTBLOB_H
+
+#include "llhudeffect.h"
+
+class LLHUDEffectBlob : public LLHUDEffect
+{
+public:
+ friend class LLHUDObject;
+
+ void setPixelSize(S32 pixels) { mPixelSize = pixels; }
+
+protected:
+ LLHUDEffectBlob(const U8 type);
+ ~LLHUDEffectBlob();
+
+ /*virtual*/ void render();
+ /*virtual*/ void renderForTimer();
+private:
+ S32 mPixelSize;
+ LLFrameTimer mTimer;
+};
+
+#endif // LL_LLHUDEFFECTBLOB_H
diff --git a/indra/newview/llhudobject.cpp b/indra/newview/llhudobject.cpp
index 5e762ee037..95d57d08d8 100644
--- a/indra/newview/llhudobject.cpp
+++ b/indra/newview/llhudobject.cpp
@@ -32,6 +32,7 @@
#include "llhudtext.h"
#include "llhudicon.h"
#include "llhudeffectbeam.h"
+#include "llhudeffectblob.h"
#include "llhudeffecttrail.h"
#include "llhudeffectlookat.h"
#include "llhudeffectpointat.h"
@@ -237,6 +238,9 @@ LLHUDEffect *LLHUDObject::addHUDEffect(const U8 type)
case LL_HUD_EFFECT_POINTAT:
hud_objectp = new LLHUDEffectPointAt(type);
break;
+ case LL_HUD_EFFECT_BLOB:
+ hud_objectp = new LLHUDEffectBlob(type);
+ break;
default:
llwarns << "Unknown type of hud effect:" << (U32) type << llendl;
}
diff --git a/indra/newview/llhudobject.h b/indra/newview/llhudobject.h
index 33e6394445..2f7a98c86c 100644
--- a/indra/newview/llhudobject.h
+++ b/indra/newview/llhudobject.h
@@ -95,7 +95,8 @@ public:
LL_HUD_EFFECT_LOOKAT,
LL_HUD_EFFECT_POINTAT,
LL_HUD_EFFECT_VOICE_VISUALIZER, // Ventrella
- LL_HUD_NAME_TAG
+ LL_HUD_NAME_TAG,
+ LL_HUD_EFFECT_BLOB
};
protected:
static void sortObjects();
diff --git a/indra/newview/llinventorymodelbackgroundfetch.cpp b/indra/newview/llinventorymodelbackgroundfetch.cpp
index 570e48d526..e31360fcbc 100644
--- a/indra/newview/llinventorymodelbackgroundfetch.cpp
+++ b/indra/newview/llinventorymodelbackgroundfetch.cpp
@@ -182,7 +182,7 @@ void LLInventoryModelBackgroundFetch::backgroundFetch()
{
// If we'll be using the capability, we'll be sending batches and the background thing isn't as important.
std::string url = gAgent.getRegion()->getCapability("FetchInventoryDescendents2");
- if (!url.empty())
+ if (gSavedSettings.getBOOL("UseHTTPInventory") && !url.empty())
{
bulkFetch(url);
return;
diff --git a/indra/newview/lllocationinputctrl.cpp b/indra/newview/lllocationinputctrl.cpp
index 55164f6094..5c65dcec34 100644
--- a/indra/newview/lllocationinputctrl.cpp
+++ b/indra/newview/lllocationinputctrl.cpp
@@ -211,7 +211,6 @@ LLLocationInputCtrl::LLLocationInputCtrl(const LLLocationInputCtrl::Params& p)
{
// 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
diff --git a/indra/newview/llnavigationbar.cpp b/indra/newview/llnavigationbar.cpp
index e4f83ce6b9..3b160ddc8e 100644
--- a/indra/newview/llnavigationbar.cpp
+++ b/indra/newview/llnavigationbar.cpp
@@ -636,18 +636,19 @@ void LLNavigationBar::onRegionNameResponse(
U64 region_handle, const std::string& url, const LLUUID& snapshot_id, bool teleport)
{
// Invalid location?
- if (!region_handle)
+ if (region_handle)
+ {
+ // Teleport to the location.
+ LLVector3d region_pos = from_region_handle(region_handle);
+ LLVector3d global_pos = region_pos + (LLVector3d) local_coords;
+
+ llinfos << "Teleporting to: " << LLSLURL(region_name, global_pos).getSLURLString() << llendl;
+ gAgent.teleportViaLocation(global_pos);
+ }
+ else if (gSavedSettings.getBOOL("SearchFromAddressBar"))
{
invokeSearch(typed_location);
- return;
}
-
- // Teleport to the location.
- LLVector3d region_pos = from_region_handle(region_handle);
- LLVector3d global_pos = region_pos + (LLVector3d) local_coords;
-
- llinfos << "Teleporting to: " << LLSLURL(region_name, global_pos).getSLURLString() << llendl;
- gAgent.teleportViaLocation(global_pos);
}
void LLNavigationBar::showTeleportHistoryMenu(LLUICtrl* btn_ctrl)
diff --git a/indra/newview/llnearbychatbar.cpp b/indra/newview/llnearbychatbar.cpp
index 836ae9a0cf..162e465fef 100644
--- a/indra/newview/llnearbychatbar.cpp
+++ b/indra/newview/llnearbychatbar.cpp
@@ -157,6 +157,16 @@ BOOL LLGestureComboList::handleKeyHere(KEY key, MASK mask)
return handled;
}
+void LLGestureComboList::draw()
+{
+ LLUICtrl::draw();
+
+ if(mButton->getToggleState())
+ {
+ showList();
+ }
+}
+
void LLGestureComboList::showList()
{
LLRect rect = mList->getRect();
@@ -180,6 +190,7 @@ void LLGestureComboList::showList()
// Show the list and push the button down
mButton->setToggleState(TRUE);
mList->setVisible(TRUE);
+ sendChildToFront(mList);
LLUI::addPopup(mList);
}
diff --git a/indra/newview/llnearbychatbar.h b/indra/newview/llnearbychatbar.h
index 033d1dd5a2..96ab45071b 100644
--- a/indra/newview/llnearbychatbar.h
+++ b/indra/newview/llnearbychatbar.h
@@ -72,6 +72,8 @@ public:
virtual void hideList();
virtual BOOL handleKeyHere(KEY key, MASK mask);
+ virtual void draw();
+
S32 getCurrentIndex() const;
void onItemSelected(const LLSD& data);
void sortByName(bool ascending = true);
diff --git a/indra/newview/llnetmap.cpp b/indra/newview/llnetmap.cpp
index 93039d935d..e29078c545 100644
--- a/indra/newview/llnetmap.cpp
+++ b/indra/newview/llnetmap.cpp
@@ -904,23 +904,29 @@ BOOL LLNetMap::handleClick(S32 x, S32 y, MASK mask)
BOOL LLNetMap::handleDoubleClick(S32 x, S32 y, MASK mask)
{
LLVector3d pos_global = viewPosToGlobal(x, y);
-
- // If we're not tracking a beacon already, double-click will set one
- if (!LLTracker::isTracking(NULL))
+
+ bool double_click_teleport = gSavedSettings.getBOOL("DoubleClickTeleport");
+ bool double_click_show_world_map = gSavedSettings.getBOOL("DoubleClickShowWorldMap");
+
+ if (double_click_teleport || double_click_show_world_map)
{
- LLFloaterWorldMap* world_map = LLFloaterWorldMap::getInstance();
- if (world_map)
+ // If we're not tracking a beacon already, double-click will set one
+ if (!LLTracker::isTracking(NULL))
{
- world_map->trackLocation(pos_global);
+ LLFloaterWorldMap* world_map = LLFloaterWorldMap::getInstance();
+ if (world_map)
+ {
+ world_map->trackLocation(pos_global);
+ }
}
}
-
- if (gSavedSettings.getBOOL("DoubleClickTeleport"))
+
+ if (double_click_teleport)
{
// If DoubleClickTeleport is on, double clicking the minimap will teleport there
gAgent.teleportViaLocationLookAt(pos_global);
}
- else
+ else if (double_click_show_world_map)
{
LLFloaterReg::showInstance("world_map");
}
diff --git a/indra/newview/llnotificationscripthandler.cpp b/indra/newview/llnotificationscripthandler.cpp
index 45590c3cdb..bbb4d03768 100644
--- a/indra/newview/llnotificationscripthandler.cpp
+++ b/indra/newview/llnotificationscripthandler.cpp
@@ -88,7 +88,7 @@ bool LLScriptHandler::processNotification(const LLSD& notify)
initChannel();
}
- if(notify["sigtype"].asString() == "add" || notify["sigtype"].asString() == "change")
+ if(notify["sigtype"].asString() == "add")
{
if (LLHandlerUtil::canLogToIM(notification))
{
diff --git a/indra/newview/llpanellogin.cpp b/indra/newview/llpanellogin.cpp
index 3b5830f8e0..b472698a49 100644
--- a/indra/newview/llpanellogin.cpp
+++ b/indra/newview/llpanellogin.cpp
@@ -1,1193 +1,1183 @@
-/**
- * @file llpanellogin.cpp
- * @brief Login dialog and logo display
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llpanellogin.h"
-
-#include "indra_constants.h" // for key and mask constants
-#include "llfloaterreg.h"
-#include "llfontgl.h"
-#include "llmd5.h"
-#include "llsecondlifeurls.h"
-#include "v4color.h"
-
-#include "llappviewer.h"
-#include "llbutton.h"
-#include "llcheckboxctrl.h"
-#include "llcommandhandler.h" // for secondlife:///app/login/
-#include "llcombobox.h"
-#include "llcurl.h"
-#include "llviewercontrol.h"
-#include "llfloaterpreference.h"
-#include "llfocusmgr.h"
-#include "lllineeditor.h"
-#include "llnotificationsutil.h"
-#include "llsecapi.h"
-#include "llstartup.h"
-#include "lltextbox.h"
-#include "llui.h"
-#include "lluiconstants.h"
-#include "llslurl.h"
-#include "llversioninfo.h"
-#include "llviewerhelp.h"
-#include "llviewertexturelist.h"
-#include "llviewermenu.h" // for handle_preferences()
-#include "llviewernetwork.h"
-#include "llviewerwindow.h" // to link into child list
-#include "lluictrlfactory.h"
-#include "llhttpclient.h"
-#include "llweb.h"
-#include "llmediactrl.h"
-#include "llrootview.h"
-
-#include "llfloatertos.h"
-#include "lltrans.h"
-#include "llglheaders.h"
-#include "llpanelloginlistener.h"
-
-#if LL_WINDOWS
-#pragma warning(disable: 4355) // 'this' used in initializer list
-#endif // LL_WINDOWS
-
-#include "llsdserialize.h"
-
-const S32 BLACK_BORDER_HEIGHT = 160;
-const S32 MAX_PASSWORD = 16;
-
-LLPanelLogin *LLPanelLogin::sInstance = NULL;
-BOOL LLPanelLogin::sCapslockDidNotification = FALSE;
-
-// Helper for converting a user name into the canonical "Firstname Lastname" form.
-// For new accounts without a last name "Resident" is added as a last name.
-static std::string canonicalize_username(const std::string& name);
-
-class LLLoginRefreshHandler : public LLCommandHandler
-{
-public:
- // don't allow from external browsers
- LLLoginRefreshHandler() : LLCommandHandler("login_refresh", UNTRUSTED_BLOCK) { }
- bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
- {
- if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)
- {
- LLPanelLogin::loadLoginPage();
- }
- return true;
- }
-};
-
-LLLoginRefreshHandler gLoginRefreshHandler;
-
-
-// helper class that trys to download a URL from a web site and calls a method
-// on parent class indicating if the web server is working or not
-class LLIamHereLogin : public LLHTTPClient::Responder
-{
- private:
- LLIamHereLogin( LLPanelLogin* parent ) :
- mParent( parent )
- {}
-
- LLPanelLogin* mParent;
-
- public:
- static boost::intrusive_ptr< LLIamHereLogin > build( LLPanelLogin* parent )
- {
- return boost::intrusive_ptr< LLIamHereLogin >( new LLIamHereLogin( parent ) );
- };
-
- virtual void setParent( LLPanelLogin* parentIn )
- {
- mParent = parentIn;
- };
-
- // We don't actually expect LLSD back, so need to override completedRaw
- virtual void completedRaw(U32 status, const std::string& reason,
- const LLChannelDescriptors& channels,
- const LLIOPipe::buffer_ptr_t& buffer)
- {
- completed(status, reason, LLSD()); // will call result() or error()
- }
-
- virtual void result( const LLSD& content )
- {
- if ( mParent )
- mParent->setSiteIsAlive( true );
- };
-
- virtual void error( U32 status, const std::string& reason )
- {
- if ( mParent )
- mParent->setSiteIsAlive( false );
- };
-};
-
-// this is global and not a class member to keep crud out of the header file
-namespace {
- boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0;
-};
-
-
-//---------------------------------------------------------------------------
-// Public methods
-//---------------------------------------------------------------------------
-LLPanelLogin::LLPanelLogin(const LLRect &rect,
- BOOL show_server,
- void (*callback)(S32 option, void* user_data),
- void *cb_data)
-: LLPanel(),
- mLogoImage(),
- mCallback(callback),
- mCallbackData(cb_data),
- mHtmlAvailable( TRUE ),
- mListener(new LLPanelLoginListener(this))
-{
- setBackgroundVisible(FALSE);
- setBackgroundOpaque(TRUE);
-
- // instance management
- if (LLPanelLogin::sInstance)
- {
- llwarns << "Duplicate instance of login view deleted" << llendl;
- // Don't leave bad pointer in gFocusMgr
- gFocusMgr.setDefaultKeyboardFocus(NULL);
-
- delete LLPanelLogin::sInstance;
- }
-
- mPasswordModified = FALSE;
- LLPanelLogin::sInstance = this;
-
- LLView* login_holder = gViewerWindow->getLoginPanelHolder();
- if (login_holder)
- {
- login_holder->addChild(this);
- }
-
- // Logo
- mLogoImage = LLUI::getUIImage("startup_logo");
-
- buildFromFile( "panel_login.xml");
-
- // Legacy login web page is hidden under the menu bar.
- // Adjust reg-in-client web browser widget to not be hidden.
- if (gSavedSettings.getBOOL("RegInClient"))
- {
- reshape(rect.getWidth(), rect.getHeight() - MENU_BAR_HEIGHT);
- }
- else
- {
- reshape(rect.getWidth(), rect.getHeight());
- }
-
- getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);
-
- // change z sort of clickable text to be behind buttons
- //sendChildToBack(getChildView("channel_text"));
- sendChildToBack(getChildView("forgot_password_text"));
-
- if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION)
- {
- LLSLURL slurl(gSavedSettings.getString("LoginLocation"));
- LLStartUp::setStartSLURL(slurl);
- }
- updateLocationCombo(false);
-
- LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
- server_choice_combo->setCommitCallback(onSelectServer, NULL);
- server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1));
- updateServerCombo();
-
- childSetAction("connect_btn", onClickConnect, this);
-
- getChild<LLPanel>("login")->setDefaultBtn("connect_btn");
-
- std::string channel = LLVersionInfo::getChannel();
- std::string version = llformat("%s (%d)",
- LLVersionInfo::getShortVersion().c_str(),
- LLVersionInfo::getBuild());
- //LLTextBox* channel_text = getChild<LLTextBox>("channel_text");
- //channel_text->setTextArg("[CHANNEL]", channel); // though not displayed
- //channel_text->setTextArg("[VERSION]", version);
- //channel_text->setClickedCallback(onClickVersion, this);
-
- LLTextBox* forgot_password_text = getChild<LLTextBox>("forgot_password_text");
- forgot_password_text->setClickedCallback(onClickForgotPassword, NULL);
-
- LLTextBox* create_new_account_text = getChild<LLTextBox>("create_new_account_text");
- create_new_account_text->setClickedCallback(onClickNewAccount, NULL);
-
- LLTextBox* need_help_text = getChild<LLTextBox>("login_help");
- need_help_text->setClickedCallback(onClickHelp, NULL);
-
- // get the web browser control
- LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
- web_browser->addObserver(this);
-
- // Clear the browser's cache to avoid any potential for the cache messing up the login screen.
- web_browser->clearCache();
-
- reshapeBrowser();
-
- // kick off a request to grab the url manually
- gResponsePtr = LLIamHereLogin::build( this );
-
- LLHTTPClient::head( LLGridManager::getInstance()->getLoginPage(), gResponsePtr );
-
- // Show last logged in user favorites in "Start at" combo.
- addUsersWithFavoritesToUsername();
- getChild<LLComboBox>("username_combo")->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this));
-
- updateLocationCombo(false);
-
-}
-
-void LLPanelLogin::addUsersWithFavoritesToUsername()
-{
- LLComboBox* combo = getChild<LLComboBox>("username_combo");
- if (!combo) return;
- std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
- LLSD fav_llsd;
- llifstream file;
- file.open(filename);
- if (!file.is_open()) return;
- LLSDSerialize::fromXML(fav_llsd, file);
- for (LLSD::map_const_iterator iter = fav_llsd.beginMap();
- iter != fav_llsd.endMap(); ++iter)
- {
- combo->add(iter->first);
- }
-}
-
-void LLPanelLogin::addFavoritesToStartLocation()
-{
- LLComboBox* combo = getChild<LLComboBox>("start_location_combo");
- if (!combo) return;
- int num_items = combo->getItemCount();
- for (int i = num_items - 1; i > 2; i--)
- {
- combo->remove(i);
- }
- std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
- LLSD fav_llsd;
- llifstream file;
- file.open(filename);
- if (!file.is_open()) return;
- LLSDSerialize::fromXML(fav_llsd, file);
- for (LLSD::map_const_iterator iter = fav_llsd.beginMap();
- iter != fav_llsd.endMap(); ++iter)
- {
- std::string user_defined_name = getChild<LLComboBox>("username_combo")->getSimple();
-
- // The account name in stored_favorites.xml has Resident last name even if user has
- // a single word account name, so it can be compared case-insensitive with the
- // user defined "firstname lastname".
- S32 res = LLStringUtil::compareInsensitive(canonicalize_username(user_defined_name), iter->first);
- if (res != 0) continue;
-
- combo->addSeparator();
- LLSD user_llsd = iter->second;
- for (LLSD::array_const_iterator iter1 = user_llsd.beginArray();
- iter1 != user_llsd.endArray(); ++iter1)
- {
- std::string label = (*iter1)["name"].asString();
- std::string value = (*iter1)["slurl"].asString();
- if(label != "" && value != "")
- {
- combo->add(label, value);
- }
- }
- break;
- }
-}
-
-// force the size to be correct (XML doesn't seem to be sufficient to do this)
-// (with some padding so the other login screen doesn't show through)
-void LLPanelLogin::reshapeBrowser()
-{
- LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
- LLRect rect = gViewerWindow->getWindowRectScaled();
- LLRect html_rect;
- html_rect.setCenterAndSize(
- rect.getCenterX() - 2, rect.getCenterY() + 40,
- rect.getWidth() + 6, rect.getHeight() - 78 );
- web_browser->setRect( html_rect );
- web_browser->reshape( html_rect.getWidth(), html_rect.getHeight(), TRUE );
- reshape( rect.getWidth(), rect.getHeight(), 1 );
-}
-
-void LLPanelLogin::setSiteIsAlive( bool alive )
-{
- LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
- // if the contents of the site was retrieved
- if ( alive )
- {
- if ( web_browser )
- {
- loadLoginPage();
-
- // mark as available
- mHtmlAvailable = TRUE;
- }
- }
- else
- // the site is not available (missing page, server down, other badness)
- {
- if ( web_browser )
- {
- // hide browser control (revealing default one)
- web_browser->setVisible( FALSE );
-
- // mark as unavailable
- mHtmlAvailable = FALSE;
- }
- }
-}
-
-
-LLPanelLogin::~LLPanelLogin()
-{
- LLPanelLogin::sInstance = NULL;
-
- // tell the responder we're not here anymore
- if ( gResponsePtr )
- gResponsePtr->setParent( 0 );
-
- //// We know we're done with the image, so be rid of it.
- //gTextureList.deleteImage( mLogoImage );
-
- // Controls having keyboard focus by default
- // must reset it on destroy. (EXT-2748)
- gFocusMgr.setDefaultKeyboardFocus(NULL);
-}
-
-// virtual
-void LLPanelLogin::draw()
-{
- glPushMatrix();
- {
- F32 image_aspect = 1.333333f;
- F32 view_aspect = (F32)getRect().getWidth() / (F32)getRect().getHeight();
- // stretch image to maintain aspect ratio
- if (image_aspect > view_aspect)
- {
- glTranslatef(-0.5f * (image_aspect / view_aspect - 1.f) * getRect().getWidth(), 0.f, 0.f);
- glScalef(image_aspect / view_aspect, 1.f, 1.f);
- }
-
- S32 width = getRect().getWidth();
- S32 height = getRect().getHeight();
-
- if ( mHtmlAvailable )
- {
- if (getChild<LLView>("login_widgets")->getVisible())
- {
- // draw a background box in black
- gl_rect_2d( 0, height - 264, width, 264, LLColor4::black );
- // draw the bottom part of the background image
- // just the blue background to the native client UI
- mLogoImage->draw(0, -264, width + 8, mLogoImage->getHeight());
- }
- }
- else
- {
- // the HTML login page is not available so default to the original screen
- S32 offscreen_part = height / 3;
- mLogoImage->draw(0, -offscreen_part, width, height+offscreen_part);
- };
- }
- glPopMatrix();
-
- LLPanel::draw();
-}
-
-// virtual
-BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask)
-{
- if ( KEY_F1 == key )
- {
- LLViewerHelp* vhelp = LLViewerHelp::getInstance();
- vhelp->showTopic(vhelp->f1HelpTopic());
- return TRUE;
- }
-
- return LLPanel::handleKeyHere(key, mask);
-}
-
-// virtual
-void LLPanelLogin::setFocus(BOOL b)
-{
- if(b != hasFocus())
- {
- if(b)
- {
- LLPanelLogin::giveFocus();
- }
- else
- {
- LLPanel::setFocus(b);
- }
- }
-}
-
-// static
-void LLPanelLogin::giveFocus()
-{
- if( sInstance )
- {
- // Grab focus and move cursor to first blank input field
- std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
- std::string pass = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
-
- BOOL have_username = !username.empty();
- BOOL have_pass = !pass.empty();
-
- LLLineEditor* edit = NULL;
- LLComboBox* combo = NULL;
- if (have_username && !have_pass)
- {
- // User saved his name but not his password. Move
- // focus to password field.
- edit = sInstance->getChild<LLLineEditor>("password_edit");
- }
- else
- {
- // User doesn't have a name, so start there.
- combo = sInstance->getChild<LLComboBox>("username_combo");
- }
-
- if (edit)
- {
- edit->setFocus(TRUE);
- edit->selectAll();
- }
- else if (combo)
- {
- combo->setFocus(TRUE);
- }
- }
-}
-
-// static
-void LLPanelLogin::showLoginWidgets()
-{
- // *NOTE: Mani - This may or may not be obselete code.
- // It seems to be part of the defunct? reg-in-client project.
- sInstance->getChildView("login_widgets")->setVisible( true);
- LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
- sInstance->reshapeBrowser();
- // *TODO: Append all the usual login parameters, like first_login=Y etc.
- std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage();
- web_browser->navigateTo( splash_screen_url, "text/html" );
- LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo");
- username_combo->setFocus(TRUE);
-}
-
-// static
-void LLPanelLogin::show(const LLRect &rect,
- BOOL show_server,
- void (*callback)(S32 option, void* user_data),
- void* callback_data)
-{
- new LLPanelLogin(rect, show_server, callback, callback_data);
-
- if( !gFocusMgr.getKeyboardFocus() )
- {
- // Grab focus and move cursor to first enabled control
- sInstance->setFocus(TRUE);
- }
-
- // Make sure that focus always goes here (and use the latest sInstance that was just created)
- gFocusMgr.setDefaultKeyboardFocus(sInstance);
-}
-
-// static
-void LLPanelLogin::setFields(LLPointer<LLCredential> credential,
- BOOL remember)
-{
- if (!sInstance)
- {
- llwarns << "Attempted fillFields with no login view shown" << llendl;
- return;
- }
- LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL;
-
- LLSD identifier = credential->getIdentifier();
- if((std::string)identifier["type"] == "agent")
- {
- std::string firstname = identifier["first_name"].asString();
- std::string lastname = identifier["last_name"].asString();
- std::string login_id = firstname;
- if (!lastname.empty() && lastname != "Resident")
- {
- // support traditional First Last name SLURLs
- login_id += " ";
- login_id += lastname;
- }
- sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id);
- }
- else if((std::string)identifier["type"] == "account")
- {
- sInstance->getChild<LLComboBox>("username_combo")->setLabel((std::string)identifier["account_name"]);
- }
- else
- {
- sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string());
- }
- sInstance->addFavoritesToStartLocation();
- // if the password exists in the credential, set the password field with
- // a filler to get some stars
- LLSD authenticator = credential->getAuthenticator();
- LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL;
- if(authenticator.isMap() &&
- authenticator.has("secret") &&
- (authenticator["secret"].asString().size() > 0))
- {
-
- // This is a MD5 hex digest of a password.
- // We don't actually use the password input field,
- // fill it with MAX_PASSWORD characters so we get a
- // nice row of asterixes.
- const std::string filler("123456789!123456");
- sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string("123456789!123456"));
- }
- else
- {
- sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string());
- }
- sInstance->getChild<LLUICtrl>("remember_check")->setValue(remember);
-}
-
-
-// static
-void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
- BOOL& remember)
-{
- if (!sInstance)
- {
- llwarns << "Attempted getFields with no login view shown" << llendl;
- return;
- }
-
- // load the credential so we can pass back the stored password or hash if the user did
- // not modify the password field.
-
- credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
-
- LLSD identifier = LLSD::emptyMap();
- LLSD authenticator = LLSD::emptyMap();
-
- if(credential.notNull())
- {
- authenticator = credential->getAuthenticator();
- }
-
- std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
- LLStringUtil::trim(username);
- std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
-
- LL_INFOS2("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL;
- // determine if the username is a first/last form or not.
- size_t separator_index = username.find_first_of(' ');
- if (separator_index == username.npos
- && !LLGridManager::getInstance()->isSystemGrid())
- {
- LL_INFOS2("Credentials", "Authentication") << "account: " << username << LL_ENDL;
- // single username, so this is a 'clear' identifier
- identifier["type"] = CRED_IDENTIFIER_TYPE_ACCOUNT;
- identifier["account_name"] = username;
-
- if (LLPanelLogin::sInstance->mPasswordModified)
- {
- authenticator = LLSD::emptyMap();
- // password is plaintext
- authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR;
- authenticator["secret"] = password;
- }
- }
- else
- {
- // Be lenient in terms of what separators we allow for two-word names
- // and allow legacy users to login with firstname.lastname
- separator_index = username.find_first_of(" ._");
- std::string first = username.substr(0, separator_index);
- std::string last;
- if (separator_index != username.npos)
- {
- last = username.substr(separator_index+1, username.npos);
- LLStringUtil::trim(last);
- }
- else
- {
- // ...on Linden grids, single username users as considered to have
- // last name "Resident"
- // *TODO: Make login.cgi support "account_name" like above
- last = "Resident";
- }
-
- if (last.find_first_of(' ') == last.npos)
- {
- LL_INFOS2("Credentials", "Authentication") << "agent: " << username << LL_ENDL;
- // traditional firstname / lastname
- identifier["type"] = CRED_IDENTIFIER_TYPE_AGENT;
- identifier["first_name"] = first;
- identifier["last_name"] = last;
-
- if (LLPanelLogin::sInstance->mPasswordModified)
- {
- authenticator = LLSD::emptyMap();
- authenticator["type"] = CRED_AUTHENTICATOR_TYPE_HASH;
- authenticator["algorithm"] = "md5";
- LLMD5 pass((const U8 *)password.c_str());
- char md5pass[33]; /* Flawfinder: ignore */
- pass.hex_digest(md5pass);
- authenticator["secret"] = md5pass;
- }
- }
- }
- credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator);
- remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue();
-}
-
-// static
-BOOL LLPanelLogin::isGridComboDirty()
-{
- BOOL user_picked = FALSE;
- if (!sInstance)
- {
- llwarns << "Attempted getServer with no login view shown" << llendl;
- }
- else
- {
- LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
- user_picked = combo->isDirty();
- }
- return user_picked;
-}
-
-// static
-BOOL LLPanelLogin::areCredentialFieldsDirty()
-{
- if (!sInstance)
- {
- llwarns << "Attempted getServer with no login view shown" << llendl;
- }
- else
- {
- std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
- LLStringUtil::trim(username);
- std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
- LLComboBox* combo = sInstance->getChild<LLComboBox>("username_combo");
- if(combo && combo->isDirty())
- {
- return true;
- }
- LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("password_edit");
- if(ctrl && ctrl->isDirty())
- {
- return true;
- }
- }
- return false;
-}
-
-
-// static
-void LLPanelLogin::updateLocationCombo( bool force_visible )
-{
- if (!sInstance)
- {
- return;
- }
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
-
- switch(LLStartUp::getStartSLURL().getType())
- {
- case LLSLURL::LOCATION:
- {
-
- combo->setCurrentByIndex( 2 );
- combo->setTextEntry(LLStartUp::getStartSLURL().getLocationString());
- break;
- }
- case LLSLURL::HOME_LOCATION:
- combo->setCurrentByIndex(1);
- break;
- default:
- combo->setCurrentByIndex(0);
- break;
- }
-
- BOOL show_start = TRUE;
-
- if ( ! force_visible )
- show_start = gSavedSettings.getBOOL("ShowStartLocation");
-
- sInstance->getChildView("start_location_combo")->setVisible( show_start);
- sInstance->getChildView("start_location_text")->setVisible( show_start);
-
- BOOL show_server = gSavedSettings.getBOOL("ForceShowGrid");
- sInstance->getChildView("server_combo_text")->setVisible( show_server);
- sInstance->getChildView("server_combo")->setVisible( show_server);
-}
-
-// static
-void LLPanelLogin::updateStartSLURL()
-{
- if (!sInstance) return;
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
- S32 index = combo->getCurrentIndex();
-
- switch (index)
- {
- case 0:
- {
- LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST));
- break;
- }
- case 1:
- {
- LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
- break;
- }
- default:
- {
- LLSLURL slurl = LLSLURL(combo->getValue().asString());
- if(slurl.getType() == LLSLURL::LOCATION)
- {
- // we've changed the grid, so update the grid selection
- LLStartUp::setStartSLURL(slurl);
- }
- break;
- }
- }
-}
-
-
-void LLPanelLogin::setLocation(const LLSLURL& slurl)
-{
- LLStartUp::setStartSLURL(slurl);
- updateServer();
-}
-
-// static
-void LLPanelLogin::closePanel()
-{
- if (sInstance)
- {
- LLPanelLogin::sInstance->getParent()->removeChild( LLPanelLogin::sInstance );
-
- delete sInstance;
- sInstance = NULL;
- }
-}
-
-// static
-void LLPanelLogin::setAlwaysRefresh(bool refresh)
-{
- if (LLStartUp::getStartupState() >= STATE_LOGIN_CLEANUP) return;
-
- LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
-
- if (web_browser)
- {
- web_browser->setAlwaysRefresh(refresh);
- }
-}
-
-
-
-void LLPanelLogin::loadLoginPage()
-{
- if (!sInstance) return;
-
- std::ostringstream oStr;
-
- std::string login_page = LLGridManager::getInstance()->getLoginPage();
-
- oStr << login_page;
-
- // Use the right delimeter depending on how LLURI parses the URL
- LLURI login_page_uri = LLURI(login_page);
-
- std::string first_query_delimiter = "&";
- if (login_page_uri.queryMap().size() == 0)
- {
- first_query_delimiter = "?";
- }
-
- // Language
- std::string language = LLUI::getLanguage();
- oStr << first_query_delimiter<<"lang=" << language;
-
- // First Login?
- if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
- {
- oStr << "&firstlogin=TRUE";
- }
-
- // Channel and Version
- std::string version = llformat("%s (%d)",
- LLVersionInfo::getShortVersion().c_str(),
- LLVersionInfo::getBuild());
-
- char* curl_channel = curl_escape(LLVersionInfo::getChannel().c_str(), 0);
- char* curl_version = curl_escape(version.c_str(), 0);
-
- oStr << "&channel=" << curl_channel;
- oStr << "&version=" << curl_version;
-
- curl_free(curl_channel);
- curl_free(curl_version);
-
- // Grid
- char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLabel().c_str(), 0);
- oStr << "&grid=" << curl_grid;
- curl_free(curl_grid);
-
- // add OS info
- char * os_info = curl_escape(LLAppViewer::instance()->getOSInfo().getOSStringSimple().c_str(), 0);
- oStr << "&os=" << os_info;
- curl_free(os_info);
-
-
- gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
- gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor());
-
- LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
-
- // navigate to the "real" page
- if (gSavedSettings.getBOOL("RegInClient"))
- {
- web_browser->setFocus(TRUE);
- login_page = sInstance->getString("reg_in_client_url");
- web_browser->navigateTo(login_page, "text/html");
- }
- else
- {
- web_browser->navigateTo( oStr.str(), "text/html" );
- }
-}
-
-void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event)
-{
- if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
- {
- LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
- if (web_browser)
- {
- // *HACK HACK HACK HACK!
- /* Stuff a Tab key into the browser now so that the first field will
- ** get the focus! The embedded javascript on the page that properly
- ** sets the initial focus in a real web browser is not working inside
- ** the viewer, so this is an UGLY HACK WORKAROUND for now.
- */
- // Commented out as it's not reliable
- //web_browser->handleKey(KEY_TAB, MASK_NONE, false);
- }
- }
-}
-
-//---------------------------------------------------------------------------
-// Protected methods
-//---------------------------------------------------------------------------
-
-// static
-void LLPanelLogin::onClickConnect(void *)
-{
- if (sInstance && sInstance->mCallback)
- {
- // tell the responder we're not here anymore
- if ( gResponsePtr )
- gResponsePtr->setParent( 0 );
-
- // JC - Make sure the fields all get committed.
- sInstance->setFocus(FALSE);
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
- LLSD combo_val = combo->getSelectedValue();
- if (combo_val.isUndefined())
- {
- combo_val = combo->getValue();
- }
- if(combo_val.isUndefined())
- {
- LLNotificationsUtil::add("StartRegionEmpty");
- return;
- }
- try
- {
- LLGridManager::getInstance()->setGridChoice(combo_val.asString());
- }
- catch (LLInvalidGridName ex)
- {
- LLSD args;
- args["GRID"] = combo_val.asString();
- LLNotificationsUtil::add("InvalidGrid", args);
- return;
- }
- updateStartSLURL();
- std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
-
-
- if(username.empty())
- {
- // user must type in something into the username field
- LLNotificationsUtil::add("MustHaveAccountToLogIn");
- }
- else
- {
- LLPointer<LLCredential> cred;
- BOOL remember;
- getFields(cred, remember);
- std::string identifier_type;
- cred->identifierType(identifier_type);
- LLSD allowed_credential_types;
- LLGridManager::getInstance()->getLoginIdentifierTypes(allowed_credential_types);
-
- // check the typed in credential type against the credential types expected by the server.
- for(LLSD::array_iterator i = allowed_credential_types.beginArray();
- i != allowed_credential_types.endArray();
- i++)
- {
-
- if(i->asString() == identifier_type)
- {
- // yay correct credential type
- sInstance->mCallback(0, sInstance->mCallbackData);
- return;
- }
- }
-
- // Right now, maingrid is the only thing that is picky about
- // credential format, as it doesn't yet allow account (single username)
- // format creds. - Rox. James, we wanna fix the message when we change
- // this.
- LLNotificationsUtil::add("InvalidCredentialFormat");
- }
- }
-}
-
-/*
-// static
-bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- llinfos << "Going to account creation URL" << llendl;
- LLWeb::loadURLExternal( LLNotifications::instance().getGlobalString("CREATE_ACCOUNT_URL"));
- }
- else
- {
- sInstance->setFocus(TRUE);
- }
- return false;
-}
-*/
-
-// static
-void LLPanelLogin::onClickNewAccount(void*)
-{
- LLWeb::loadURLExternal(sInstance->getString("create_account_url"));
-}
-
-
-// static
-void LLPanelLogin::onClickVersion(void*)
-{
- LLFloaterReg::showInstance("sl_about");
-}
-
-//static
-void LLPanelLogin::onClickForgotPassword(void*)
-{
- if (sInstance )
- {
- LLWeb::loadURLExternal(sInstance->getString( "forgot_password_url" ));
- }
-}
-
-//static
-void LLPanelLogin::onClickHelp(void*)
-{
- if (sInstance)
- {
- LLViewerHelp* vhelp = LLViewerHelp::getInstance();
- vhelp->showTopic(vhelp->preLoginTopic());
- }
-}
-
-// static
-void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
-{
- LLPanelLogin *This = (LLPanelLogin *) user_data;
- This->mPasswordModified = TRUE;
- if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE)
- {
-// *TODO: use another way to notify user about enabled caps lock, see EXT-6858
- sCapslockDidNotification = TRUE;
- }
-}
-
-
-void LLPanelLogin::updateServer()
-{
- try
- {
-
- updateServerCombo();
- // if they've selected another grid, we should load the credentials
- // for that grid and set them to the UI.
- if(sInstance && !sInstance->areCredentialFieldsDirty())
- {
- LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
- bool remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue();
- sInstance->setFields(credential, remember);
- }
- // grid changed so show new splash screen (possibly)
- loadLoginPage();
- updateLocationCombo(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION);
- }
- catch (LLInvalidGridName ex)
- {
- // do nothing
- }
-}
-
-void LLPanelLogin::updateServerCombo()
-{
- if (!sInstance)
- {
- return;
- }
- // We add all of the possible values, sorted, and then add a bar and the current value at the top
- LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
- server_choice_combo->removeall();
-
- std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(!gSavedSettings.getBOOL("ShowBetaGrids"));
-
- for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin();
- grid_choice != known_grids.end();
- grid_choice++)
- {
- if (!grid_choice->first.empty())
- {
- server_choice_combo->add(grid_choice->second, grid_choice->first);
- }
- }
- server_choice_combo->sortByName();
-
- server_choice_combo->addSeparator(ADD_TOP);
-
- server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),
- LLGridManager::getInstance()->getGrid(), ADD_TOP);
-
- server_choice_combo->selectFirstItem();
-}
-
-// static
-void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
-{
- // *NOTE: The paramters for this method are ignored.
- // LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*)
- // calls this method.
- LL_INFOS("AppInit") << "onSelectServer" << LL_ENDL;
- // The user twiddled with the grid choice ui.
- // apply the selection to the grid setting.
- LLPointer<LLCredential> credential;
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
- LLSD combo_val = combo->getSelectedValue();
- if (combo_val.isUndefined())
- {
- combo_val = combo->getValue();
- }
-
- combo = sInstance->getChild<LLComboBox>("start_location_combo");
- combo->setCurrentByIndex(1);
- LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation")));
- LLGridManager::getInstance()->setGridChoice(combo_val.asString());
- // This new selection will override preset uris
- // from the command line.
- updateServer();
- updateLocationCombo(false);
- updateLoginPanelLinks();
-}
-
-void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe)
-{
- if (!sInstance)
- {
- return;
- }
-
- LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
- if(fe == combo)
- {
- onSelectServer(combo, NULL);
- }
-}
-
-void LLPanelLogin::updateLoginPanelLinks()
-{
- LLSD grid_data;
- LLGridManager::getInstance()->getGridInfo(grid_data);
- bool system_grid = grid_data.has(GRID_IS_SYSTEM_GRID_VALUE);
-
- // need to call through sInstance, as it's called from onSelectServer, which
- // is static.
- sInstance->getChildView("create_new_account_text")->setVisible( system_grid);
- sInstance->getChildView("forgot_password_text")->setVisible( system_grid);
-}
-
-std::string canonicalize_username(const std::string& name)
-{
- std::string cname = name;
- LLStringUtil::trim(cname);
-
- // determine if the username is a first/last form or not.
- size_t separator_index = cname.find_first_of(" ._");
- std::string first = cname.substr(0, separator_index);
- std::string last;
- if (separator_index != cname.npos)
- {
- last = cname.substr(separator_index+1, cname.npos);
- LLStringUtil::trim(last);
- }
- else
- {
- // ...on Linden grids, single username users as considered to have
- // last name "Resident"
- last = "Resident";
- }
-
- // Username in traditional "firstname lastname" form.
- return first + ' ' + last;
-}
+/**
+ * @file llpanellogin.cpp
+ * @brief Login dialog and logo display
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llpanellogin.h"
+
+#include "indra_constants.h" // for key and mask constants
+#include "llfloaterreg.h"
+#include "llfontgl.h"
+#include "llmd5.h"
+#include "llsecondlifeurls.h"
+#include "v4color.h"
+
+#include "llappviewer.h"
+#include "llbutton.h"
+#include "llcheckboxctrl.h"
+#include "llcommandhandler.h" // for secondlife:///app/login/
+#include "llcombobox.h"
+#include "llcurl.h"
+#include "llviewercontrol.h"
+#include "llfloaterpreference.h"
+#include "llfocusmgr.h"
+#include "lllineeditor.h"
+#include "llnotificationsutil.h"
+#include "llsecapi.h"
+#include "llstartup.h"
+#include "lltextbox.h"
+#include "llui.h"
+#include "lluiconstants.h"
+#include "llslurl.h"
+#include "llversioninfo.h"
+#include "llviewerhelp.h"
+#include "llviewertexturelist.h"
+#include "llviewermenu.h" // for handle_preferences()
+#include "llviewernetwork.h"
+#include "llviewerwindow.h" // to link into child list
+#include "lluictrlfactory.h"
+#include "llhttpclient.h"
+#include "llweb.h"
+#include "llmediactrl.h"
+#include "llrootview.h"
+
+#include "llfloatertos.h"
+#include "lltrans.h"
+#include "llglheaders.h"
+#include "llpanelloginlistener.h"
+
+#if LL_WINDOWS
+#pragma warning(disable: 4355) // 'this' used in initializer list
+#endif // LL_WINDOWS
+
+#include "llsdserialize.h"
+
+const S32 BLACK_BORDER_HEIGHT = 160;
+const S32 MAX_PASSWORD = 16;
+
+LLPanelLogin *LLPanelLogin::sInstance = NULL;
+BOOL LLPanelLogin::sCapslockDidNotification = FALSE;
+
+
+class LLLoginRefreshHandler : public LLCommandHandler
+{
+public:
+ // don't allow from external browsers
+ LLLoginRefreshHandler() : LLCommandHandler("login_refresh", UNTRUSTED_BLOCK) { }
+ bool handle(const LLSD& tokens, const LLSD& query_map, LLMediaCtrl* web)
+ {
+ if (LLStartUp::getStartupState() < STATE_LOGIN_CLEANUP)
+ {
+ LLPanelLogin::loadLoginPage();
+ }
+ return true;
+ }
+};
+
+LLLoginRefreshHandler gLoginRefreshHandler;
+
+
+// helper class that trys to download a URL from a web site and calls a method
+// on parent class indicating if the web server is working or not
+class LLIamHereLogin : public LLHTTPClient::Responder
+{
+ private:
+ LLIamHereLogin( LLPanelLogin* parent ) :
+ mParent( parent )
+ {}
+
+ LLPanelLogin* mParent;
+
+ public:
+ static boost::intrusive_ptr< LLIamHereLogin > build( LLPanelLogin* parent )
+ {
+ return boost::intrusive_ptr< LLIamHereLogin >( new LLIamHereLogin( parent ) );
+ };
+
+ virtual void setParent( LLPanelLogin* parentIn )
+ {
+ mParent = parentIn;
+ };
+
+ // We don't actually expect LLSD back, so need to override completedRaw
+ virtual void completedRaw(U32 status, const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+ {
+ completed(status, reason, LLSD()); // will call result() or error()
+ }
+
+ virtual void result( const LLSD& content )
+ {
+ if ( mParent )
+ mParent->setSiteIsAlive( true );
+ };
+
+ virtual void error( U32 status, const std::string& reason )
+ {
+ if ( mParent )
+ mParent->setSiteIsAlive( false );
+ };
+};
+
+// this is global and not a class member to keep crud out of the header file
+namespace {
+ boost::intrusive_ptr< LLIamHereLogin > gResponsePtr = 0;
+};
+
+
+//---------------------------------------------------------------------------
+// Public methods
+//---------------------------------------------------------------------------
+LLPanelLogin::LLPanelLogin(const LLRect &rect,
+ BOOL show_server,
+ void (*callback)(S32 option, void* user_data),
+ void *cb_data)
+: LLPanel(),
+ mLogoImage(),
+ mCallback(callback),
+ mCallbackData(cb_data),
+ mHtmlAvailable( TRUE ),
+ mListener(new LLPanelLoginListener(this))
+{
+ setBackgroundVisible(FALSE);
+ setBackgroundOpaque(TRUE);
+
+ // instance management
+ if (LLPanelLogin::sInstance)
+ {
+ llwarns << "Duplicate instance of login view deleted" << llendl;
+ // Don't leave bad pointer in gFocusMgr
+ gFocusMgr.setDefaultKeyboardFocus(NULL);
+
+ delete LLPanelLogin::sInstance;
+ }
+
+ mPasswordModified = FALSE;
+ LLPanelLogin::sInstance = this;
+
+ LLView* login_holder = gViewerWindow->getLoginPanelHolder();
+ if (login_holder)
+ {
+ login_holder->addChild(this);
+ }
+
+ // Logo
+ mLogoImage = LLUI::getUIImage("startup_logo");
+
+ buildFromFile( "panel_login.xml");
+
+ // Legacy login web page is hidden under the menu bar.
+ // Adjust reg-in-client web browser widget to not be hidden.
+ if (gSavedSettings.getBOOL("RegInClient"))
+ {
+ reshape(rect.getWidth(), rect.getHeight() - MENU_BAR_HEIGHT);
+ }
+ else
+ {
+ reshape(rect.getWidth(), rect.getHeight());
+ }
+
+ getChild<LLLineEditor>("password_edit")->setKeystrokeCallback(onPassKey, this);
+
+ // change z sort of clickable text to be behind buttons
+ //sendChildToBack(getChildView("channel_text"));
+ sendChildToBack(getChildView("forgot_password_text"));
+
+ if(LLStartUp::getStartSLURL().getType() != LLSLURL::LOCATION)
+ {
+ LLSLURL slurl(gSavedSettings.getString("LoginLocation"));
+ LLStartUp::setStartSLURL(slurl);
+ }
+ updateLocationCombo(false);
+
+ gSavedSettings.getControl("SessionSettingsFile")->getSignal()->connect(boost::bind(&onModeChange));
+
+ LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
+ server_choice_combo->setCommitCallback(onSelectServer, NULL);
+ server_choice_combo->setFocusLostCallback(boost::bind(onServerComboLostFocus, _1));
+ updateServerCombo();
+
+ childSetAction("connect_btn", onClickConnect, this);
+
+ getChild<LLPanel>("login")->setDefaultBtn("connect_btn");
+
+ std::string channel = LLVersionInfo::getChannel();
+ std::string version = llformat("%s (%d)",
+ LLVersionInfo::getShortVersion().c_str(),
+ LLVersionInfo::getBuild());
+ //LLTextBox* channel_text = getChild<LLTextBox>("channel_text");
+ //channel_text->setTextArg("[CHANNEL]", channel); // though not displayed
+ //channel_text->setTextArg("[VERSION]", version);
+ //channel_text->setClickedCallback(onClickVersion, this);
+
+ LLTextBox* forgot_password_text = getChild<LLTextBox>("forgot_password_text");
+ forgot_password_text->setClickedCallback(onClickForgotPassword, NULL);
+
+ LLTextBox* create_new_account_text = getChild<LLTextBox>("create_new_account_text");
+ create_new_account_text->setClickedCallback(onClickNewAccount, NULL);
+
+ LLTextBox* need_help_text = getChild<LLTextBox>("login_help");
+ need_help_text->setClickedCallback(onClickHelp, NULL);
+
+ // get the web browser control
+ LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
+ web_browser->addObserver(this);
+
+ // Clear the browser's cache to avoid any potential for the cache messing up the login screen.
+ web_browser->clearCache();
+
+ reshapeBrowser();
+
+ // kick off a request to grab the url manually
+ gResponsePtr = LLIamHereLogin::build( this );
+
+ LLHTTPClient::head( LLGridManager::getInstance()->getLoginPage(), gResponsePtr );
+
+ // Show last logged in user favorites in "Start at" combo.
+ addUsersWithFavoritesToUsername();
+ getChild<LLComboBox>("username_combo")->setTextChangedCallback(boost::bind(&LLPanelLogin::addFavoritesToStartLocation, this));
+
+ updateLocationCombo(false);
+
+}
+
+void LLPanelLogin::addUsersWithFavoritesToUsername()
+{
+ LLComboBox* combo = getChild<LLComboBox>("username_combo");
+ if (!combo) return;
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
+ LLSD fav_llsd;
+ llifstream file;
+ file.open(filename);
+ if (!file.is_open()) return;
+ LLSDSerialize::fromXML(fav_llsd, file);
+ for (LLSD::map_const_iterator iter = fav_llsd.beginMap();
+ iter != fav_llsd.endMap(); ++iter)
+ {
+ combo->add(iter->first);
+ }
+}
+
+void LLPanelLogin::addFavoritesToStartLocation()
+{
+ LLComboBox* combo = getChild<LLComboBox>("start_location_combo");
+ if (!combo) return;
+ int num_items = combo->getItemCount();
+ for (int i = num_items - 1; i > 2; i--)
+ {
+ combo->remove(i);
+ }
+ std::string filename = gDirUtilp->getExpandedFilename(LL_PATH_USER_SETTINGS, "stored_favorites.xml");
+ LLSD fav_llsd;
+ llifstream file;
+ file.open(filename);
+ if (!file.is_open()) return;
+ LLSDSerialize::fromXML(fav_llsd, file);
+ for (LLSD::map_const_iterator iter = fav_llsd.beginMap();
+ iter != fav_llsd.endMap(); ++iter)
+ {
+ if(iter->first != getChild<LLComboBox>("username_combo")->getSimple()) continue;
+ combo->addSeparator();
+ LLSD user_llsd = iter->second;
+ for (LLSD::array_const_iterator iter1 = user_llsd.beginArray();
+ iter1 != user_llsd.endArray(); ++iter1)
+ {
+ std::string label = (*iter1)["name"].asString();
+ std::string value = (*iter1)["slurl"].asString();
+ if(label != "" && value != "")
+ {
+ combo->add(label, value);
+ }
+ }
+ break;
+ }
+}
+
+// force the size to be correct (XML doesn't seem to be sufficient to do this)
+// (with some padding so the other login screen doesn't show through)
+void LLPanelLogin::reshapeBrowser()
+{
+ LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
+ LLRect rect = gViewerWindow->getWindowRectScaled();
+ LLRect html_rect;
+ html_rect.setCenterAndSize(
+ rect.getCenterX() - 2, rect.getCenterY() + 40,
+ rect.getWidth() + 6, rect.getHeight() - 78 );
+ web_browser->setRect( html_rect );
+ web_browser->reshape( html_rect.getWidth(), html_rect.getHeight(), TRUE );
+ reshape( rect.getWidth(), rect.getHeight(), 1 );
+}
+
+void LLPanelLogin::setSiteIsAlive( bool alive )
+{
+ LLMediaCtrl* web_browser = getChild<LLMediaCtrl>("login_html");
+ // if the contents of the site was retrieved
+ if ( alive )
+ {
+ if ( web_browser )
+ {
+ loadLoginPage();
+
+ // mark as available
+ mHtmlAvailable = TRUE;
+ }
+ }
+ else
+ // the site is not available (missing page, server down, other badness)
+ {
+ if ( web_browser )
+ {
+ // hide browser control (revealing default one)
+ web_browser->setVisible( FALSE );
+
+ // mark as unavailable
+ mHtmlAvailable = FALSE;
+ }
+ }
+}
+
+
+LLPanelLogin::~LLPanelLogin()
+{
+ LLPanelLogin::sInstance = NULL;
+
+ // tell the responder we're not here anymore
+ if ( gResponsePtr )
+ gResponsePtr->setParent( 0 );
+
+ //// We know we're done with the image, so be rid of it.
+ //gTextureList.deleteImage( mLogoImage );
+
+ // Controls having keyboard focus by default
+ // must reset it on destroy. (EXT-2748)
+ gFocusMgr.setDefaultKeyboardFocus(NULL);
+}
+
+// virtual
+void LLPanelLogin::draw()
+{
+ glPushMatrix();
+ {
+ F32 image_aspect = 1.333333f;
+ F32 view_aspect = (F32)getRect().getWidth() / (F32)getRect().getHeight();
+ // stretch image to maintain aspect ratio
+ if (image_aspect > view_aspect)
+ {
+ glTranslatef(-0.5f * (image_aspect / view_aspect - 1.f) * getRect().getWidth(), 0.f, 0.f);
+ glScalef(image_aspect / view_aspect, 1.f, 1.f);
+ }
+
+ S32 width = getRect().getWidth();
+ S32 height = getRect().getHeight();
+
+ if ( mHtmlAvailable )
+ {
+ if (getChild<LLView>("login_widgets")->getVisible())
+ {
+ // draw a background box in black
+ gl_rect_2d( 0, height - 264, width, 264, LLColor4::black );
+ // draw the bottom part of the background image
+ // just the blue background to the native client UI
+ mLogoImage->draw(0, -264, width + 8, mLogoImage->getHeight());
+ }
+ }
+ else
+ {
+ // the HTML login page is not available so default to the original screen
+ S32 offscreen_part = height / 3;
+ mLogoImage->draw(0, -offscreen_part, width, height+offscreen_part);
+ };
+ }
+ glPopMatrix();
+
+ LLPanel::draw();
+}
+
+// virtual
+BOOL LLPanelLogin::handleKeyHere(KEY key, MASK mask)
+{
+ if ( KEY_F1 == key )
+ {
+ LLViewerHelp* vhelp = LLViewerHelp::getInstance();
+ vhelp->showTopic(vhelp->f1HelpTopic());
+ return TRUE;
+ }
+
+ return LLPanel::handleKeyHere(key, mask);
+}
+
+// virtual
+void LLPanelLogin::setFocus(BOOL b)
+{
+ if(b != hasFocus())
+ {
+ if(b)
+ {
+ LLPanelLogin::giveFocus();
+ }
+ else
+ {
+ LLPanel::setFocus(b);
+ }
+ }
+}
+
+// static
+void LLPanelLogin::giveFocus()
+{
+ if( sInstance )
+ {
+ // Grab focus and move cursor to first blank input field
+ std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
+ std::string pass = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
+
+ BOOL have_username = !username.empty();
+ BOOL have_pass = !pass.empty();
+
+ LLLineEditor* edit = NULL;
+ LLComboBox* combo = NULL;
+ if (have_username && !have_pass)
+ {
+ // User saved his name but not his password. Move
+ // focus to password field.
+ edit = sInstance->getChild<LLLineEditor>("password_edit");
+ }
+ else
+ {
+ // User doesn't have a name, so start there.
+ combo = sInstance->getChild<LLComboBox>("username_combo");
+ }
+
+ if (edit)
+ {
+ edit->setFocus(TRUE);
+ edit->selectAll();
+ }
+ else if (combo)
+ {
+ combo->setFocus(TRUE);
+ }
+ }
+}
+
+// static
+void LLPanelLogin::showLoginWidgets()
+{
+ // *NOTE: Mani - This may or may not be obselete code.
+ // It seems to be part of the defunct? reg-in-client project.
+ sInstance->getChildView("login_widgets")->setVisible( true);
+ LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
+ sInstance->reshapeBrowser();
+ // *TODO: Append all the usual login parameters, like first_login=Y etc.
+ std::string splash_screen_url = LLGridManager::getInstance()->getLoginPage();
+ web_browser->navigateTo( splash_screen_url, "text/html" );
+ LLUICtrl* username_combo = sInstance->getChild<LLUICtrl>("username_combo");
+ username_combo->setFocus(TRUE);
+}
+
+// static
+void LLPanelLogin::show(const LLRect &rect,
+ BOOL show_server,
+ void (*callback)(S32 option, void* user_data),
+ void* callback_data)
+{
+ new LLPanelLogin(rect, show_server, callback, callback_data);
+
+ if( !gFocusMgr.getKeyboardFocus() )
+ {
+ // Grab focus and move cursor to first enabled control
+ sInstance->setFocus(TRUE);
+ }
+
+ // Make sure that focus always goes here (and use the latest sInstance that was just created)
+ gFocusMgr.setDefaultKeyboardFocus(sInstance);
+}
+
+// static
+void LLPanelLogin::setFields(LLPointer<LLCredential> credential,
+ BOOL remember)
+{
+ if (!sInstance)
+ {
+ llwarns << "Attempted fillFields with no login view shown" << llendl;
+ return;
+ }
+ LL_INFOS("Credentials") << "Setting login fields to " << *credential << LL_ENDL;
+
+ LLSD identifier = credential->getIdentifier();
+ if((std::string)identifier["type"] == "agent")
+ {
+ std::string firstname = identifier["first_name"].asString();
+ std::string lastname = identifier["last_name"].asString();
+ std::string login_id = firstname;
+ if (!lastname.empty() && lastname != "Resident")
+ {
+ // support traditional First Last name SLURLs
+ login_id += " ";
+ login_id += lastname;
+ }
+ sInstance->getChild<LLComboBox>("username_combo")->setLabel(login_id);
+ }
+ else if((std::string)identifier["type"] == "account")
+ {
+ sInstance->getChild<LLComboBox>("username_combo")->setLabel((std::string)identifier["account_name"]);
+ }
+ else
+ {
+ sInstance->getChild<LLComboBox>("username_combo")->setLabel(std::string());
+ }
+ sInstance->addFavoritesToStartLocation();
+ // if the password exists in the credential, set the password field with
+ // a filler to get some stars
+ LLSD authenticator = credential->getAuthenticator();
+ LL_INFOS("Credentials") << "Setting authenticator field " << authenticator["type"].asString() << LL_ENDL;
+ if(authenticator.isMap() &&
+ authenticator.has("secret") &&
+ (authenticator["secret"].asString().size() > 0))
+ {
+
+ // This is a MD5 hex digest of a password.
+ // We don't actually use the password input field,
+ // fill it with MAX_PASSWORD characters so we get a
+ // nice row of asterixes.
+ const std::string filler("123456789!123456");
+ sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string("123456789!123456"));
+ }
+ else
+ {
+ sInstance->getChild<LLUICtrl>("password_edit")->setValue(std::string());
+ }
+ sInstance->getChild<LLUICtrl>("remember_check")->setValue(remember);
+}
+
+
+// static
+void LLPanelLogin::getFields(LLPointer<LLCredential>& credential,
+ BOOL& remember)
+{
+ if (!sInstance)
+ {
+ llwarns << "Attempted getFields with no login view shown" << llendl;
+ return;
+ }
+
+ // load the credential so we can pass back the stored password or hash if the user did
+ // not modify the password field.
+
+ credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+
+ LLSD identifier = LLSD::emptyMap();
+ LLSD authenticator = LLSD::emptyMap();
+
+ if(credential.notNull())
+ {
+ authenticator = credential->getAuthenticator();
+ }
+
+ std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
+ LLStringUtil::trim(username);
+ std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
+
+ LL_INFOS2("Credentials", "Authentication") << "retrieving username:" << username << LL_ENDL;
+ // determine if the username is a first/last form or not.
+ size_t separator_index = username.find_first_of(' ');
+ if (separator_index == username.npos
+ && !LLGridManager::getInstance()->isSystemGrid())
+ {
+ LL_INFOS2("Credentials", "Authentication") << "account: " << username << LL_ENDL;
+ // single username, so this is a 'clear' identifier
+ identifier["type"] = CRED_IDENTIFIER_TYPE_ACCOUNT;
+ identifier["account_name"] = username;
+
+ if (LLPanelLogin::sInstance->mPasswordModified)
+ {
+ authenticator = LLSD::emptyMap();
+ // password is plaintext
+ authenticator["type"] = CRED_AUTHENTICATOR_TYPE_CLEAR;
+ authenticator["secret"] = password;
+ }
+ }
+ else
+ {
+ // Be lenient in terms of what separators we allow for two-word names
+ // and allow legacy users to login with firstname.lastname
+ separator_index = username.find_first_of(" ._");
+ std::string first = username.substr(0, separator_index);
+ std::string last;
+ if (separator_index != username.npos)
+ {
+ last = username.substr(separator_index+1, username.npos);
+ LLStringUtil::trim(last);
+ }
+ else
+ {
+ // ...on Linden grids, single username users as considered to have
+ // last name "Resident"
+ // *TODO: Make login.cgi support "account_name" like above
+ last = "Resident";
+ }
+
+ if (last.find_first_of(' ') == last.npos)
+ {
+ LL_INFOS2("Credentials", "Authentication") << "agent: " << username << LL_ENDL;
+ // traditional firstname / lastname
+ identifier["type"] = CRED_IDENTIFIER_TYPE_AGENT;
+ identifier["first_name"] = first;
+ identifier["last_name"] = last;
+
+ if (LLPanelLogin::sInstance->mPasswordModified)
+ {
+ authenticator = LLSD::emptyMap();
+ authenticator["type"] = CRED_AUTHENTICATOR_TYPE_HASH;
+ authenticator["algorithm"] = "md5";
+ LLMD5 pass((const U8 *)password.c_str());
+ char md5pass[33]; /* Flawfinder: ignore */
+ pass.hex_digest(md5pass);
+ authenticator["secret"] = md5pass;
+ }
+ }
+ }
+ credential = gSecAPIHandler->createCredential(LLGridManager::getInstance()->getGrid(), identifier, authenticator);
+ remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue();
+}
+
+// static
+BOOL LLPanelLogin::isGridComboDirty()
+{
+ BOOL user_picked = FALSE;
+ if (!sInstance)
+ {
+ llwarns << "Attempted getServer with no login view shown" << llendl;
+ }
+ else
+ {
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
+ user_picked = combo->isDirty();
+ }
+ return user_picked;
+}
+
+// static
+BOOL LLPanelLogin::areCredentialFieldsDirty()
+{
+ if (!sInstance)
+ {
+ llwarns << "Attempted getServer with no login view shown" << llendl;
+ }
+ else
+ {
+ std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
+ LLStringUtil::trim(username);
+ std::string password = sInstance->getChild<LLUICtrl>("password_edit")->getValue().asString();
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("username_combo");
+ if(combo && combo->isDirty())
+ {
+ return true;
+ }
+ LLLineEditor* ctrl = sInstance->getChild<LLLineEditor>("password_edit");
+ if(ctrl && ctrl->isDirty())
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+
+// static
+void LLPanelLogin::updateLocationCombo( bool force_visible )
+{
+ if (!sInstance)
+ {
+ return;
+ }
+
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
+
+ switch(LLStartUp::getStartSLURL().getType())
+ {
+ case LLSLURL::LOCATION:
+ {
+
+ combo->setCurrentByIndex( 2 );
+ combo->setTextEntry(LLStartUp::getStartSLURL().getLocationString());
+ break;
+ }
+ case LLSLURL::HOME_LOCATION:
+ combo->setCurrentByIndex(1);
+ break;
+ default:
+ combo->setCurrentByIndex(0);
+ break;
+ }
+
+ BOOL show_start = TRUE;
+
+ if ( ! force_visible )
+ show_start = gSavedSettings.getBOOL("ShowStartLocation");
+
+ sInstance->getChildView("start_location_combo")->setVisible( show_start);
+ sInstance->getChildView("start_location_text")->setVisible( show_start);
+
+ BOOL show_server = gSavedSettings.getBOOL("ForceShowGrid");
+ sInstance->getChildView("server_combo_text")->setVisible( show_server);
+ sInstance->getChildView("server_combo")->setVisible( show_server);
+}
+
+// static
+void LLPanelLogin::updateStartSLURL()
+{
+ if (!sInstance) return;
+
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("start_location_combo");
+ S32 index = combo->getCurrentIndex();
+
+ switch (index)
+ {
+ case 0:
+ {
+ LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_LAST));
+ break;
+ }
+ case 1:
+ {
+ LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
+ break;
+ }
+ default:
+ {
+ LLSLURL slurl = LLSLURL(combo->getValue().asString());
+ if(slurl.getType() == LLSLURL::LOCATION)
+ {
+ // we've changed the grid, so update the grid selection
+ LLStartUp::setStartSLURL(slurl);
+ }
+ break;
+ }
+ }
+}
+
+
+void LLPanelLogin::setLocation(const LLSLURL& slurl)
+{
+ LLStartUp::setStartSLURL(slurl);
+ updateServer();
+}
+
+// static
+void LLPanelLogin::closePanel()
+{
+ if (sInstance)
+ {
+ LLPanelLogin::sInstance->getParent()->removeChild( LLPanelLogin::sInstance );
+
+ delete sInstance;
+ sInstance = NULL;
+ }
+}
+
+// static
+void LLPanelLogin::setAlwaysRefresh(bool refresh)
+{
+ if (LLStartUp::getStartupState() >= STATE_LOGIN_CLEANUP) return;
+
+ LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
+
+ if (web_browser)
+ {
+ web_browser->setAlwaysRefresh(refresh);
+ }
+}
+
+
+
+void LLPanelLogin::loadLoginPage()
+{
+ if (!sInstance) return;
+
+ std::ostringstream oStr;
+
+ std::string login_page = LLGridManager::getInstance()->getLoginPage();
+
+ oStr << login_page;
+
+ // Use the right delimeter depending on how LLURI parses the URL
+ LLURI login_page_uri = LLURI(login_page);
+
+ std::string first_query_delimiter = "&";
+ if (login_page_uri.queryMap().size() == 0)
+ {
+ first_query_delimiter = "?";
+ }
+
+ // Language
+ std::string language = LLUI::getLanguage();
+ oStr << first_query_delimiter<<"lang=" << language;
+
+ // First Login?
+ if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
+ {
+ oStr << "&firstlogin=TRUE";
+ }
+
+ // Channel and Version
+ std::string version = llformat("%s (%d)",
+ LLVersionInfo::getShortVersion().c_str(),
+ LLVersionInfo::getBuild());
+
+ char* curl_channel = curl_escape(LLVersionInfo::getChannel().c_str(), 0);
+ char* curl_version = curl_escape(version.c_str(), 0);
+
+ oStr << "&channel=" << curl_channel;
+ oStr << "&version=" << curl_version;
+
+ curl_free(curl_channel);
+ curl_free(curl_version);
+
+ // Grid
+ char* curl_grid = curl_escape(LLGridManager::getInstance()->getGridLabel().c_str(), 0);
+ oStr << "&grid=" << curl_grid;
+ curl_free(curl_grid);
+
+ // add OS info
+ char * os_info = curl_escape(LLAppViewer::instance()->getOSInfo().getOSStringSimple().c_str(), 0);
+ oStr << "&os=" << os_info;
+ curl_free(os_info);
+
+
+ gViewerWindow->setMenuBackgroundColor(false, !LLGridManager::getInstance()->isInProductionGrid());
+ gLoginMenuBarView->setBackgroundColor(gMenuBarView->getBackgroundColor());
+
+ LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
+
+ // navigate to the "real" page
+ if (gSavedSettings.getBOOL("RegInClient"))
+ {
+ web_browser->setFocus(TRUE);
+ login_page = sInstance->getString("reg_in_client_url");
+ web_browser->navigateTo(login_page, "text/html");
+ }
+ else
+ {
+ web_browser->navigateTo( oStr.str(), "text/html" );
+ }
+}
+
+void LLPanelLogin::handleMediaEvent(LLPluginClassMedia* /*self*/, EMediaEvent event)
+{
+ if(event == MEDIA_EVENT_NAVIGATE_COMPLETE)
+ {
+ LLMediaCtrl* web_browser = sInstance->getChild<LLMediaCtrl>("login_html");
+ if (web_browser)
+ {
+ // *HACK HACK HACK HACK!
+ /* Stuff a Tab key into the browser now so that the first field will
+ ** get the focus! The embedded javascript on the page that properly
+ ** sets the initial focus in a real web browser is not working inside
+ ** the viewer, so this is an UGLY HACK WORKAROUND for now.
+ */
+ // Commented out as it's not reliable
+ //web_browser->handleKey(KEY_TAB, MASK_NONE, false);
+ }
+ }
+}
+
+//---------------------------------------------------------------------------
+// Protected methods
+//---------------------------------------------------------------------------
+
+// static
+void LLPanelLogin::onClickConnect(void *)
+{
+ if (sInstance && sInstance->mCallback)
+ {
+ // tell the responder we're not here anymore
+ if ( gResponsePtr )
+ gResponsePtr->setParent( 0 );
+
+ // JC - Make sure the fields all get committed.
+ sInstance->setFocus(FALSE);
+
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
+ LLSD combo_val = combo->getSelectedValue();
+ if (combo_val.isUndefined())
+ {
+ combo_val = combo->getValue();
+ }
+ if(combo_val.isUndefined())
+ {
+ LLNotificationsUtil::add("StartRegionEmpty");
+ return;
+ }
+ try
+ {
+ LLGridManager::getInstance()->setGridChoice(combo_val.asString());
+ }
+ catch (LLInvalidGridName ex)
+ {
+ LLSD args;
+ args["GRID"] = combo_val.asString();
+ LLNotificationsUtil::add("InvalidGrid", args);
+ return;
+ }
+ updateStartSLURL();
+ std::string username = sInstance->getChild<LLUICtrl>("username_combo")->getValue().asString();
+
+
+ if(username.empty())
+ {
+ // user must type in something into the username field
+ LLNotificationsUtil::add("MustHaveAccountToLogIn");
+ }
+ else
+ {
+ LLPointer<LLCredential> cred;
+ BOOL remember;
+ getFields(cred, remember);
+ std::string identifier_type;
+ cred->identifierType(identifier_type);
+ LLSD allowed_credential_types;
+ LLGridManager::getInstance()->getLoginIdentifierTypes(allowed_credential_types);
+
+ // check the typed in credential type against the credential types expected by the server.
+ for(LLSD::array_iterator i = allowed_credential_types.beginArray();
+ i != allowed_credential_types.endArray();
+ i++)
+ {
+
+ if(i->asString() == identifier_type)
+ {
+ // yay correct credential type
+ sInstance->mCallback(0, sInstance->mCallbackData);
+ return;
+ }
+ }
+
+ // Right now, maingrid is the only thing that is picky about
+ // credential format, as it doesn't yet allow account (single username)
+ // format creds. - Rox. James, we wanna fix the message when we change
+ // this.
+ LLNotificationsUtil::add("InvalidCredentialFormat");
+ }
+ }
+}
+
+/*
+// static
+bool LLPanelLogin::newAccountAlertCallback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ llinfos << "Going to account creation URL" << llendl;
+ LLWeb::loadURLExternal( LLNotifications::instance().getGlobalString("CREATE_ACCOUNT_URL"));
+ }
+ else
+ {
+ sInstance->setFocus(TRUE);
+ }
+ return false;
+}
+*/
+
+// static
+void LLPanelLogin::onClickNewAccount(void*)
+{
+ LLWeb::loadURLExternal(sInstance->getString("create_account_url"));
+}
+
+
+// static
+void LLPanelLogin::onClickVersion(void*)
+{
+ LLFloaterReg::showInstance("sl_about");
+}
+
+//static
+void LLPanelLogin::onClickForgotPassword(void*)
+{
+ if (sInstance )
+ {
+ LLWeb::loadURLExternal(sInstance->getString( "forgot_password_url" ));
+ }
+}
+
+//static
+void LLPanelLogin::onClickHelp(void*)
+{
+ if (sInstance)
+ {
+ LLViewerHelp* vhelp = LLViewerHelp::getInstance();
+ vhelp->showTopic(vhelp->preLoginTopic());
+ }
+}
+
+// static
+void LLPanelLogin::onPassKey(LLLineEditor* caller, void* user_data)
+{
+ LLPanelLogin *This = (LLPanelLogin *) user_data;
+ This->mPasswordModified = TRUE;
+ if (gKeyboard->getKeyDown(KEY_CAPSLOCK) && sCapslockDidNotification == FALSE)
+ {
+// *TODO: use another way to notify user about enabled caps lock, see EXT-6858
+ sCapslockDidNotification = TRUE;
+ }
+}
+
+
+void LLPanelLogin::updateServer()
+{
+ try
+ {
+
+ updateServerCombo();
+ // if they've selected another grid, we should load the credentials
+ // for that grid and set them to the UI.
+ if(sInstance && !sInstance->areCredentialFieldsDirty())
+ {
+ LLPointer<LLCredential> credential = gSecAPIHandler->loadCredential(LLGridManager::getInstance()->getGrid());
+ bool remember = sInstance->getChild<LLUICtrl>("remember_check")->getValue();
+ sInstance->setFields(credential, remember);
+ }
+ // grid changed so show new splash screen (possibly)
+ loadLoginPage();
+ updateLocationCombo(LLStartUp::getStartSLURL().getType() == LLSLURL::LOCATION);
+ }
+ catch (LLInvalidGridName ex)
+ {
+ // do nothing
+ }
+}
+
+void LLPanelLogin::updateServerCombo()
+{
+ if (!sInstance)
+ {
+ return;
+ }
+ // We add all of the possible values, sorted, and then add a bar and the current value at the top
+ LLComboBox* server_choice_combo = sInstance->getChild<LLComboBox>("server_combo");
+ server_choice_combo->removeall();
+
+ std::map<std::string, std::string> known_grids = LLGridManager::getInstance()->getKnownGrids(!gSavedSettings.getBOOL("ShowBetaGrids"));
+
+ for (std::map<std::string, std::string>::iterator grid_choice = known_grids.begin();
+ grid_choice != known_grids.end();
+ grid_choice++)
+ {
+ if (!grid_choice->first.empty())
+ {
+ server_choice_combo->add(grid_choice->second, grid_choice->first);
+ }
+ }
+ server_choice_combo->sortByName();
+
+ server_choice_combo->addSeparator(ADD_TOP);
+
+ server_choice_combo->add(LLGridManager::getInstance()->getGridLabel(),
+ LLGridManager::getInstance()->getGrid(), ADD_TOP);
+
+ server_choice_combo->selectFirstItem();
+}
+
+// static
+void LLPanelLogin::onSelectServer(LLUICtrl*, void*)
+{
+ // *NOTE: The paramters for this method are ignored.
+ // LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe, void*)
+ // calls this method.
+ LL_INFOS("AppInit") << "onSelectServer" << LL_ENDL;
+ // The user twiddled with the grid choice ui.
+ // apply the selection to the grid setting.
+ LLPointer<LLCredential> credential;
+
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
+ LLSD combo_val = combo->getSelectedValue();
+ if (combo_val.isUndefined())
+ {
+ combo_val = combo->getValue();
+ }
+
+ combo = sInstance->getChild<LLComboBox>("start_location_combo");
+ combo->setCurrentByIndex(1);
+ LLStartUp::setStartSLURL(LLSLURL(gSavedSettings.getString("LoginLocation")));
+ LLGridManager::getInstance()->setGridChoice(combo_val.asString());
+ // This new selection will override preset uris
+ // from the command line.
+ updateServer();
+ updateLocationCombo(false);
+ updateLoginPanelLinks();
+}
+
+void LLPanelLogin::onServerComboLostFocus(LLFocusableElement* fe)
+{
+ if (!sInstance)
+ {
+ return;
+ }
+
+ LLComboBox* combo = sInstance->getChild<LLComboBox>("server_combo");
+ if(fe == combo)
+ {
+ onSelectServer(combo, NULL);
+ }
+}
+
+void LLPanelLogin::updateLoginPanelLinks()
+{
+ LLSD grid_data;
+ LLGridManager::getInstance()->getGridInfo(grid_data);
+ bool system_grid = grid_data.has(GRID_IS_SYSTEM_GRID_VALUE);
+
+ // need to call through sInstance, as it's called from onSelectServer, which
+ // is static.
+ sInstance->getChildView("create_new_account_text")->setVisible( system_grid);
+ sInstance->getChildView("forgot_password_text")->setVisible( system_grid);
+}
+
+//static
+void LLPanelLogin::onModeChange()
+{
+ LLNotificationsUtil::add("ModeChange", LLSD(), LLSD(), boost::bind(&onModeChangeConfirm, _1, _2));
+}
+
+//static
+void LLPanelLogin::onModeChangeConfirm(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ switch (option)
+ {
+ case 0:
+ LLAppViewer::instance()->requestQuit();
+ break;
+ case 1:
+ // do nothing
+ break;
+ default:
+ break;
+ }
+}
diff --git a/indra/newview/llpanellogin.h b/indra/newview/llpanellogin.h
index 1ef6539ecc..1430bec832 100644
--- a/indra/newview/llpanellogin.h
+++ b/indra/newview/llpanellogin.h
@@ -98,6 +98,8 @@ private:
static void onServerComboLostFocus(LLFocusableElement*);
static void updateServerCombo();
static void updateStartSLURL();
+ static void onModeChange();
+ static void onModeChangeConfirm(const LLSD& notification, const LLSD& response);
static void updateLoginPanelLinks();
diff --git a/indra/newview/llpanelpicks.cpp b/indra/newview/llpanelpicks.cpp
index c4f3866cad..ddce83c616 100755
--- a/indra/newview/llpanelpicks.cpp
+++ b/indra/newview/llpanelpicks.cpp
@@ -70,6 +70,7 @@ static const std::string CLASSIFIED_NAME("classified_name");
static LLRegisterPanelClassWrapper<LLPanelPicks> t_panel_picks("panel_picks");
+
class LLPickHandler : public LLCommandHandler,
public LLAvatarPropertiesObserver
{
@@ -83,6 +84,12 @@ public:
bool handle(const LLSD& params, const LLSD& query_map,
LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnablePicks"))
+ {
+ LLNotificationsUtil::add("NoPicks", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
// handle app/classified/create urls first
if (params.size() == 1 && params[0].asString() == "create")
{
@@ -189,6 +196,12 @@ public:
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableClassifieds"))
+ {
+ LLNotificationsUtil::add("NoClassifieds", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
// handle app/classified/create urls first
if (params.size() == 1 && params[0].asString() == "create")
{
diff --git a/indra/newview/llpanelprofile.cpp b/indra/newview/llpanelprofile.cpp
index 4f13c0c022..fd5c3362bb 100755
--- a/indra/newview/llpanelprofile.cpp
+++ b/indra/newview/llpanelprofile.cpp
@@ -31,16 +31,27 @@
#include "llavataractions.h"
#include "llfloaterreg.h"
#include "llcommandhandler.h"
+#include "llnotificationsutil.h"
#include "llpanelpicks.h"
#include "lltabcontainer.h"
#include "llviewercontrol.h"
+#include "llviewernetwork.h"
static const std::string PANEL_PICKS = "panel_picks";
static const std::string PANEL_PROFILE = "panel_profile";
std::string getProfileURL(const std::string& agent_name)
{
- std::string url = gSavedSettings.getString("WebProfileURL");
+ std::string url;
+
+ if (LLGridManager::getInstance()->isInProductionGrid())
+ {
+ url = gSavedSettings.getString("WebProfileURL");
+ }
+ else
+ {
+ url = gSavedSettings.getString("WebProfileNonProductionURL");
+ }
LLSD subs;
subs["AGENT_NAME"] = agent_name;
url = LLWeb::expandURLSubstitutions(url,subs);
@@ -105,6 +116,12 @@ public:
if (verb == "pay")
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAvatarPay"))
+ {
+ LLNotificationsUtil::add("NoAvatarPay", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
LLAvatarActions::pay(avatar_id);
return true;
}
diff --git a/indra/newview/llshareavatarhandler.cpp b/indra/newview/llshareavatarhandler.cpp
index 34194970b8..6b4f1d3dc6 100644
--- a/indra/newview/llshareavatarhandler.cpp
+++ b/indra/newview/llshareavatarhandler.cpp
@@ -27,6 +27,8 @@
#include "llviewerprecompiledheaders.h"
#include "llcommandhandler.h"
#include "llavataractions.h"
+#include "llnotificationsutil.h"
+#include "llui.h"
class LLShareWithAvatarHandler : public LLCommandHandler
{
@@ -38,6 +40,12 @@ public:
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableAvatarShare"))
+ {
+ LLNotificationsUtil::add("NoAvatarShare", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
//Make sure we have some parameters
if (params.size() == 0)
{
diff --git a/indra/newview/llsidetray.cpp b/indra/newview/llsidetray.cpp
index eb537c7d7b..8aaa7f0e13 100644
--- a/indra/newview/llsidetray.cpp
+++ b/indra/newview/llsidetray.cpp
@@ -629,8 +629,16 @@ LLPanel* LLSideTray::openChildPanel(LLSideTrayTab* tab, const std::string& panel
std::string tab_name = tab->getName();
+ bool tab_attached = isTabAttached(tab_name);
+
+ if (tab_attached && LLUI::sSettingGroups["config"]->getBOOL("OpenSidePanelsInFloaters"))
+ {
+ tab->toggleTabDocked();
+ tab_attached = false;
+ }
+
// Select tab and expand Side Tray only when a tab is attached.
- if (isTabAttached(tab_name))
+ if (tab_attached)
{
selectTabByName(tab_name);
if (mCollapsed)
@@ -641,14 +649,7 @@ LLPanel* LLSideTray::openChildPanel(LLSideTrayTab* tab, const std::string& panel
LLFloater* floater_tab = LLFloaterReg::getInstance("side_bar_tab", tab_name);
if (!floater_tab) return NULL;
- // Restore the floater if it was minimized.
- if (floater_tab->isMinimized())
- {
- floater_tab->setMinimized(FALSE);
- }
-
- // Send the floater to the front.
- floater_tab->setFrontmost();
+ floater_tab->openFloater(panel_name);
}
LLSideTrayPanelContainer* container = dynamic_cast<LLSideTrayPanelContainer*>(view->getParent());
@@ -979,16 +980,7 @@ void LLSideTray::reflectCollapseChange()
{
updateSidetrayVisibility();
- if(mCollapsed)
- {
- gFloaterView->setSnapOffsetRight(0);
- setFocus(FALSE);
- }
- else
- {
- gFloaterView->setSnapOffsetRight(getRect().getWidth());
- setFocus(TRUE);
- }
+ setFocus(!mCollapsed);
gFloaterView->refresh();
}
@@ -1161,23 +1153,43 @@ void LLSideTray::reshape(S32 width, S32 height, BOOL called_from_parent)
*/
LLPanel* LLSideTray::showPanel (const std::string& panel_name, const LLSD& params)
{
+ LLPanel* new_panel = NULL;
+
// Look up the tab in the list of detached tabs.
child_vector_const_iter_t child_it;
for ( child_it = mDetachedTabs.begin(); child_it != mDetachedTabs.end(); ++child_it)
{
- LLPanel* panel = openChildPanel(*child_it, panel_name, params);
- if (panel) return panel;
- }
+ new_panel = openChildPanel(*child_it, panel_name, params);
+ if (new_panel) break;
+ }
// Look up the tab in the list of attached tabs.
for ( child_it = mTabs.begin(); child_it != mTabs.end(); ++child_it)
- {
- LLPanel* panel = openChildPanel(*child_it, panel_name, params);
- if (panel) return panel;
+ {
+ new_panel = openChildPanel(*child_it, panel_name, params);
+ if (new_panel) break;
+ }
+
+ return new_panel;
+}
+
+void LLSideTray::hidePanel(const std::string& panel_name)
+{
+ LLPanel* panelp = getPanel(panel_name);
+ if (panelp)
+ {
+ if(isTabAttached(panel_name))
+ {
+ collapseSideBar();
+ }
+ else
+ {
+ LLFloaterReg::hideInstance("side_bar_tab", panel_name);
+ }
}
- return NULL;
}
+
void LLSideTray::togglePanel(LLPanel* &sub_panel, const std::string& panel_name, const LLSD& params)
{
if(!sub_panel)
@@ -1267,6 +1279,42 @@ bool LLSideTray::isPanelActive(const std::string& panel_name)
return (panel->getName() == panel_name);
}
+void LLSideTray::setTabDocked(const std::string& tab_name, bool dock)
+{
+ LLSideTrayTab* tab = getTab(tab_name);
+ if (!tab)
+ { // not a docked tab, look through detached tabs
+ for(child_vector_iter_t tab_it = mDetachedTabs.begin(), tab_end_it = mDetachedTabs.end();
+ tab_it != tab_end_it;
+ ++tab_it)
+ {
+ if ((*tab_it)->getName() == tab_name)
+ {
+ tab = *tab_it;
+ break;
+ }
+ }
+
+ }
+
+ if (tab)
+ {
+ bool tab_attached = isTabAttached(tab_name);
+ LLFloater* floater_tab = LLFloaterReg::getInstance("side_bar_tab", tab_name);
+ if (!floater_tab) return;
+
+ if (dock && !tab_attached)
+ {
+ tab->dock(floater_tab);
+ }
+ else if (!dock && tab_attached)
+ {
+ tab->undock(floater_tab);
+ }
+ }
+}
+
+
void LLSideTray::updateSidetrayVisibility()
{
// set visibility of parent container based on collapsed state
diff --git a/indra/newview/llsidetray.h b/indra/newview/llsidetray.h
index 184d78845f..2516b5689f 100644
--- a/indra/newview/llsidetray.h
+++ b/indra/newview/llsidetray.h
@@ -97,6 +97,8 @@ public:
*/
LLPanel* showPanel (const std::string& panel_name, const LLSD& params = LLSD());
+ void hidePanel (const std::string& panel_name);
+
/**
* Toggling Side Tray tab which contains "sub_panel" child of "panel_name" panel.
* If "sub_panel" is not visible Side Tray is opened to display it,
@@ -112,6 +114,8 @@ public:
LLPanel* getActivePanel ();
bool isPanelActive (const std::string& panel_name);
+ void setTabDocked(const std::string& tab_name, bool dock);
+
/*
* get the panel of given type T (don't show it or do anything else with it)
*/
@@ -215,7 +219,7 @@ private:
if (LLSideTray::instanceCreated())
LLSideTray::getInstance()->setEnabled(FALSE);
}
-
+
private:
LLPanel* mButtonsPanel;
typedef std::map<std::string,LLButton*> button_map_t;
diff --git a/indra/newview/llstartup.cpp b/indra/newview/llstartup.cpp
index 0eac7d5e2a..45159de66e 100644
--- a/indra/newview/llstartup.cpp
+++ b/indra/newview/llstartup.cpp
@@ -1,3231 +1,3229 @@
-/**
- * @file llstartup.cpp
- * @brief startup routines.
- *
- * $LicenseInfo:firstyear=2004&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llstartup.h"
-
-#if LL_WINDOWS
-# include <process.h> // _spawnl()
-#else
-# include <sys/stat.h> // mkdir()
-#endif
-
-#include "llviewermedia_streamingaudio.h"
-#include "llaudioengine.h"
-
-#ifdef LL_FMOD
-# include "llaudioengine_fmod.h"
-#endif
-
-#ifdef LL_OPENAL
-#include "llaudioengine_openal.h"
-#endif
-
-#include "llares.h"
-#include "llavatarnamecache.h"
-#include "lllandmark.h"
-#include "llcachename.h"
-#include "lldir.h"
-#include "llerrorcontrol.h"
-#include "llfloaterreg.h"
-#include "llfocusmgr.h"
-#include "llhttpsender.h"
-#include "llimfloater.h"
-#include "lllocationhistory.h"
-#include "llimageworker.h"
-
-#include "llloginflags.h"
-#include "llmd5.h"
-#include "llmemorystream.h"
-#include "llmessageconfig.h"
-#include "llmoveview.h"
-#include "llnearbychat.h"
-#include "llnotifications.h"
-#include "llnotificationsutil.h"
-#include "llteleporthistory.h"
-#include "llregionhandle.h"
-#include "llsd.h"
-#include "llsdserialize.h"
-#include "llsdutil_math.h"
-#include "llsecondlifeurls.h"
-#include "llstring.h"
-#include "lluserrelations.h"
-#include "llversioninfo.h"
-#include "llviewercontrol.h"
-#include "llvfs.h"
-#include "llxorcipher.h" // saved password, MAC address
-#include "llwindow.h"
-#include "imageids.h"
-#include "message.h"
-#include "v3math.h"
-
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llagentpicksinfo.h"
-#include "llagentwearables.h"
-#include "llagentpilot.h"
-#include "llfloateravatarpicker.h"
-#include "llcallbacklist.h"
-#include "llcallingcard.h"
-#include "llconsole.h"
-#include "llcontainerview.h"
-#include "lldebugview.h"
-#include "lldrawable.h"
-#include "lleventnotifier.h"
-#include "llface.h"
-#include "llfeaturemanager.h"
-//#include "llfirstuse.h"
-#include "llfloaterhud.h"
-#include "llfloaterland.h"
-#include "llfloaterpreference.h"
-#include "llfloatertopobjects.h"
-#include "llfloaterworldmap.h"
-#include "llgesturemgr.h"
-#include "llgroupmgr.h"
-#include "llhudeffecttrail.h"
-#include "llhudmanager.h"
-#include "llhttpclient.h"
-#include "llimagebmp.h"
-#include "llinventorybridge.h"
-#include "llinventorymodel.h"
-#include "llinventorymodelbackgroundfetch.h"
-#include "llkeyboard.h"
-#include "llloginhandler.h" // gLoginHandler, SLURL support
-#include "lllogininstance.h" // Host the login module.
-#include "llpanellogin.h"
-#include "llmutelist.h"
-#include "llavatarpropertiesprocessor.h"
-#include "llpanelclassified.h"
-#include "llpanelpick.h"
-#include "llpanelgrouplandmoney.h"
-#include "llpanelgroupnotices.h"
-#include "llpreview.h"
-#include "llpreviewscript.h"
-#include "llproductinforequest.h"
-#include "llsecondlifeurls.h"
-#include "llselectmgr.h"
-#include "llsky.h"
-#include "llsidetray.h"
-#include "llstatview.h"
-#include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance
-#include "llsurface.h"
-#include "lltexturecache.h"
-#include "lltexturefetch.h"
-#include "lltoolmgr.h"
-#include "lltrans.h"
-#include "llui.h"
-#include "llurldispatcher.h"
-#include "llurlentry.h"
-#include "llslurl.h"
-#include "llurlhistory.h"
-#include "llurlwhitelist.h"
-#include "llvieweraudio.h"
-#include "llviewerassetstorage.h"
-#include "llviewercamera.h"
-#include "llviewerdisplay.h"
-#include "llviewergenericmessage.h"
-#include "llviewergesture.h"
-#include "llviewertexturelist.h"
-#include "llviewermedia.h"
-#include "llviewermenu.h"
-#include "llviewermessage.h"
-#include "llviewernetwork.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmedia.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h"
-#include "llviewerstats.h"
-#include "llviewerthrottle.h"
-#include "llviewerwindow.h"
-#include "llvoavatar.h"
-#include "llvoavatarself.h"
-#include "llvoclouds.h"
-#include "llweb.h"
-#include "llworld.h"
-#include "llworldmapmessage.h"
-#include "llxfermanager.h"
-#include "pipeline.h"
-#include "llappviewer.h"
-#include "llfasttimerview.h"
-#include "llfloatermap.h"
-#include "llweb.h"
-#include "llvoiceclient.h"
-#include "llnamelistctrl.h"
-#include "llnamebox.h"
-#include "llnameeditor.h"
-#include "llpostprocess.h"
-#include "llwlparammanager.h"
-#include "llwaterparammanager.h"
-#include "llagentlanguage.h"
-#include "llwearable.h"
-#include "llinventorybridge.h"
-#include "llappearancemgr.h"
-#include "llavatariconctrl.h"
-#include "llvoicechannel.h"
-
-#include "lllogin.h"
-#include "llevents.h"
-#include "llstartuplistener.h"
-
-#if LL_WINDOWS
-#include "lldxhardware.h"
-#endif
-
-//
-// exported globals
-//
-bool gAgentMovementCompleted = false;
-S32 gMaxAgentGroups;
-
-std::string SCREEN_HOME_FILENAME = "screen_home.bmp";
-std::string SCREEN_LAST_FILENAME = "screen_last.bmp";
-
-LLPointer<LLViewerTexture> gStartTexture;
-
-//
-// Imported globals
-//
-extern S32 gStartImageWidth;
-extern S32 gStartImageHeight;
-
-//
-// local globals
-//
-static bool gGotUseCircuitCodeAck = false;
-static std::string sInitialOutfit;
-static std::string sInitialOutfitGender; // "male" or "female"
-static boost::signals2::connection sWearablesLoadedCon;
-
-static bool gUseCircuitCallbackCalled = false;
-
-EStartupState LLStartUp::gStartupState = STATE_FIRST;
-LLSLURL LLStartUp::sStartSLURL;
-
-static LLPointer<LLCredential> gUserCredential;
-static std::string gDisplayName;
-static BOOL gRememberPassword = TRUE;
-
-static U64 gFirstSimHandle = 0;
-static LLHost gFirstSim;
-static std::string gFirstSimSeedCap;
-static LLVector3 gAgentStartLookAt(1.0f, 0.f, 0.f);
-static std::string gAgentStartLocation = "safe";
-static bool mLoginStatePastUI = false;
-
-
-boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
-boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
-
-//
-// local function declaration
-//
-
-void login_show();
-void login_callback(S32 option, void* userdata);
-void show_first_run_dialog();
-bool first_run_dialog_callback(const LLSD& notification, const LLSD& response);
-void set_startup_status(const F32 frac, const std::string& string, const std::string& msg);
-bool login_alert_status(const LLSD& notification, const LLSD& response);
-void login_packet_failed(void**, S32 result);
-void use_circuit_callback(void**, S32 result);
-void register_viewer_callbacks(LLMessageSystem* msg);
-void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32);
-bool callback_choose_gender(const LLSD& notification, const LLSD& response);
-void init_start_screen(S32 location_id);
-void release_start_screen();
-void reset_login();
-LLSD transform_cert_args(LLPointer<LLCertificate> cert);
-void general_cert_done(const LLSD& notification, const LLSD& response);
-void trust_cert_done(const LLSD& notification, const LLSD& response);
-void apply_udp_blacklist(const std::string& csv);
-bool process_login_success_response();
-void transition_back_to_login_panel(const std::string& emsg);
-
-void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group)
-{
- LLNameBox::refreshAll(id, full_name, is_group);
- LLNameEditor::refreshAll(id, full_name, is_group);
-
- // TODO: Actually be intelligent about the refresh.
- // For now, just brute force refresh the dialogs.
- dialog_refresh_all();
-}
-
-//
-// exported functionality
-//
-
-//
-// local classes
-//
-
-namespace
-{
- class LLNullHTTPSender : public LLHTTPSender
- {
- virtual void send(const LLHost& host,
- const std::string& message, const LLSD& body,
- LLHTTPClient::ResponderPtr response) const
- {
- LL_WARNS("AppInit") << " attemped to send " << message << " to " << host
- << " with null sender" << LL_ENDL;
- }
- };
-}
-
-void update_texture_fetch()
-{
- LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
- LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
- LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
- gTextureList.updateImages(0.10f);
-}
-
-// Returns false to skip other idle processing. Should only return
-// true when all initialization done.
-bool idle_startup()
-{
- LLMemType mt1(LLMemType::MTYPE_STARTUP);
-
- const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay");
- static LLTimer timeout;
- static S32 timeout_count = 0;
-
- static LLTimer login_time;
-
- // until this is encapsulated, this little hack for the
- // auth/transform loop will do.
- static F32 progress = 0.10f;
-
- static std::string auth_desc;
- static std::string auth_message;
-
- static LLVector3 initial_sun_direction(1.f, 0.f, 0.f);
- static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server
-
- // last location by default
- static S32 agent_location_id = START_LOCATION_ID_LAST;
- static S32 location_which = START_LOCATION_ID_LAST;
-
- static bool show_connect_box = true;
-
- //static bool stipend_since_login = false;
-
- // HACK: These are things from the main loop that usually aren't done
- // until initialization is complete, but need to be done here for things
- // to work.
- gIdleCallbacks.callFunctions();
- gViewerWindow->updateUI();
- LLMortician::updateClass();
-
- const std::string delims (" ");
- std::string system;
- int begIdx, endIdx;
- std::string osString = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
-
- begIdx = osString.find_first_not_of (delims);
- endIdx = osString.find_first_of (delims, begIdx);
- system = osString.substr (begIdx, endIdx - begIdx);
- system += "Locale";
-
- LLStringUtil::setLocale (LLTrans::getString(system));
-
- if (!gNoRender)
- {
- //note: Removing this line will cause incorrect button size in the login screen. -- bao.
- gTextureList.updateImages(0.01f) ;
- }
-
- if ( STATE_FIRST == LLStartUp::getStartupState() )
- {
- gViewerWindow->showCursor();
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
-
- /////////////////////////////////////////////////
- //
- // Initialize stuff that doesn't need data from simulators
- //
-
- if (LLFeatureManager::getInstance()->isSafe())
- {
- LLNotificationsUtil::add("DisplaySetToSafe");
- }
- else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) &&
- (gSavedSettings.getS32("LastFeatureVersion") != 0))
- {
- LLNotificationsUtil::add("DisplaySetToRecommended");
- }
- else if ((gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass()) &&
- (gSavedSettings.getS32("LastGPUClass") != -1))
- {
- LLNotificationsUtil::add("DisplaySetToRecommended");
- }
- else if (!gViewerWindow->getInitAlert().empty())
- {
- LLNotificationsUtil::add(gViewerWindow->getInitAlert());
- }
-
- gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion());
- gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass());
-
- // load dynamic GPU/feature tables from website (S3)
- LLFeatureManager::getInstance()->fetchHTTPTables();
-
- std::string xml_file = LLUI::locateSkin("xui_version.xml");
- LLXMLNodePtr root;
- bool xml_ok = false;
- if (LLXMLNode::parseFile(xml_file, root, NULL))
- {
- if( (root->hasName("xui_version") ) )
- {
- std::string value = root->getValue();
- F32 version = 0.0f;
- LLStringUtil::convertToF32(value, version);
- if (version >= 1.0f)
- {
- xml_ok = true;
- }
- }
- }
- if (!xml_ok)
- {
- // If XML is bad, there's a good possibility that notifications.xml is ALSO bad.
- // If that's so, then we'll get a fatal error on attempting to load it,
- // which will display a nontranslatable error message that says so.
- // Otherwise, we'll display a reasonable error message that IS translatable.
- LLAppViewer::instance()->earlyExit("BadInstallation");
- }
- //
- // Statistics stuff
- //
-
- // Load autopilot and stats stuff
- gAgentPilot.load(gSavedSettings.getString("StatsPilotFile"));
-
- //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps"));
-
- // Load the throttle settings
- gViewerThrottle.load();
-
- if (ll_init_ares() == NULL || !gAres->isInitialized())
- {
- std::string diagnostic = "Could not start address resolution system";
- LL_WARNS("AppInit") << diagnostic << LL_ENDL;
- LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic));
- }
-
- //
- // Initialize messaging system
- //
- LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL;
-
- std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg");
-
- LLFILE* found_template = NULL;
- found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */
-
- #if LL_WINDOWS
- // On the windows dev builds, unpackaged, the message_template.msg
- // file will be located in:
- // build-vc**/newview/<config>/app_settings
- if (!found_template)
- {
- message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg");
- found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */
- }
- #elif LL_DARWIN
- // On Mac dev builds, message_template.msg lives in:
- // indra/build-*/newview/<config>/Second Life/Contents/Resources/app_settings
- if (!found_template)
- {
- message_template_path =
- gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE,
- "../Resources/app_settings",
- "message_template.msg");
- found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */
- }
- #endif
-
- if (found_template)
- {
- fclose(found_template);
-
- U32 port = gSavedSettings.getU32("UserConnectionPort");
-
- if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port)
- (gSavedSettings.getBOOL("ConnectionPortEnabled")))
- {
- port = gSavedSettings.getU32("ConnectionPort");
- }
-
- LLHTTPSender::setDefaultSender(new LLNullHTTPSender());
-
- // TODO parameterize
- const F32 circuit_heartbeat_interval = 5;
- const F32 circuit_timeout = 100;
-
- const LLUseCircuitCodeResponder* responder = NULL;
- bool failure_is_fatal = true;
-
- if(!start_messaging_system(
- message_template_path,
- port,
- LLVersionInfo::getMajor(),
- LLVersionInfo::getMinor(),
- LLVersionInfo::getPatch(),
- FALSE,
- std::string(),
- responder,
- failure_is_fatal,
- circuit_heartbeat_interval,
- circuit_timeout))
- {
- std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode());
- LL_WARNS("AppInit") << diagnostic << LL_ENDL;
- LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic));
- }
-
- #if LL_WINDOWS
- // On the windows dev builds, unpackaged, the message.xml file will
- // be located in indra/build-vc**/newview/<config>/app_settings.
- std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml");
-
- if (!LLFile::isfile(message_path.c_str()))
- {
- LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", ""));
- }
- else
- {
- LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- }
- #else
- LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
- #endif
-
- }
- else
- {
- LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path));
- }
-
- if(gMessageSystem && gMessageSystem->isOK())
- {
- // Initialize all of the callbacks in case of bad message
- // system data
- LLMessageSystem* msg = gMessageSystem;
- msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE,
- invalid_message_callback,
- NULL);
- msg->setExceptionFunc(MX_PACKET_TOO_SHORT,
- invalid_message_callback,
- NULL);
-
- // running off end of a packet is now valid in the case
- // when a reader has a newer message template than
- // the sender
- /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET,
- invalid_message_callback,
- NULL);*/
- msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE,
- invalid_message_callback,
- NULL);
-
- if (gSavedSettings.getBOOL("LogMessages"))
- {
- LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL;
- msg->startLogging();
- }
-
- // start the xfer system. by default, choke the downloads
- // a lot...
- const S32 VIEWER_MAX_XFER = 3;
- start_xfer_manager(gVFS);
- gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER);
- F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle");
- if (xfer_throttle_bps > 1.f)
- {
- gXferManager->setUseAckThrottling(TRUE);
- gXferManager->setAckThrottleBPS(xfer_throttle_bps);
- }
- gAssetStorage = new LLViewerAssetStorage(msg, gXferManager, gVFS, gStaticVFS);
-
-
- F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage");
- msg->mPacketRing.setDropPercentage(dropPercent);
-
- F32 inBandwidth = gSavedSettings.getF32("InBandwidth");
- F32 outBandwidth = gSavedSettings.getF32("OutBandwidth");
- if (inBandwidth != 0.f)
- {
- LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL;
- msg->mPacketRing.setUseInThrottle(TRUE);
- msg->mPacketRing.setInBandwidth(inBandwidth);
- }
- if (outBandwidth != 0.f)
- {
- LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL;
- msg->mPacketRing.setUseOutThrottle(TRUE);
- msg->mPacketRing.setOutBandwidth(outBandwidth);
- }
- }
-
- LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL;
-
- //-------------------------------------------------
- // Init audio, which may be needed for prefs dialog
- // or audio cues in connection UI.
- //-------------------------------------------------
-
- if (FALSE == gSavedSettings.getBOOL("NoAudio"))
- {
- gAudiop = NULL;
-
-#ifdef LL_OPENAL
- if (!gAudiop
-#if !LL_WINDOWS
- && NULL == getenv("LL_BAD_OPENAL_DRIVER")
-#endif // !LL_WINDOWS
- )
- {
- gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL();
- }
-#endif
-
-#ifdef LL_FMOD
- if (!gAudiop
-#if !LL_WINDOWS
- && NULL == getenv("LL_BAD_FMOD_DRIVER")
-#endif // !LL_WINDOWS
- )
- {
- gAudiop = (LLAudioEngine *) new LLAudioEngine_FMOD();
- }
-#endif
-
- if (gAudiop)
- {
-#if LL_WINDOWS
- // FMOD on Windows needs the window handle to stop playing audio
- // when window is minimized. JC
- void* window_handle = (HWND)gViewerWindow->getPlatformWindow();
-#else
- void* window_handle = NULL;
-#endif
- bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle);
- if(init)
- {
- gAudiop->setMuted(TRUE);
- }
- else
- {
- LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL;
- delete gAudiop;
- gAudiop = NULL;
- }
-
- if (gAudiop)
- {
- // if the audio engine hasn't set up its own preferred handler for streaming audio then set up the generic streaming audio implementation which uses media plugins
- if (NULL == gAudiop->getStreamingAudioImpl())
- {
- LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL;
- gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins());
- }
- }
- }
- }
-
- LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL;
-
- if (LLTimer::knownBadTimer())
- {
- LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL;
- }
-
- //
- // Log on to system
- //
- if (gUserCredential.isNull())
- {
- gUserCredential = gLoginHandler.initializeLoginInfo();
- }
- if (gUserCredential.isNull())
- {
- show_connect_box = TRUE;
- }
- else if (gSavedSettings.getBOOL("AutoLogin"))
- {
- gRememberPassword = TRUE;
- gSavedSettings.setBOOL("RememberPassword", TRUE);
- show_connect_box = false;
- }
- else
- {
- gRememberPassword = gSavedSettings.getBOOL("RememberPassword");
- show_connect_box = TRUE;
- }
- // Go to the next startup state
- LLStartUp::setStartupState( STATE_BROWSER_INIT );
- return FALSE;
- }
-
-
- if (STATE_BROWSER_INIT == LLStartUp::getStartupState())
- {
- LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL;
- std::string msg = LLTrans::getString("LoginInitializingBrowser");
- set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str());
- display_startup();
- // LLViewerMedia::initBrowser();
- LLStartUp::setStartupState( STATE_LOGIN_SHOW );
- return FALSE;
- }
-
-
- if (STATE_LOGIN_SHOW == LLStartUp::getStartupState())
- {
- LL_DEBUGS("AppInit") << "Initializing Window" << LL_ENDL;
-
- // if we've gone backwards in the login state machine, to this state where we show the UI
- // AND the debug setting to exit in this case is true, then go ahead and bail quickly
- if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") )
- {
- // no requirement for notification here - just exit
- LLAppViewer::instance()->earlyExitNoNotify();
- }
-
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
-
- timeout_count = 0;
-
- if (show_connect_box)
- {
- // Load all the name information out of the login view
- // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't
- // show the login view until login_show() is called below.
- if (gUserCredential.isNull())
- {
- gUserCredential = gLoginHandler.initializeLoginInfo();
- }
- if (gNoRender)
- {
- LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL;
- }
- // Make sure the process dialog doesn't hide things
- gViewerWindow->setShowProgress(FALSE);
-
- initialize_edit_menu();
-
- // Show the login dialog
- login_show();
- // connect dialog is already shown, so fill in the names
- if (gUserCredential.notNull())
- {
- LLPanelLogin::setFields( gUserCredential, gRememberPassword);
- }
- LLPanelLogin::giveFocus();
-
- gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);
-
- LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input
- }
- else
- {
- // skip directly to message template verification
- LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
- }
-
- // *NOTE: This is where LLViewerParcelMgr::getInstance() used to get allocated before becoming LLViewerParcelMgr::getInstance().
-
- // *NOTE: This is where gHUDManager used to bet allocated before becoming LLHUDManager::getInstance().
-
- // *NOTE: This is where gMuteList used to get allocated before becoming LLMuteList::getInstance().
-
- // Login screen needs menus for preferences, but we can enter
- // this startup phase more than once.
- if (gLoginMenuBarView == NULL)
- {
- init_menus();
- }
-
- gViewerWindow->setNormalControlsVisible( FALSE );
- gLoginMenuBarView->setVisible( TRUE );
- gLoginMenuBarView->setEnabled( TRUE );
-
- // Hide the splash screen
- LLSplashScreen::hide();
-
- // Push our window frontmost
- gViewerWindow->getWindow()->show();
- display_startup();
-
- // DEV-16927. The following code removes errant keystrokes that happen while the window is being
- // first made visible.
-#ifdef _WIN32
- MSG msg;
- while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) );
-#endif
- timeout.reset();
- return FALSE;
- }
-
- if (STATE_LOGIN_WAIT == LLStartUp::getStartupState())
- {
- // when we get to this state, we've already been past the login UI
- // (possiblely automatically) - flag this so we can test in the
- // STATE_LOGIN_SHOW state if we've gone backwards
- mLoginStatePastUI = true;
-
- // Don't do anything. Wait for the login view to call the login_callback,
- // which will push us to the next state.
-
- // Sleep so we don't spin the CPU
- ms_sleep(1);
- return FALSE;
- }
-
- if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState())
- {
- //reset the values that could have come in from a slurl
- // DEV-42215: Make sure they're not empty -- gUserCredential
- // might already have been set from gSavedSettings, and it's too bad
- // to overwrite valid values with empty strings.
-
- if (show_connect_box)
- {
- // TODO if not use viewer auth
- // Load all the name information out of the login view
- LLPanelLogin::getFields(gUserCredential, gRememberPassword);
- // end TODO
-
- // HACK: Try to make not jump on login
- gKeyboard->resetKeys();
- }
-
- // when we get to this state, we've already been past the login UI
- // (possiblely automatically) - flag this so we can test in the
- // STATE_LOGIN_SHOW state if we've gone backwards
- mLoginStatePastUI = true;
-
- // save the credentials
- std::string userid = "unknown";
- if(gUserCredential.notNull())
- {
- userid = gUserCredential->userID();
- gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword);
- }
- gSavedSettings.setBOOL("RememberPassword", gRememberPassword);
- LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL;
- gDebugInfo["LoginName"] = userid;
-
- // create necessary directories
- // *FIX: these mkdir's should error check
- gDirUtilp->setLindenUserDir(userid);
- LLFile::mkdir(gDirUtilp->getLindenUserDir());
-
- // Set PerAccountSettingsFile to the default value.
- std::string per_account_settings_file = LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount");
- gSavedSettings.setString("PerAccountSettingsFile",
- gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,
- LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")));
-
- // Note: can't store warnings files per account because some come up before login
-
- // Overwrite default user settings with user settings
- LLAppViewer::instance()->loadSettingsFromDirectory("Account");
-
- // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation
- // and startup time is close enough if we don't have a real value.
- if (gSavedPerAccountSettings.getU32("LastLogoff") == 0)
- {
- gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
- }
-
- //Default the path if one isn't set.
- // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was
- // provided in pre 2.0 viewer. See EXT-6661
- if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty())
- {
- gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir());
- gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir());
- }
- else
- {
- gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
- }
- gDirUtilp->setPerAccountChatLogsDir(userid);
-
- LLFile::mkdir(gDirUtilp->getChatLogsDir());
- LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir());
-
-
- //good a place as any to create user windlight directories
- std::string user_windlight_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", ""));
- LLFile::mkdir(user_windlight_path_name.c_str());
-
- std::string user_windlight_skies_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", ""));
- LLFile::mkdir(user_windlight_skies_path_name.c_str());
-
- std::string user_windlight_water_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", ""));
- LLFile::mkdir(user_windlight_water_path_name.c_str());
-
- std::string user_windlight_days_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/days", ""));
- LLFile::mkdir(user_windlight_days_path_name.c_str());
-
-
- if (show_connect_box)
- {
- LLSLURL slurl;
- LLPanelLogin::closePanel();
- }
-
-
- // Load URL History File
- LLURLHistory::loadFile("url_history.xml");
- // Load location history
- LLLocationHistory::getInstance()->load();
-
- // Load Avatars icons cache
- LLAvatarIconIDCache::getInstance()->load();
-
- // Load media plugin cookies
- LLViewerMedia::loadCookieFile();
-
- //-------------------------------------------------
- // Handle startup progress screen
- //-------------------------------------------------
-
- // on startup the user can request to go to their home,
- // their last location, or some URL "-url //sim/x/y[/z]"
- // All accounts have both a home and a last location, and we don't support
- // more locations than that. Choose the appropriate one. JC
- switch (LLStartUp::getStartSLURL().getType())
- {
- case LLSLURL::LOCATION:
- agent_location_id = START_LOCATION_ID_URL;
- location_which = START_LOCATION_ID_LAST;
- break;
- case LLSLURL::LAST_LOCATION:
- agent_location_id = START_LOCATION_ID_LAST;
- location_which = START_LOCATION_ID_LAST;
- break;
- default:
- agent_location_id = START_LOCATION_ID_HOME;
- location_which = START_LOCATION_ID_HOME;
- break;
- }
-
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
-
- if (!gNoRender)
- {
- init_start_screen(agent_location_id);
- }
-
- // Display the startup progress bar.
- gViewerWindow->setShowProgress(TRUE);
- gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit"));
-
- // Poke the VFS, which could potentially block for a while if
- // Windows XP is acting up
- set_startup_status(0.07f, LLTrans::getString("LoginVerifyingCache"), LLStringUtil::null);
- display_startup();
-
- gVFS->pokeFiles();
-
- LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT );
-
- return FALSE;
- }
-
- if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState())
- {
- gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel();
-
- // Update progress status and the display loop.
- auth_desc = LLTrans::getString("LoginInProgress");
- set_startup_status(progress, auth_desc, auth_message);
- progress += 0.02f;
- display_startup();
-
- // Setting initial values...
- LLLoginInstance* login = LLLoginInstance::getInstance();
- login->setNotificationsInterface(LLNotifications::getInstance());
- if(gNoRender)
- {
- // HACK, skip optional updates if you're running drones
- login->setSkipOptionalUpdate(true);
- }
-
- login->setSerialNumber(LLAppViewer::instance()->getSerialNumber());
- login->setLastExecEvent(gLastExecEvent);
- login->setUpdaterLauncher(boost::bind(&LLAppViewer::launchUpdater, LLAppViewer::instance()));
-
- // This call to LLLoginInstance::connect() starts the
- // authentication process.
- login->connect(gUserCredential);
-
- LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK );
- return FALSE;
- }
-
- if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState())
- {
- // If we get here we have gotten past the potential stall
- // in curl, so take "may appear frozen" out of progress bar. JC
- auth_desc = LLTrans::getString("LoginInProgressNoFrozen");
- set_startup_status(progress, auth_desc, auth_message);
-
- LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE );
- return FALSE;
- }
-
- if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState())
- {
- std::ostringstream emsg;
- emsg << LLTrans::getString("LoginFailed") << "\n";
- if(LLLoginInstance::getInstance()->authFailure())
- {
- LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): "
- << LLLoginInstance::getInstance()->getResponse() << LL_ENDL;
- LLSD response = LLLoginInstance::getInstance()->getResponse();
- // Still have error conditions that may need some
- // sort of handling.
- std::string reason_response = response["reason"];
- std::string message_response = response["message"];
-
- if(!message_response.empty())
- {
- // XUI: fix translation for strings returned during login
- // We need a generic table for translations
- std::string big_reason = LLAgent::sTeleportErrorMessages[ message_response ];
- if ( big_reason.size() == 0 )
- {
- emsg << message_response;
- }
- else
- {
- emsg << big_reason;
- }
- }
-
- if(reason_response == "key")
- {
- // Couldn't login because user/password is wrong
- // Clear the credential
- gUserCredential->clearAuthenticator();
- }
-
- if(reason_response == "update"
- || reason_response == "optional")
- {
- // In the case of a needed update, quit.
- // Its either downloading or declined.
- // If optional was skipped this case shouldn't
- // be reached.
- LLLoginInstance::getInstance()->disconnect();
- LLAppViewer::instance()->forceQuit();
- }
- else
- {
- if (reason_response != "tos")
- {
- // Don't pop up a notification in the TOS case because
- // LLFloaterTOS::onCancel() already scolded the user.
- std::string error_code;
- if(response.has("errorcode"))
- {
- error_code = response["errorcode"].asString();
- }
- if ((reason_response == "CURLError") &&
- (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") &&
- response.has("certificate"))
- {
- // This was a certificate error, so grab the certificate
- // and throw up the appropriate dialog.
- LLPointer<LLCertificate> certificate = gSecAPIHandler->getCertificate(response["certificate"]);
- if(certificate)
- {
- LLSD args = transform_cert_args(certificate);
-
- if(error_code == "SSL_CACERT")
- {
- // if we are handling an untrusted CA, throw up the dialog
- // with the 'trust this CA' button.
- LLNotificationsUtil::add("TrustCertificateError", args, response,
- trust_cert_done);
-
- show_connect_box = true;
- }
- else
- {
- // the certificate exception returns a unique string for each type of exception.
- // we grab this string via the LLUserAuth object, and use that to grab the localized
- // string.
- args["REASON"] = LLTrans::getString(message_response);
-
- LLNotificationsUtil::add("GeneralCertificateError", args, response,
- general_cert_done);
-
- reset_login();
- gSavedSettings.setBOOL("AutoLogin", FALSE);
- show_connect_box = true;
-
- }
-
- }
- }
- else
- {
- // This wasn't a certificate error, so throw up the normal
- // notificatioin message.
- LLSD args;
- args["ERROR_MESSAGE"] = emsg.str();
- LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
- LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
- }
- }
- //setup map of datetime strings to codes and slt & local time offset from utc
- // *TODO: Does this need to be here?
- LLStringOps::setupDatetimeInfo (false);
- transition_back_to_login_panel(emsg.str());
- show_connect_box = true;
- }
- }
- else if(LLLoginInstance::getInstance()->authSuccess())
- {
- if(process_login_success_response())
- {
- // Pass the user information to the voice chat server interface.
- LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID);
- // create the default proximal channel
- LLVoiceChannel::initClass();
- LLGridManager::getInstance()->setFavorite();
- LLStartUp::setStartupState( STATE_WORLD_INIT);
- }
- else
- {
- LLSD args;
- args["ERROR_MESSAGE"] = emsg.str();
- LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
- LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
- transition_back_to_login_panel(emsg.str());
- show_connect_box = true;
- return FALSE;
- }
- }
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // World Init
- //---------------------------------------------------------------------
- if (STATE_WORLD_INIT == LLStartUp::getStartupState())
- {
- set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD);
- display_startup();
- // We should have an agent id by this point.
- llassert(!(gAgentID == LLUUID::null));
-
- // Finish agent initialization. (Requires gSavedSettings, builds camera)
- gAgent.init();
- gAgentCamera.init();
- set_underclothes_menu_options();
-
- // Since we connected, save off the settings so the user doesn't have to
- // type the name/password again if we crash.
- gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);
- LLUIColorTable::instance().saveUserSettings();
-
- //
- // Initialize classes w/graphics stuff.
- //
- gTextureList.doPrefetchImages();
- LLSurface::initClasses();
-
- LLFace::initClass();
-
- LLDrawable::initClass();
-
- // init the shader managers
- LLPostProcess::initClass();
- LLWLParamManager::initClass();
- LLWaterParamManager::initClass();
-
- LLViewerObject::initVOClasses();
-
- // Initialize all our tools. Must be done after saved settings loaded.
- // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton.
- LLToolMgr::getInstance()->initTools();
-
- // Pre-load floaters, like the world map, that are slow to spawn
- // due to XML complexity.
- gViewerWindow->initWorldUI();
-
- display_startup();
-
- // This is where we used to initialize gWorldp. Original comment said:
- // World initialization must be done after above window init
-
- // User might have overridden far clip
- LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance);
-
- // Before we create the first region, we need to set the agent's mOriginGlobal
- // This is necessary because creating objects before this is set will result in a
- // bad mPositionAgent cache.
-
- gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle));
-
- LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim);
-
- LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle);
- LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL;
-
- regionp->setSeedCapability(gFirstSimSeedCap);
- LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL;
-
- // Set agent's initial region to be the one we just created.
- gAgent.setRegion(regionp);
-
- // Set agent's initial position, which will be read by LLVOAvatar when the avatar
- // object is created. I think this must be done after setting the region. JC
- gAgent.setPositionAgent(agent_start_position_region);
-
- display_startup();
- LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT );
-
- return FALSE;
- }
-
-
- //---------------------------------------------------------------------
- // Load QuickTime/GStreamer and other multimedia engines, can be slow.
- // Do it while we're waiting on the network for our seed capability. JC
- //---------------------------------------------------------------------
- if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState())
- {
- LLStartUp::multimediaInit();
- LLStartUp::setStartupState( STATE_FONT_INIT );
- return FALSE;
- }
-
- // Loading fonts takes several seconds
- if (STATE_FONT_INIT == LLStartUp::getStartupState())
- {
- LLStartUp::fontInit();
- LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT );
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // Wait for Seed Cap Grant
- //---------------------------------------------------------------------
- if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
- {
- return FALSE;
- }
-
-
- //---------------------------------------------------------------------
- // Seed Capability Granted
- // no newMessage calls should happen before this point
- //---------------------------------------------------------------------
- if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState())
- {
- update_texture_fetch();
-
- if ( gViewerWindow != NULL)
- { // This isn't the first logon attempt, so show the UI
- gViewerWindow->setNormalControlsVisible( TRUE );
- }
- gLoginMenuBarView->setVisible( FALSE );
- gLoginMenuBarView->setEnabled( FALSE );
-
- if (!gNoRender)
- {
- // direct logging to the debug console's line buffer
- LLError::logToFixedBuffer(gDebugView->mDebugConsolep);
-
- // set initial visibility of debug console
- gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));
- }
-
- //
- // Set message handlers
- //
- LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL;
-
- // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted
- register_viewer_callbacks(gMessageSystem);
-
- // Debugging info parameters
- gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms
-
- #ifndef LL_RELEASE_FOR_DOWNLOAD
- gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg
- gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode
- #endif
-
- gXferManager->registerCallbacks(gMessageSystem);
-
- LLStartUp::initNameCache();
-
- // update the voice settings *after* gCacheName initialization
- // so that we can construct voice UI that relies on the name cache
- LLVoiceClient::getInstance()->updateSettings();
-
- //gCacheName is required for nearby chat history loading
- //so I just moved nearby history loading a few states further
- if (!gNoRender && gSavedPerAccountSettings.getBOOL("LogShowHistory"))
- {
- LLNearbyChat* nearby_chat = LLNearbyChat::getInstance();
- if (nearby_chat) nearby_chat->loadHistory();
- }
-
- // *Note: this is where gWorldMap used to be initialized.
-
- // register null callbacks for audio until the audio system is initialized
- gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL);
- gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL);
-
- //reset statistics
- LLViewerStats::getInstance()->resetStats();
-
- display_startup();
- //
- // Set up region and surface defaults
- //
-
-
- // Sets up the parameters for the first simulator
-
- LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL;
- gFrameTime = totalTime();
- F32 last_time = gFrameTimeSeconds;
- gFrameTimeSeconds = (S64)(gFrameTime - gStartTime)/SEC_TO_MICROSEC;
-
- gFrameIntervalSeconds = gFrameTimeSeconds - last_time;
- if (gFrameIntervalSeconds < 0.f)
- {
- gFrameIntervalSeconds = 0.f;
- }
-
- // Make sure agent knows correct aspect ratio
- // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below
- LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw());
- LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio());
- // Initialize FOV
- LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle"));
-
- // Move agent to starting location. The position handed to us by
- // the space server is in global coordinates, but the agent frame
- // is in region local coordinates. Therefore, we need to adjust
- // the coordinates handed to us to fit in the local region.
-
- gAgent.setPositionAgent(agent_start_position_region);
- gAgent.resetAxes(gAgentStartLookAt);
- gAgentCamera.stopCameraAnimation();
- gAgentCamera.resetCamera();
-
- // Initialize global class data needed for surfaces (i.e. textures)
- if (!gNoRender)
- {
- LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
- // Initialize all of the viewer object classes for the first time (doing things like texture fetches.
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- gSky.init(initial_sun_direction);
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- }
-
- LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL;
- // For all images pre-loaded into viewer cache, decode them.
- // Need to do this AFTER we init the sky
- const S32 DECODE_TIME_SEC = 2;
- for (int i = 0; i < DECODE_TIME_SEC; i++)
- {
- F32 frac = (F32)i / (F32)DECODE_TIME_SEC;
- set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD);
- display_startup();
- gTextureList.decodeAllImages(1.f);
- }
- LLStartUp::setStartupState( STATE_WORLD_WAIT );
-
- // JC - Do this as late as possible to increase likelihood Purify
- // will run.
- LLMessageSystem* msg = gMessageSystem;
- if (!msg->mOurCircuitCode)
- {
- LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL;
- }
-
- gUseCircuitCallbackCalled = false;
-
- msg->enableCircuit(gFirstSim, TRUE);
- // now, use the circuit info to tell simulator about us!
- LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL;
- msg->newMessageFast(_PREHASH_UseCircuitCode);
- msg->nextBlockFast(_PREHASH_CircuitCode);
- msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode);
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
- msg->sendReliable(
- gFirstSim,
- gSavedSettings.getS32("UseCircuitCodeMaxRetries"),
- FALSE,
- gSavedSettings.getF32("UseCircuitCodeTimeout"),
- use_circuit_callback,
- NULL);
-
- timeout.reset();
-
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // Agent Send
- //---------------------------------------------------------------------
- if(STATE_WORLD_WAIT == LLStartUp::getStartupState())
- {
- LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL;
- set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD);
- if(gGotUseCircuitCodeAck)
- {
- LLStartUp::setStartupState( STATE_AGENT_SEND );
- }
- LLMessageSystem* msg = gMessageSystem;
- while (msg->checkAllMessages(gFrameCount, gServicePump))
- {
- }
- msg->processAcks();
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // Agent Send
- //---------------------------------------------------------------------
- if (STATE_AGENT_SEND == LLStartUp::getStartupState())
- {
- LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL;
- set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD);
- // register with the message system so it knows we're
- // expecting this message
- LLMessageSystem* msg = gMessageSystem;
- msg->setHandlerFuncFast(
- _PREHASH_AgentMovementComplete,
- process_agent_movement_complete);
- LLViewerRegion* regionp = gAgent.getRegion();
- if(regionp)
- {
- send_complete_agent_movement(regionp->getHost());
- gAssetStorage->setUpstream(regionp->getHost());
- gCacheName->setUpstream(regionp->getHost());
- msg->newMessageFast(_PREHASH_EconomyDataRequest);
- gAgent.sendReliableMessage();
- }
-
- // Create login effect
- // But not on first login, because you can't see your avatar then
- if (!gAgent.isFirstLogin())
- {
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
- effectp->setPositionGlobal(gAgent.getPositionGlobal());
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- LLHUDManager::getInstance()->sendEffects();
- }
-
- LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT
-
- timeout.reset();
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // Agent Wait
- //---------------------------------------------------------------------
- if (STATE_AGENT_WAIT == LLStartUp::getStartupState())
- {
- LLMessageSystem* msg = gMessageSystem;
- while (msg->checkAllMessages(gFrameCount, gServicePump))
- {
- if (gAgentMovementCompleted)
- {
- // Sometimes we have more than one message in the
- // queue. break out of this loop and continue
- // processing. If we don't, then this could skip one
- // or more login steps.
- break;
- }
- else
- {
- LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got "
- << msg->getMessageName() << LL_ENDL;
- }
- }
- msg->processAcks();
-
- if (gAgentMovementCompleted)
- {
- LLStartUp::setStartupState( STATE_INVENTORY_SEND );
- }
-
- return FALSE;
- }
-
- //---------------------------------------------------------------------
- // Inventory Send
- //---------------------------------------------------------------------
- if (STATE_INVENTORY_SEND == LLStartUp::getStartupState())
- {
- // Inform simulator of our language preference
- LLAgentLanguage::update();
-
- // unpack thin inventory
- LLSD response = LLLoginInstance::getInstance()->getResponse();
- //bool dump_buffer = false;
-
- LLSD inv_lib_root = response["inventory-lib-root"];
- if(inv_lib_root.isDefined())
- {
- // should only be one
- LLSD id = inv_lib_root[0]["folder_id"];
- if(id.isDefined())
- {
- gInventory.setLibraryRootFolderID(id.asUUID());
- }
- }
-
- LLSD inv_lib_owner = response["inventory-lib-owner"];
- if(inv_lib_owner.isDefined())
- {
- // should only be one
- LLSD id = inv_lib_owner[0]["agent_id"];
- if(id.isDefined())
- {
- gInventory.setLibraryOwnerID( LLUUID(id.asUUID()));
- }
- }
-
- LLSD inv_skel_lib = response["inventory-skel-lib"];
- if(inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull())
- {
- if(!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID()))
- {
- LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL;
- }
- }
-
- LLSD inv_skeleton = response["inventory-skeleton"];
- if(inv_skeleton.isDefined())
- {
- if(!gInventory.loadSkeleton(inv_skeleton, gAgent.getID()))
- {
- LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL;
- }
- }
-
- LLSD buddy_list = response["buddy-list"];
- if(buddy_list.isDefined())
- {
- LLAvatarTracker::buddy_map_t list;
- LLUUID agent_id;
- S32 has_rights = 0, given_rights = 0;
- for(LLSD::array_const_iterator it = buddy_list.beginArray(),
- end = buddy_list.endArray(); it != end; ++it)
- {
- LLSD buddy_id = (*it)["buddy_id"];
- if(buddy_id.isDefined())
- {
- agent_id = buddy_id.asUUID();
- }
-
- LLSD buddy_rights_has = (*it)["buddy_rights_has"];
- if(buddy_rights_has.isDefined())
- {
- has_rights = buddy_rights_has.asInteger();
- }
-
- LLSD buddy_rights_given = (*it)["buddy_rights_given"];
- if(buddy_rights_given.isDefined())
- {
- given_rights = buddy_rights_given.asInteger();
- }
-
- list[agent_id] = new LLRelationship(given_rights, has_rights, false);
- }
- LLAvatarTracker::instance().addBuddyList(list);
- }
-
- bool show_hud = false;
- LLSD tutorial_setting = response["tutorial_setting"];
- if(tutorial_setting.isDefined())
- {
- for(LLSD::array_const_iterator it = tutorial_setting.beginArray(),
- end = tutorial_setting.endArray(); it != end; ++it)
- {
- LLSD tutorial_url = (*it)["tutorial_url"];
- if(tutorial_url.isDefined())
- {
- // Tutorial floater will append language code
- gSavedSettings.setString("TutorialURL", tutorial_url.asString());
- }
-
- // For Viewer 2.0 we are not using the web-based tutorial
- // If we reverse that decision, put this code back and use
- // login.cgi to send a different URL with content that matches
- // the Viewer 2.0 UI.
- //LLSD use_tutorial = (*it)["use_tutorial"];
- //if(use_tutorial.asString() == "true")
- //{
- // show_hud = true;
- //}
- }
- }
- // Either we want to show tutorial because this is the first login
- // to a Linden Help Island or the user quit with the tutorial
- // visible. JC
- if (show_hud || gSavedSettings.getBOOL("ShowTutorial"))
- {
- LLFloaterReg::showInstance("hud", LLSD(), FALSE);
- }
-
- LLSD event_notifications = response["event_notifications"];
- if(event_notifications.isDefined())
- {
- gEventNotifier.load(event_notifications);
- }
-
- LLSD classified_categories = response["classified_categories"];
- if(classified_categories.isDefined())
- {
- LLClassifiedInfo::loadCategories(classified_categories);
- }
-
- // This method MUST be called before gInventory.findCategoryUUIDForType because of
- // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap.
- gInventory.buildParentChildMap();
-
- //all categories loaded. lets create "My Favorites" category
- gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true);
-
- // set up callbacks
- llinfos << "Registering Callbacks" << llendl;
- LLMessageSystem* msg = gMessageSystem;
- llinfos << " Inventory" << llendl;
- LLInventoryModel::registerCallbacks(msg);
- llinfos << " AvatarTracker" << llendl;
- LLAvatarTracker::instance().registerCallbacks(msg);
- llinfos << " Landmark" << llendl;
- LLLandmark::registerCallbacks(msg);
-
- // request mute list
- llinfos << "Requesting Mute List" << llendl;
- LLMuteList::getInstance()->requestFromServer(gAgent.getID());
-
- // Get L$ and ownership credit information
- llinfos << "Requesting Money Balance" << llendl;
- LLStatusBar::sendMoneyBalanceRequest();
-
- // request all group information
- llinfos << "Requesting Agent Data" << llendl;
- gAgent.sendAgentDataUpdateRequest();
-
- // Create the inventory views
- llinfos << "Creating Inventory Views" << llendl;
- LLFloaterReg::getInstance("inventory");
-
- LLStartUp::setStartupState( STATE_MISC );
- return FALSE;
- }
-
-
- //---------------------------------------------------------------------
- // Misc
- //---------------------------------------------------------------------
- if (STATE_MISC == LLStartUp::getStartupState())
- {
- // We have a region, and just did a big inventory download.
- // We can estimate the user's connection speed, and set their
- // max bandwidth accordingly. JC
- if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
- {
- // This is actually a pessimistic computation, because TCP may not have enough
- // time to ramp up on the (small) default inventory file to truly measure max
- // bandwidth. JC
- F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS();
- const F32 FAST_RATE_BPS = 600.f * 1024.f;
- const F32 FASTER_RATE_BPS = 750.f * 1024.f;
- F32 max_bandwidth = gViewerThrottle.getMaxBandwidth();
- if (rate_bps > FASTER_RATE_BPS
- && rate_bps > max_bandwidth)
- {
- LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to "
- << FASTER_RATE_BPS/1024.f
- << " kbps" << LL_ENDL;
- gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f);
- }
- else if (rate_bps > FAST_RATE_BPS
- && rate_bps > max_bandwidth)
- {
- LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to "
- << FAST_RATE_BPS/1024.f
- << " kbps" << LL_ENDL;
- gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f);
- }
-
- // Set the show start location to true, now that the user has logged
- // on with this install.
- gSavedSettings.setBOOL("ShowStartLocation", TRUE);
-
- LLSideTray::getInstance()->showPanel("panel_home", LLSD());
-
- }
-
- // We're successfully logged in.
- gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE);
-
- LLFloaterReg::showInitialVisibleInstances();
-
- // based on the comments, we've successfully logged in so we can delete the 'forced'
- // URL that the updater set in settings.ini (in a mostly paranoid fashion)
- std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" );
- if ( nextLoginLocation.length() )
- {
- // clear it
- gSavedSettings.setString( "NextLoginLocation", "" );
-
- // and make sure it's saved
- gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE );
- LLUIColorTable::instance().saveUserSettings();
- };
-
- if (!gNoRender)
- {
- // JC: Initializing audio requests many sounds for download.
- init_audio();
-
- // JC: Initialize "active" gestures. This may also trigger
- // many gesture downloads, if this is the user's first
- // time on this machine or -purge has been run.
- LLSD gesture_options
- = LLLoginInstance::getInstance()->getResponse("gestures");
- if (gesture_options.isDefined())
- {
- LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size()
- << LL_ENDL;
- uuid_vec_t item_ids;
- for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(),
- end = gesture_options.endArray(); resp_it != end; ++resp_it)
- {
- // If the id is not specifed in the LLSD,
- // the LLSD operator[]() will return a null LLUUID.
- LLUUID item_id = (*resp_it)["item_id"];
- LLUUID asset_id = (*resp_it)["asset_id"];
-
- if (item_id.notNull() && asset_id.notNull())
- {
- // Could schedule and delay these for later.
- const BOOL no_inform_server = FALSE;
- const BOOL no_deactivate_similar = FALSE;
- LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id,
- no_inform_server,
- no_deactivate_similar);
- // We need to fetch the inventory items for these gestures
- // so we have the names to populate the UI.
- item_ids.push_back(item_id);
- }
- }
- // no need to add gesture to inventory observer, it's already made in constructor
- LLGestureMgr::instance().setFetchIDs(item_ids);
- LLGestureMgr::instance().startFetch();
- }
- }
- gDisplaySwapBuffers = TRUE;
-
- LLMessageSystem* msg = gMessageSystem;
- msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger);
- msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound);
- msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound);
- msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change);
-
- LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL;
-
- gRenderStartTime.reset();
- gForegroundTime.reset();
-
- // HACK: Inform simulator of window size.
- // Do this here so it's less likely to race with RegisterNewAgent.
- // TODO: Put this into RegisterNewAgent
- // JC - 7/20/2002
- gViewerWindow->sendShapeToSim();
-
-
- // Ignore stipend information for now. Money history is on the web site.
- // if needed, show the L$ history window
- //if (stipend_since_login && !gNoRender)
- //{
- //}
-
- // The reason we show the alert is because we want to
- // reduce confusion for when you log in and your provided
- // location is not your expected location. So, if this is
- // your first login, then you do not have an expectation,
- // thus, do not show this alert.
- if (!gAgent.isFirstLogin())
- {
- llinfos << "gAgentStartLocation : " << gAgentStartLocation << llendl;
- LLSLURL start_slurl = LLStartUp::getStartSLURL();
-
- if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) ||
- ((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) ||
- ((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home")))
- {
- // Start location is OK
- // Disabled code to restore camera location and focus if logging in to default location
- static bool samename = false;
- if (samename)
- {
- // restore old camera pos
- gAgentCamera.setFocusOnAvatar(FALSE, FALSE);
- gAgentCamera.setCameraPosAndFocusGlobal(gSavedSettings.getVector3d("CameraPosOnLogout"), gSavedSettings.getVector3d("FocusPosOnLogout"), LLUUID::null);
- BOOL limit_hit = FALSE;
- gAgentCamera.calcCameraPositionTargetGlobal(&limit_hit);
- if (limit_hit)
- {
- gAgentCamera.setFocusOnAvatar(TRUE, FALSE);
- }
- gAgentCamera.stopCameraAnimation();
- }
- }
- else
- {
- std::string msg;
- switch(start_slurl.getType())
- {
- case LLSLURL::LOCATION:
- {
-
- msg = "AvatarMovedDesired";
- break;
- }
- case LLSLURL::HOME_LOCATION:
- {
- msg = "AvatarMovedHome";
- break;
- }
- default:
- {
- msg = "AvatarMovedLast";
- }
- }
- LLNotificationsUtil::add(msg);
- }
- }
-
- //DEV-17797. get null folder. Any items found here moved to Lost and Found
- LLInventoryModelBackgroundFetch::instance().findLostItems();
-
- LLStartUp::setStartupState( STATE_PRECACHE );
- timeout.reset();
- return FALSE;
- }
-
- if (STATE_PRECACHE == LLStartUp::getStartupState())
- {
- F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY;
-
- // We now have an inventory skeleton, so if this is a user's first
- // login, we can start setting up their clothing and avatar
- // appearance. This helps to avoid the generic "Ruth" avatar in
- // the orientation island tutorial experience. JC
- if (gAgent.isFirstLogin()
- && !sInitialOutfit.empty() // registration set up an outfit
- && !sInitialOutfitGender.empty() // and a gender
- && isAgentAvatarValid() // can't wear clothes without object
- && !gAgent.isGenderChosen() ) // nothing already loading
- {
- // Start loading the wearables, textures, gestures
- LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender );
- }
-
- // wait precache-delay and for agent's avatar or a lot longer.
- if(((timeout_frac > 1.f) && isAgentAvatarValid())
- || (timeout_frac > 3.f))
- {
- LLStartUp::setStartupState( STATE_WEARABLES_WAIT );
- }
- else
- {
- update_texture_fetch();
- set_startup_status(0.60f + 0.30f * timeout_frac,
- LLTrans::getString("LoginPrecaching"),
- gAgent.mMOTD);
- display_startup();
- if (!LLViewerShaderMgr::sInitialized)
- {
- LLViewerShaderMgr::sInitialized = TRUE;
- LLViewerShaderMgr::instance()->setShaders();
- }
- }
-
- return TRUE;
- }
-
- if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState())
- {
- static LLFrameTimer wearables_timer;
-
- const F32 wearables_time = wearables_timer.getElapsedTimeF32();
- const F32 MAX_WEARABLES_TIME = 10.f;
-
- if (!gAgent.isGenderChosen())
- {
- // No point in waiting for clothing, we don't even
- // know what gender we are. Pop a dialog to ask and
- // proceed to draw the world. JC
- //
- // *NOTE: We might hit this case even if we have an
- // initial outfit, but if the load hasn't started
- // already then something is wrong so fall back
- // to generic outfits. JC
- LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(),
- callback_choose_gender);
- LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
- }
-
- if (wearables_time > MAX_WEARABLES_TIME)
- {
- LLNotificationsUtil::add("ClothingLoading");
- LLViewerStats::getInstance()->incStat(LLViewerStats::ST_WEARABLES_TOO_LONG);
- LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
- }
-
- if (gAgent.isFirstLogin())
- {
- // wait for avatar to be completely loaded
- if (isAgentAvatarValid()
- && gAgentAvatarp->isFullyLoaded())
- {
- //llinfos << "avatar fully loaded" << llendl;
- LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
- }
- }
- else
- {
- // OK to just get the wearables
- if ( gAgentWearables.areWearablesLoaded() )
- {
- // We have our clothing, proceed.
- //llinfos << "wearables loaded" << llendl;
- LLStartUp::setStartupState( STATE_CLEANUP );
- return TRUE;
- }
- }
-
- update_texture_fetch();
- set_startup_status(0.9f + 0.1f * wearables_time / MAX_WEARABLES_TIME,
- LLTrans::getString("LoginDownloadingClothing").c_str(),
- gAgent.mMOTD.c_str());
- return TRUE;
- }
-
- if (STATE_CLEANUP == LLStartUp::getStartupState())
- {
- set_startup_status(1.0, "", "");
-
- // Let the map know about the inventory.
- LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance();
- if(floater_world_map)
- {
- floater_world_map->observeInventory(&gInventory);
- floater_world_map->observeFriends();
- }
- gViewerWindow->showCursor();
- gViewerWindow->getWindow()->resetBusyCount();
- gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
- LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL;
- gViewerWindow->setShowProgress(FALSE);
- gViewerWindow->setProgressCancelButtonVisible(FALSE);
-
- // We're not away from keyboard, even though login might have taken
- // a while. JC
- gAgent.clearAFK();
-
- // Have the agent start watching the friends list so we can update proxies
- gAgent.observeFriends();
- if (gSavedSettings.getBOOL("LoginAsGod"))
- {
- gAgent.requestEnterGodMode();
- }
-
- // Start automatic replay if the flag is set.
- if (gSavedSettings.getBOOL("StatsAutoRun") || LLAgentPilot::sReplaySession)
- {
- LLUUID id;
- LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL;
- gAgentPilot.startPlayback();
- }
-
- show_debug_menus(); // Debug menu visiblity and First Use trigger
-
- // If we've got a startup URL, dispatch it
- LLStartUp::dispatchURL();
-
- // Retrieve information about the land data
- // (just accessing this the first time will fetch it,
- // then the data is cached for the viewer's lifetime)
- LLProductInfoRequestManager::instance();
-
- // *FIX:Mani - What do I do here?
- // Need we really clear the Auth response data?
- // Clean up the userauth stuff.
- // LLUserAuth::getInstance()->reset();
-
- LLStartUp::setStartupState( STATE_STARTED );
-
- // Unmute audio if desired and setup volumes.
- // Unmute audio if desired and setup volumes.
- // This is a not-uncommon crash site, so surround it with
- // llinfos output to aid diagnosis.
- LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL;
- audio_update_volume();
- LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL;
-
- // reset keyboard focus to sane state of pointing at world
- gFocusMgr.setKeyboardFocus(NULL);
-
-#if 0 // sjb: enable for auto-enabling timer display
- gDebugView->mFastTimerView->setVisible(TRUE);
-#endif
-
- LLAppViewer::instance()->handleLoginComplete();
-
- // reset timers now that we are running "logged in" logic
- LLFastTimer::reset();
-
- LLAgentPicksInfo::getInstance()->requestNumberOfPicks();
-
- LLIMFloater::initIMFloater();
-
- return TRUE;
- }
-
- LL_WARNS("AppInit") << "Reached end of idle_startup for state " << LLStartUp::getStartupState() << LL_ENDL;
- return TRUE;
-}
-
-//
-// local function definition
-//
-
-void login_show()
-{
- LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL;
-
-#ifdef LL_RELEASE_FOR_DOWNLOAD
- BOOL bUseDebugLogin = gSavedSettings.getBOOL("UseDebugLogin");
-#else
- BOOL bUseDebugLogin = TRUE;
-#endif
-
- LLPanelLogin::show( gViewerWindow->getWindowRectScaled(),
- bUseDebugLogin || gSavedSettings.getBOOL("SecondLifeEnterprise"),
- login_callback, NULL );
-
-}
-
-// Callback for when login screen is closed. Option 0 = connect, option 1 = quit.
-void login_callback(S32 option, void *userdata)
-{
- const S32 CONNECT_OPTION = 0;
- const S32 QUIT_OPTION = 1;
-
- if (CONNECT_OPTION == option)
- {
- LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
- return;
- }
- else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION
- {
- if (!gSavedSettings.getBOOL("RememberPassword"))
- {
- // turn off the setting and write out to disk
- gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE );
- LLUIColorTable::instance().saveUserSettings();
- }
-
- // Next iteration through main loop should shut down the app cleanly.
- LLAppViewer::instance()->userQuit();
-
- if (LLAppViewer::instance()->quitRequested())
- {
- LLPanelLogin::closePanel();
- }
- return;
- }
- else
- {
- LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL;
- }
-}
-
-void show_first_run_dialog()
-{
- LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback);
-}
-
-bool first_run_dialog_callback(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL;
- LLWeb::loadURLExternal(LLTrans::getString("create_account_url") );
- }
-
- LLPanelLogin::giveFocus();
- return false;
-}
-
-
-
-void set_startup_status(const F32 frac, const std::string& string, const std::string& msg)
-{
- gViewerWindow->setProgressPercent(frac*100);
- gViewerWindow->setProgressString(string);
-
- gViewerWindow->setProgressMessage(msg);
-}
-
-bool login_alert_status(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- // Buttons
- switch( option )
- {
- case 0: // OK
- break;
- // case 1: // Help
- // LLWeb::loadURL(LLNotifications::instance().getGlobalString("SUPPORT_URL") );
- // break;
- case 2: // Teleport
- // Restart the login process, starting at our home locaton
- LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
- LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
- break;
- default:
- LL_WARNS("AppInit") << "Missing case in login_alert_status switch" << LL_ENDL;
- }
-
- LLPanelLogin::giveFocus();
- return false;
-}
-
-
-void use_circuit_callback(void**, S32 result)
-{
- // bail if we're quitting.
- if(LLApp::isExiting()) return;
- if( !gUseCircuitCallbackCalled )
- {
- gUseCircuitCallbackCalled = true;
- if (result)
- {
- // Make sure user knows something bad happened. JC
- LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL;
- LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status);
- reset_login();
- }
- else
- {
- gGotUseCircuitCodeAck = true;
- }
- }
-}
-
-void register_viewer_callbacks(LLMessageSystem* msg)
-{
- msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data );
- msg->setHandlerFuncFast(_PREHASH_ImageData, LLViewerTextureList::receiveImageHeader );
- msg->setHandlerFuncFast(_PREHASH_ImagePacket, LLViewerTextureList::receiveImagePacket );
- msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update );
- msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update );
- msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update );
- msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved );
- msg->setHandlerFunc("SimStats", process_sim_stats);
- msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message );
- msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data);
- msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo);
-
- msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator);
- msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL);
- msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL);
- msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator);
- msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator);
- msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL);
-
- msg->setHandlerFunc("CrossedRegion", process_crossed_region);
- msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish);
-
- msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message);
- msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message);
- msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL);
- msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message);
-
- msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value);
- msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value);
- msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation);
- msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance);
- msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse);
- msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures);
- msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint);
- msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response);
- msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties);
- msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties);
-
- msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im);
- msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question);
- msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL);
- msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL);
- msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect);
-
- msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL);
- msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL);
- msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL);
- msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL);
- msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply,
- &LLLiveLSLEditor::processScriptRunningReply);
-
- msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack);
-
- msg->setHandlerFunc("LogoutReply", process_logout_reply);
-
- //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility,
- // &LLAgent::processAddModifyAbility);
- //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility,
- // &LLAgent::processRemoveModifyAbility);
- msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate,
- &LLAgent::processAgentDataUpdate);
- msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate,
- &LLAgent::processAgentGroupDataUpdate);
- msg->setHandlerFunc("AgentDropGroup",
- &LLAgent::processAgentDropGroup);
- // land ownership messages
- msg->setHandlerFuncFast(_PREHASH_ParcelOverlay,
- LLViewerParcelMgr::processParcelOverlay);
- msg->setHandlerFuncFast(_PREHASH_ParcelProperties,
- LLViewerParcelMgr::processParcelProperties);
- msg->setHandlerFunc("ParcelAccessListReply",
- LLViewerParcelMgr::processParcelAccessListReply);
- msg->setHandlerFunc("ParcelDwellReply",
- LLViewerParcelMgr::processParcelDwellReply);
-
- msg->setHandlerFunc("AvatarPropertiesReply",
- &LLAvatarPropertiesProcessor::processAvatarPropertiesReply);
- msg->setHandlerFunc("AvatarInterestsReply",
- &LLAvatarPropertiesProcessor::processAvatarInterestsReply);
- msg->setHandlerFunc("AvatarGroupsReply",
- &LLAvatarPropertiesProcessor::processAvatarGroupsReply);
- // ratings deprecated
- //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply,
- // LLPanelAvatar::processAvatarStatisticsReply);
- msg->setHandlerFunc("AvatarNotesReply",
- &LLAvatarPropertiesProcessor::processAvatarNotesReply);
- msg->setHandlerFunc("AvatarPicksReply",
- &LLAvatarPropertiesProcessor::processAvatarPicksReply);
- msg->setHandlerFunc("AvatarClassifiedReply",
- &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply);
-
- msg->setHandlerFuncFast(_PREHASH_CreateGroupReply,
- LLGroupMgr::processCreateGroupReply);
- msg->setHandlerFuncFast(_PREHASH_JoinGroupReply,
- LLGroupMgr::processJoinGroupReply);
- msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply,
- LLGroupMgr::processEjectGroupMemberReply);
- msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply,
- LLGroupMgr::processLeaveGroupReply);
- msg->setHandlerFuncFast(_PREHASH_GroupProfileReply,
- LLGroupMgr::processGroupPropertiesReply);
-
- // ratings deprecated
- // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply,
- // LLFloaterRate::processReputationIndividualReply);
-
- msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate,
- LLAgentWearables::processAgentInitialWearablesUpdate );
-
- msg->setHandlerFunc("ScriptControlChange",
- LLAgent::processScriptControlChange );
-
- msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect);
-
- msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers);
-
- msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply,
- LLPanelGroupLandMoney::processGroupAccountSummaryReply);
- msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply,
- LLPanelGroupLandMoney::processGroupAccountDetailsReply);
- msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply,
- LLPanelGroupLandMoney::processGroupAccountTransactionsReply);
-
- msg->setHandlerFuncFast(_PREHASH_UserInfoReply,
- process_user_info_reply);
-
- msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL);
-
- msg->setHandlerFunc("TeleportStart", process_teleport_start );
- msg->setHandlerFunc("TeleportProgress", process_teleport_progress);
- msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL);
- msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL);
-
- msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL);
-
- msg->setHandlerFuncFast(_PREHASH_GroupMembersReply,
- LLGroupMgr::processGroupMembersReply);
- msg->setHandlerFunc("GroupRoleDataReply",
- LLGroupMgr::processGroupRoleDataReply);
- msg->setHandlerFunc("GroupRoleMembersReply",
- LLGroupMgr::processGroupRoleMembersReply);
- msg->setHandlerFunc("GroupTitlesReply",
- LLGroupMgr::processGroupTitlesReply);
- // Special handler as this message is sometimes used for group land.
- msg->setHandlerFunc("PlacesReply", process_places_reply);
- msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply);
-
- msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply);
-
- msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply);
- msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply);
- msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply);
-
- msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply);
-// msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply);
- msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply);
- msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply);
- msg->setHandlerFunc("ScriptDialog", process_script_dialog);
- msg->setHandlerFunc("LoadURL", process_load_url);
- msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request);
- msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply);
-
- // calling cards
- msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard);
- msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard);
- msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard);
-
- msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply);
-
- msg->setHandlerFunc("InitiateDownload", process_initiate_download);
- msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply);
- msg->setHandlerFunc("GenericMessage", process_generic_message);
-
- msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message);
-}
-
-void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32)
-{
- // nothing
-}
-
-// *HACK: Must match name in Library or agent inventory
-const std::string ROOT_GESTURES_FOLDER = "Gestures";
-const std::string COMMON_GESTURES_FOLDER = "Common Gestures";
-const std::string MALE_GESTURES_FOLDER = "Male Gestures";
-const std::string FEMALE_GESTURES_FOLDER = "Female Gestures";
-const std::string SPEECH_GESTURES_FOLDER = "Speech Gestures";
-const std::string OTHER_GESTURES_FOLDER = "Other Gestures";
-const S32 OPT_CLOSED_WINDOW = -1;
-const S32 OPT_MALE = 0;
-const S32 OPT_FEMALE = 1;
-const S32 OPT_TRUST_CERT = 0;
-const S32 OPT_CANCEL_TRUST = 1;
-
-bool callback_choose_gender(const LLSD& notification, const LLSD& response)
-{
-
- // These defaults are returned from the server on login. They are set in login.xml.
- // If no default is returned from the server, they are retrieved from settings.xml.
-
- S32 option = LLNotification::getSelectedOption(notification, response);
- switch(option)
- {
- case OPT_MALE:
- LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" );
- break;
-
- case OPT_FEMALE:
- case OPT_CLOSED_WINDOW:
- default:
- LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" );
- break;
- }
- return false;
-}
-
-void LLStartUp::copyLibraryGestures(const std::string& same_gender_gestures)
-{
- llinfos << "Copying library gestures" << llendl;
-
- // Copy gestures
- LLUUID lib_gesture_cat_id =
- gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE,false,true);
- if (lib_gesture_cat_id.isNull())
- {
- llwarns << "Unable to copy gestures, source category not found" << llendl;
- }
- LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
-
- std::vector<std::string> gesture_folders_to_copy;
- gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER);
- gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER);
- gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER);
- gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER);
- gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER);
-
- for(std::vector<std::string>::iterator it = gesture_folders_to_copy.begin();
- it != gesture_folders_to_copy.end();
- ++it)
- {
- std::string& folder_name = *it;
-
- LLPointer<LLInventoryCallback> cb(NULL);
-
- if (folder_name == same_gender_gestures ||
- folder_name == COMMON_GESTURES_FOLDER ||
- folder_name == OTHER_GESTURES_FOLDER)
- {
- cb = new ActivateGestureCallback;
- }
-
-
- LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name);
- if (cat_id.isNull())
- {
- llwarns << "failed to find gesture folder for " << folder_name << llendl;
- }
- else
- {
- llinfos << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << llendl;
- LLAppearanceMgr* app_mgr = LLAppearanceMgr::getInstance();
- callAfterCategoryFetch(cat_id,
- boost::bind(&LLAppearanceMgr::shallowCopyCategory,
- app_mgr,
- cat_id,
- dst_id,
- cb));
- }
- }
-}
-
-void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
- const std::string& gender_name )
-{
- llinfos << "starting" << llendl;
-
- // Not going through the processAgentInitialWearables path, so need to set this here.
- LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
- // Initiate creation of COF, since we're also bypassing that.
- gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
-
- S32 gender = 0;
- std::string same_gender_gestures;
- if (gender_name == "male")
- {
- gender = OPT_MALE;
- same_gender_gestures = MALE_GESTURES_FOLDER;
- }
- else
- {
- gender = OPT_FEMALE;
- same_gender_gestures = FEMALE_GESTURES_FOLDER;
- }
-
- // try to find the outfit - if not there, create some default
- // wearables.
- LLUUID cat_id = findDescendentCategoryIDByName(
- gInventory.getLibraryRootFolderID(),
- outfit_folder_name);
- if (cat_id.isNull())
- {
- gAgentWearables.createStandardWearables(gender);
- }
- else
- {
- sWearablesLoadedCon = gAgentWearables.addLoadedCallback(LLStartUp::saveInitialOutfit);
-
- bool do_copy = true;
- bool do_append = false;
- LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
- LLAppearanceMgr::instance().wearInventoryCategory(cat, do_copy, do_append);
- }
-
- // Copy gestures
- copyLibraryGestures(same_gender_gestures);
-
- // This is really misnamed -- it means we have started loading
- // an outfit/shape that will give the avatar a gender eventually. JC
- gAgent.setGenderChosen(TRUE);
-
-}
-
-//static
-void LLStartUp::saveInitialOutfit()
-{
- if (sInitialOutfit.empty()) return;
-
- if (sWearablesLoadedCon.connected())
- {
- sWearablesLoadedCon.disconnect();
- }
- LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false);
-}
-
-std::string& LLStartUp::getInitialOutfitName()
-{
- return sInitialOutfit;
-}
-
-// Loads a bitmap to display during load
-void init_start_screen(S32 location_id)
-{
- if (gStartTexture.notNull())
- {
- gStartTexture = NULL;
- LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL;
- }
-
- LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL;
-
- std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter();
-
- if ((S32)START_LOCATION_ID_LAST == location_id)
- {
- temp_str += SCREEN_LAST_FILENAME;
- }
- else
- {
- temp_str += SCREEN_HOME_FILENAME;
- }
-
- LLPointer<LLImageBMP> start_image_bmp = new LLImageBMP;
-
- // Turn off start screen to get around the occasional readback
- // driver bug
- if(!gSavedSettings.getBOOL("UseStartScreen"))
- {
- LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL;
- return;
- }
- else if(!start_image_bmp->load(temp_str) )
- {
- LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL;
- return;
- }
-
- gStartImageWidth = start_image_bmp->getWidth();
- gStartImageHeight = start_image_bmp->getHeight();
-
- LLPointer<LLImageRaw> raw = new LLImageRaw;
- if (!start_image_bmp->decode(raw, 0.0f))
- {
- LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL;
- gStartTexture = NULL;
- return;
- }
-
- raw->expandToPowerOfTwo();
- gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE) ;
-}
-
-
-// frees the bitmap
-void release_start_screen()
-{
- LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL;
- gStartTexture = NULL;
-}
-
-
-// static
-std::string LLStartUp::startupStateToString(EStartupState state)
-{
-#define RTNENUM(E) case E: return #E
- switch(state){
- RTNENUM( STATE_FIRST );
- RTNENUM( STATE_BROWSER_INIT );
- RTNENUM( STATE_LOGIN_SHOW );
- RTNENUM( STATE_LOGIN_WAIT );
- RTNENUM( STATE_LOGIN_CLEANUP );
- RTNENUM( STATE_LOGIN_AUTH_INIT );
- RTNENUM( STATE_LOGIN_CURL_UNSTUCK );
- RTNENUM( STATE_LOGIN_PROCESS_RESPONSE );
- RTNENUM( STATE_WORLD_INIT );
- RTNENUM( STATE_MULTIMEDIA_INIT );
- RTNENUM( STATE_FONT_INIT );
- RTNENUM( STATE_SEED_GRANTED_WAIT );
- RTNENUM( STATE_SEED_CAP_GRANTED );
- RTNENUM( STATE_WORLD_WAIT );
- RTNENUM( STATE_AGENT_SEND );
- RTNENUM( STATE_AGENT_WAIT );
- RTNENUM( STATE_INVENTORY_SEND );
- RTNENUM( STATE_MISC );
- RTNENUM( STATE_PRECACHE );
- RTNENUM( STATE_WEARABLES_WAIT );
- RTNENUM( STATE_CLEANUP );
- RTNENUM( STATE_STARTED );
- default:
- return llformat("(state #%d)", state);
- }
-#undef RTNENUM
-}
-
-// static
-void LLStartUp::setStartupState( EStartupState state )
-{
- LL_INFOS("AppInit") << "Startup state changing from " <<
- getStartupStateString() << " to " <<
- startupStateToString(state) << LL_ENDL;
- gStartupState = state;
- postStartupState();
-}
-
-void LLStartUp::postStartupState()
-{
- LLSD stateInfo;
- stateInfo["str"] = getStartupStateString();
- stateInfo["enum"] = gStartupState;
- sStateWatcher->post(stateInfo);
-}
-
-
-void reset_login()
-{
- gAgentWearables.cleanup();
- gAgentCamera.cleanup();
- gAgent.cleanup();
- LLWorld::getInstance()->destroyClass();
-
- LLStartUp::setStartupState( STATE_LOGIN_SHOW );
-
- if ( gViewerWindow )
- { // Hide menus and normal buttons
- gViewerWindow->setNormalControlsVisible( FALSE );
- gLoginMenuBarView->setVisible( TRUE );
- gLoginMenuBarView->setEnabled( TRUE );
- }
-
- // Hide any other stuff
- LLFloaterReg::hideVisibleInstances();
-}
-
-//---------------------------------------------------------------------------
-
-// Initialize all plug-ins except the web browser (which was initialized
-// early, before the login screen). JC
-void LLStartUp::multimediaInit()
-{
- LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL;
- std::string msg = LLTrans::getString("LoginInitializingMultimedia");
- set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str());
- display_startup();
-
- // LLViewerMedia::initClass();
- LLViewerParcelMedia::initClass();
-}
-
-void LLStartUp::fontInit()
-{
- LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL;
- std::string msg = LLTrans::getString("LoginInitializingFonts");
- set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str());
- display_startup();
-
- LLFontGL::loadDefaultFonts();
-}
-
-void LLStartUp::initNameCache()
-{
- // Can be called multiple times
- if ( gCacheName ) return;
-
- gCacheName = new LLCacheName(gMessageSystem);
- gCacheName->addObserver(&callback_cache_name);
- gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting"));
- gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody"));
- gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone"));
- // Load stored cache if possible
- LLAppViewer::instance()->loadNameCache();
-
- // Start cache in not-running state until we figure out if we have
- // capabilities for display name lookup
- LLAvatarNameCache::initClass(false);
- LLAvatarNameCache::setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames"));
-}
-
-void LLStartUp::cleanupNameCache()
-{
- LLAvatarNameCache::cleanupClass();
-
- delete gCacheName;
- gCacheName = NULL;
-}
-
-bool LLStartUp::dispatchURL()
-{
- // ok, if we've gotten this far and have a startup URL
- if (!getStartSLURL().isValid())
- {
- return false;
- }
- if(getStartSLURL().getType() != LLSLURL::APP)
- {
-
- // If we started with a location, but we're already
- // at that location, don't pop dialogs open.
- LLVector3 pos = gAgent.getPositionAgent();
- LLVector3 slurlpos = getStartSLURL().getPosition();
- F32 dx = pos.mV[VX] - slurlpos.mV[VX];
- F32 dy = pos.mV[VY] - slurlpos.mV[VY];
- const F32 SLOP = 2.f; // meters
-
- if( getStartSLURL().getRegion() != gAgent.getRegion()->getName()
- || (dx*dx > SLOP*SLOP)
- || (dy*dy > SLOP*SLOP) )
- {
- LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(),
- NULL, false);
- }
- return true;
- }
- return false;
-}
-
-void LLStartUp::setStartSLURL(const LLSLURL& slurl)
-{
- sStartSLURL = slurl;
- switch(slurl.getType())
- {
- case LLSLURL::HOME_LOCATION:
- {
- gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_HOME);
- break;
- }
- case LLSLURL::LAST_LOCATION:
- {
- gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_LAST);
- break;
- }
- default:
- LLGridManager::getInstance()->setGridChoice(slurl.getGrid());
- break;
- }
-}
-
-bool login_alert_done(const LLSD& notification, const LLSD& response)
-{
- LLPanelLogin::giveFocus();
- return false;
-}
-
-// parse the certificate information into args for the
-// certificate notifications
-LLSD transform_cert_args(LLPointer<LLCertificate> cert)
-{
- LLSD args = LLSD::emptyMap();
- std::string value;
- LLSD cert_info;
- cert->getLLSD(cert_info);
- // convert all of the elements in the cert into
- // args for the xml dialog, so we have flexability to
- // display various parts of the cert by only modifying
- // the cert alert dialog xml.
- for(LLSD::map_iterator iter = cert_info.beginMap();
- iter != cert_info.endMap();
- iter++)
- {
- // key usage and extended key usage
- // are actually arrays, and we want to format them as comma separated
- // strings, so special case those.
- LLSDSerialize::toXML(cert_info[iter->first], std::cout);
- if((iter->first== std::string(CERT_KEY_USAGE)) |
- (iter->first == std::string(CERT_EXTENDED_KEY_USAGE)))
- {
- value = "";
- LLSD usage = cert_info[iter->first];
- for (LLSD::array_iterator usage_iter = usage.beginArray();
- usage_iter != usage.endArray();
- usage_iter++)
- {
-
- if(usage_iter != usage.beginArray())
- {
- value += ", ";
- }
-
- value += (*usage_iter).asString();
- }
-
- }
- else
- {
- value = iter->second.asString();
- }
-
- std::string name = iter->first;
- std::transform(name.begin(), name.end(), name.begin(),
- (int(*)(int))toupper);
- args[name.c_str()] = value;
- }
- return args;
-}
-
-
-// when we handle a cert error, give focus back to the login panel
-void general_cert_done(const LLSD& notification, const LLSD& response)
-{
- LLStartUp::setStartupState( STATE_LOGIN_SHOW );
- LLPanelLogin::giveFocus();
-}
-
-// check to see if the user wants to trust the cert.
-// if they do, add it to the cert store and
-void trust_cert_done(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotification::getSelectedOption(notification, response);
- switch(option)
- {
- case OPT_TRUST_CERT:
- {
- LLPointer<LLCertificate> cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]);
- LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore"));
- store->add(cert);
- store->save();
- LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
- break;
- }
- case OPT_CANCEL_TRUST:
- reset_login();
- gSavedSettings.setBOOL("AutoLogin", FALSE);
- LLStartUp::setStartupState( STATE_LOGIN_SHOW );
- default:
- LLPanelLogin::giveFocus();
- break;
- }
-
-}
-
-void apply_udp_blacklist(const std::string& csv)
-{
-
- std::string::size_type start = 0;
- std::string::size_type comma = 0;
- do
- {
- comma = csv.find(",", start);
- if (comma == std::string::npos)
- {
- comma = csv.length();
- }
- std::string item(csv, start, comma-start);
-
- lldebugs << "udp_blacklist " << item << llendl;
- gMessageSystem->banUdpMessage(item);
-
- start = comma + 1;
-
- }
- while(comma < csv.length());
-
-}
-
-bool process_login_success_response()
-{
- LLSD response = LLLoginInstance::getInstance()->getResponse();
-
- std::string text(response["udp_blacklist"]);
- if(!text.empty())
- {
- apply_udp_blacklist(text);
- }
-
- // unpack login data needed by the application
- text = response["agent_id"].asString();
- if(!text.empty()) gAgentID.set(text);
- gDebugInfo["AgentID"] = text;
-
- // Agent id needed for parcel info request in LLUrlEntryParcel
- // to resolve parcel name.
- LLUrlEntryParcel::setAgentID(gAgentID);
-
- text = response["session_id"].asString();
- if(!text.empty()) gAgentSessionID.set(text);
- gDebugInfo["SessionID"] = text;
-
- // Session id needed for parcel info request in LLUrlEntryParcel
- // to resolve parcel name.
- LLUrlEntryParcel::setSessionID(gAgentSessionID);
-
- text = response["secure_session_id"].asString();
- if(!text.empty()) gAgent.mSecureSessionID.set(text);
-
- // if the response contains a display name, use that,
- // otherwise if the response contains a first and/or last name,
- // use those. Otherwise use the credential identifier
-
- gDisplayName = "";
- if (response.has("display_name"))
- {
- gDisplayName.assign(response["display_name"].asString());
- if(!gDisplayName.empty())
- {
- // Remove quotes from string. Login.cgi sends these to force
- // names that look like numbers into strings.
- LLStringUtil::replaceChar(gDisplayName, '"', ' ');
- LLStringUtil::trim(gDisplayName);
- }
- }
- if(gDisplayName.empty())
- {
- if(response.has("first_name"))
- {
- gDisplayName.assign(response["first_name"].asString());
- LLStringUtil::replaceChar(gDisplayName, '"', ' ');
- LLStringUtil::trim(gDisplayName);
- }
- if(response.has("last_name"))
- {
- text.assign(response["last_name"].asString());
- LLStringUtil::replaceChar(text, '"', ' ');
- LLStringUtil::trim(text);
- if(!gDisplayName.empty())
- {
- gDisplayName += " ";
- }
- gDisplayName += text;
- }
- }
- if(gDisplayName.empty())
- {
- gDisplayName.assign(gUserCredential->asString());
- }
-
- // this is their actual ability to access content
- text = response["agent_access_max"].asString();
- if (!text.empty())
- {
- // agent_access can be 'A', 'M', and 'PG'.
- gAgent.setMaturity(text[0]);
- }
-
- // this is the value of their preference setting for that content
- // which will always be <= agent_access_max
- text = response["agent_region_access"].asString();
- if (!text.empty())
- {
- U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]);
-
- gSavedSettings.setU32("PreferredMaturity", preferredMaturity);
- }
- // During the AO transition, this flag will be true. Then the flag will
- // go away. After the AO transition, this code and all the code that
- // uses it can be deleted.
- text = response["ao_transition"].asString();
- if (!text.empty())
- {
- if (text == "1")
- {
- gAgent.setAOTransition();
- }
- }
-
- text = response["start_location"].asString();
- if(!text.empty())
- {
- gAgentStartLocation.assign(text);
- }
-
- text = response["circuit_code"].asString();
- if(!text.empty())
- {
- gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10);
- }
- std::string sim_ip_str = response["sim_ip"];
- std::string sim_port_str = response["sim_port"];
- if(!sim_ip_str.empty() && !sim_port_str.empty())
- {
- U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10);
- gFirstSim.set(sim_ip_str, sim_port);
- if (gFirstSim.isOk())
- {
- gMessageSystem->enableCircuit(gFirstSim, TRUE);
- }
- }
- std::string region_x_str = response["region_x"];
- std::string region_y_str = response["region_y"];
- if(!region_x_str.empty() && !region_y_str.empty())
- {
- U32 region_x = strtoul(region_x_str.c_str(), NULL, 10);
- U32 region_y = strtoul(region_y_str.c_str(), NULL, 10);
- gFirstSimHandle = to_region_handle(region_x, region_y);
- }
-
- const std::string look_at_str = response["look_at"];
- if (!look_at_str.empty())
- {
- size_t len = look_at_str.size();
- LLMemoryStream mstr((U8*)look_at_str.c_str(), len);
- LLSD sd = LLSDSerialize::fromNotation(mstr, len);
- gAgentStartLookAt = ll_vector3_from_sd(sd);
- }
-
- text = response["seed_capability"].asString();
- if (!text.empty()) gFirstSimSeedCap = text;
-
- text = response["seconds_since_epoch"].asString();
- if(!text.empty())
- {
- U32 server_utc_time = strtoul(text.c_str(), NULL, 10);
- if(server_utc_time)
- {
- time_t now = time(NULL);
- gUTCOffset = (server_utc_time - now);
- }
- }
-
- // this is the base used to construct help URLs
- text = response["help_url_format"].asString();
- if (!text.empty())
- {
- // replace the default help URL format
- gSavedSettings.setString("HelpURLFormat",text);
-
- // don't fall back to Standalone's pre-connection static help
- gSavedSettings.setBOOL("HelpUseLocal", false);
- }
-
- std::string home_location = response["home"];
- if(!home_location.empty())
- {
- size_t len = home_location.size();
- LLMemoryStream mstr((U8*)home_location.c_str(), len);
- LLSD sd = LLSDSerialize::fromNotation(mstr, len);
- S32 region_x = sd["region_handle"][0].asInteger();
- S32 region_y = sd["region_handle"][1].asInteger();
- U64 region_handle = to_region_handle(region_x, region_y);
- LLVector3 position = ll_vector3_from_sd(sd["position"]);
- gAgent.setHomePosRegion(region_handle, position);
- }
-
- gAgent.mMOTD.assign(response["message"]);
-
- // Options...
- // Each 'option' is an array of submaps.
- // It appears that we only ever use the first element of the array.
- LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"];
- if(inv_root_folder_id.notNull())
- {
- gInventory.setRootFolderID(inv_root_folder_id);
- //gInventory.mock(gAgent.getInventoryRootID());
- }
-
- LLSD login_flags = response["login-flags"][0];
- if(login_flags.size())
- {
- std::string flag = login_flags["ever_logged_in"];
- if(!flag.empty())
- {
- gAgent.setFirstLogin((flag == "N") ? TRUE : FALSE);
- }
-
- /* Flag is currently ignored by the viewer.
- flag = login_flags["stipend_since_login"];
- if(flag == "Y")
- {
- stipend_since_login = true;
- }
- */
-
- flag = login_flags["gendered"].asString();
- if(flag == "Y")
- {
- gAgent.setGenderChosen(TRUE);
- }
-
- bool pacific_daylight_time = false;
- flag = login_flags["daylight_savings"].asString();
- if(flag == "Y")
- {
- pacific_daylight_time = (flag == "Y");
- }
-
- //setup map of datetime strings to codes and slt & local time offset from utc
- LLStringOps::setupDatetimeInfo(pacific_daylight_time);
- }
-
- // set up the voice configuration. Ultimately, we should pass this up as part of each voice
- // channel if we need to move to multiple voice servers per grid.
- LLSD voice_config_info = response["voice-config"];
- if(voice_config_info.has("VoiceServerType"))
- {
- gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString());
- }
-
- // Request the map server url
- std::string map_server_url = response["map-server-url"];
- if(!map_server_url.empty())
- {
- // We got an answer from the grid -> use that for map for the current session
- gSavedSettings.setString("CurrentMapServerURL", map_server_url);
- LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL;
- }
- else
- {
- // No answer from the grid -> use the default setting for current session
- map_server_url = gSavedSettings.getString("MapServerURL");
- gSavedSettings.setString("CurrentMapServerURL", map_server_url);
- LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL;
- }
-
- // Default male and female avatars allowing the user to choose their avatar on first login.
- // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard
- // "new ruth." Not to be confused with 'initial-outfit' below
- LLSD newuser_config = response["newuser-config"][0];
- if(newuser_config.has("DefaultFemaleAvatar"))
- {
- gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString());
- }
- if(newuser_config.has("DefaultMaleAvatar"))
- {
- gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString());
- }
-
- // Initial outfit for the user.
- // QUESTION: Why can't we simply simply set the users outfit directly
- // from a web page into the user info on the server? - Roxie
- LLSD initial_outfit = response["initial-outfit"][0];
- if(initial_outfit.size())
- {
- std::string flag = initial_outfit["folder_name"];
- if(!flag.empty())
- {
- // Initial outfit is a folder in your inventory,
- // must be an exact folder-name match.
- sInitialOutfit = flag;
- }
-
- flag = initial_outfit["gender"].asString();
- if(!flag.empty())
- {
- sInitialOutfitGender = flag;
- }
- }
-
- LLSD global_textures = response["global-textures"][0];
- if(global_textures.size())
- {
- // Extract sun and moon texture IDs. These are used
- // in the LLVOSky constructor, but I can't figure out
- // how to pass them in. JC
- LLUUID id = global_textures["sun_texture_id"];
- if(id.notNull())
- {
- gSunTextureID = id;
- }
-
- id = global_textures["moon_texture_id"];
- if(id.notNull())
- {
- gMoonTextureID = id;
- }
-
- id = global_textures["cloud_texture_id"];
- if(id.notNull())
- {
- gCloudTextureID = id;
- }
- }
-
- // Set the location of the snapshot sharing config endpoint
- std::string snapshot_config_url = response["snapshot_config_url"];
- if(!snapshot_config_url.empty())
- {
- gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url);
- }
-
- // Start the process of fetching the OpenID session cookie for this user login
- std::string openid_url = response["openid_url"];
- if(!openid_url.empty())
- {
- std::string openid_token = response["openid_token"];
- LLViewerMedia::openIDSetup(openid_url, openid_token);
- }
-
- if(response.has("max-agent-groups")) {
- std::string max_agent_groups(response["max-agent-groups"]);
- gMaxAgentGroups = atoi(max_agent_groups.c_str());
- LL_INFOS("LLStartup") << "gMaxAgentGroups read from login.cgi: "
- << gMaxAgentGroups << LL_ENDL;
- }
- else {
- gMaxAgentGroups = DEFAULT_MAX_AGENT_GROUPS;
- LL_INFOS("LLStartup") << "using gMaxAgentGroups default: "
- << gMaxAgentGroups << LL_ENDL;
- }
-
- bool success = false;
- // JC: gesture loading done below, when we have an asset system
- // in place. Don't delete/clear gUserCredentials until then.
- if(gAgentID.notNull()
- && gAgentSessionID.notNull()
- && gMessageSystem->mOurCircuitCode
- && gFirstSim.isOk()
- && gInventory.getRootFolderID().notNull())
- {
- success = true;
- }
-
- return success;
-}
-
-void transition_back_to_login_panel(const std::string& emsg)
-{
- if (gNoRender)
- {
- LL_WARNS("AppInit") << "Failed to login!" << LL_ENDL;
- LL_WARNS("AppInit") << emsg << LL_ENDL;
- exit(0);
- }
-
- // Bounce back to the login screen.
- reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW );
- gSavedSettings.setBOOL("AutoLogin", FALSE);
-}
+/**
+ * @file llstartup.cpp
+ * @brief startup routines.
+ *
+ * $LicenseInfo:firstyear=2004&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llstartup.h"
+
+#if LL_WINDOWS
+# include <process.h> // _spawnl()
+#else
+# include <sys/stat.h> // mkdir()
+#endif
+
+#include "llviewermedia_streamingaudio.h"
+#include "llaudioengine.h"
+
+#ifdef LL_FMOD
+# include "llaudioengine_fmod.h"
+#endif
+
+#ifdef LL_OPENAL
+#include "llaudioengine_openal.h"
+#endif
+
+#include "llares.h"
+#include "llavatarnamecache.h"
+#include "lllandmark.h"
+#include "llcachename.h"
+#include "lldir.h"
+#include "llerrorcontrol.h"
+#include "llfloaterreg.h"
+#include "llfocusmgr.h"
+#include "llhttpsender.h"
+#include "llimfloater.h"
+#include "lllocationhistory.h"
+#include "llimageworker.h"
+
+#include "llloginflags.h"
+#include "llmd5.h"
+#include "llmemorystream.h"
+#include "llmessageconfig.h"
+#include "llmoveview.h"
+#include "llnearbychat.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+#include "llteleporthistory.h"
+#include "llregionhandle.h"
+#include "llsd.h"
+#include "llsdserialize.h"
+#include "llsdutil_math.h"
+#include "llsecondlifeurls.h"
+#include "llstring.h"
+#include "lluserrelations.h"
+#include "llversioninfo.h"
+#include "llviewercontrol.h"
+#include "llvfs.h"
+#include "llxorcipher.h" // saved password, MAC address
+#include "llwindow.h"
+#include "imageids.h"
+#include "message.h"
+#include "v3math.h"
+
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llagentpicksinfo.h"
+#include "llagentwearables.h"
+#include "llagentpilot.h"
+#include "llfloateravatarpicker.h"
+#include "llcallbacklist.h"
+#include "llcallingcard.h"
+#include "llconsole.h"
+#include "llcontainerview.h"
+#include "lldebugview.h"
+#include "lldrawable.h"
+#include "lleventnotifier.h"
+#include "llface.h"
+#include "llfeaturemanager.h"
+//#include "llfirstuse.h"
+#include "llfloaterhud.h"
+#include "llfloaterland.h"
+#include "llfloaterpreference.h"
+#include "llfloatertopobjects.h"
+#include "llfloaterworldmap.h"
+#include "llgesturemgr.h"
+#include "llgroupmgr.h"
+#include "llhudeffecttrail.h"
+#include "llhudmanager.h"
+#include "llhttpclient.h"
+#include "llimagebmp.h"
+#include "llinventorybridge.h"
+#include "llinventorymodel.h"
+#include "llinventorymodelbackgroundfetch.h"
+#include "llkeyboard.h"
+#include "llloginhandler.h" // gLoginHandler, SLURL support
+#include "lllogininstance.h" // Host the login module.
+#include "llpanellogin.h"
+#include "llmutelist.h"
+#include "llavatarpropertiesprocessor.h"
+#include "llpanelclassified.h"
+#include "llpanelpick.h"
+#include "llpanelgrouplandmoney.h"
+#include "llpanelgroupnotices.h"
+#include "llpreview.h"
+#include "llpreviewscript.h"
+#include "llproductinforequest.h"
+#include "llsecondlifeurls.h"
+#include "llselectmgr.h"
+#include "llsky.h"
+#include "llsidetray.h"
+#include "llstatview.h"
+#include "llstatusbar.h" // sendMoneyBalanceRequest(), owns L$ balance
+#include "llsurface.h"
+#include "lltexturecache.h"
+#include "lltexturefetch.h"
+#include "lltoolmgr.h"
+#include "lltrans.h"
+#include "llui.h"
+#include "llurldispatcher.h"
+#include "llurlentry.h"
+#include "llslurl.h"
+#include "llurlhistory.h"
+#include "llurlwhitelist.h"
+#include "llvieweraudio.h"
+#include "llviewerassetstorage.h"
+#include "llviewercamera.h"
+#include "llviewerdisplay.h"
+#include "llviewergenericmessage.h"
+#include "llviewergesture.h"
+#include "llviewertexturelist.h"
+#include "llviewermedia.h"
+#include "llviewermenu.h"
+#include "llviewermessage.h"
+#include "llviewernetwork.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmedia.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llviewerstats.h"
+#include "llviewerthrottle.h"
+#include "llviewerwindow.h"
+#include "llvoavatar.h"
+#include "llvoavatarself.h"
+#include "llvoclouds.h"
+#include "llweb.h"
+#include "llworld.h"
+#include "llworldmapmessage.h"
+#include "llxfermanager.h"
+#include "pipeline.h"
+#include "llappviewer.h"
+#include "llfasttimerview.h"
+#include "llfloatermap.h"
+#include "llweb.h"
+#include "llvoiceclient.h"
+#include "llnamelistctrl.h"
+#include "llnamebox.h"
+#include "llnameeditor.h"
+#include "llpostprocess.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llagentlanguage.h"
+#include "llwearable.h"
+#include "llinventorybridge.h"
+#include "llappearancemgr.h"
+#include "llavatariconctrl.h"
+#include "llvoicechannel.h"
+
+#include "lllogin.h"
+#include "llevents.h"
+#include "llstartuplistener.h"
+
+#if LL_WINDOWS
+#include "lldxhardware.h"
+#endif
+
+//
+// exported globals
+//
+bool gAgentMovementCompleted = false;
+S32 gMaxAgentGroups;
+
+std::string SCREEN_HOME_FILENAME = "screen_home.bmp";
+std::string SCREEN_LAST_FILENAME = "screen_last.bmp";
+
+LLPointer<LLViewerTexture> gStartTexture;
+
+//
+// Imported globals
+//
+extern S32 gStartImageWidth;
+extern S32 gStartImageHeight;
+
+//
+// local globals
+//
+static bool gGotUseCircuitCodeAck = false;
+static std::string sInitialOutfit;
+static std::string sInitialOutfitGender; // "male" or "female"
+static boost::signals2::connection sWearablesLoadedCon;
+
+static bool gUseCircuitCallbackCalled = false;
+
+EStartupState LLStartUp::gStartupState = STATE_FIRST;
+LLSLURL LLStartUp::sStartSLURL;
+
+static LLPointer<LLCredential> gUserCredential;
+static std::string gDisplayName;
+static BOOL gRememberPassword = TRUE;
+
+static U64 gFirstSimHandle = 0;
+static LLHost gFirstSim;
+static std::string gFirstSimSeedCap;
+static LLVector3 gAgentStartLookAt(1.0f, 0.f, 0.f);
+static std::string gAgentStartLocation = "safe";
+static bool mLoginStatePastUI = false;
+
+
+boost::scoped_ptr<LLEventPump> LLStartUp::sStateWatcher(new LLEventStream("StartupState"));
+boost::scoped_ptr<LLStartupListener> LLStartUp::sListener(new LLStartupListener());
+
+//
+// local function declaration
+//
+
+void login_show();
+void login_callback(S32 option, void* userdata);
+void show_first_run_dialog();
+bool first_run_dialog_callback(const LLSD& notification, const LLSD& response);
+void set_startup_status(const F32 frac, const std::string& string, const std::string& msg);
+bool login_alert_status(const LLSD& notification, const LLSD& response);
+void login_packet_failed(void**, S32 result);
+void use_circuit_callback(void**, S32 result);
+void register_viewer_callbacks(LLMessageSystem* msg);
+void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32);
+bool callback_choose_gender(const LLSD& notification, const LLSD& response);
+void init_start_screen(S32 location_id);
+void release_start_screen();
+void reset_login();
+LLSD transform_cert_args(LLPointer<LLCertificate> cert);
+void general_cert_done(const LLSD& notification, const LLSD& response);
+void trust_cert_done(const LLSD& notification, const LLSD& response);
+void apply_udp_blacklist(const std::string& csv);
+bool process_login_success_response();
+void transition_back_to_login_panel(const std::string& emsg);
+
+void callback_cache_name(const LLUUID& id, const std::string& full_name, bool is_group)
+{
+ LLNameBox::refreshAll(id, full_name, is_group);
+ LLNameEditor::refreshAll(id, full_name, is_group);
+
+ // TODO: Actually be intelligent about the refresh.
+ // For now, just brute force refresh the dialogs.
+ dialog_refresh_all();
+}
+
+//
+// exported functionality
+//
+
+//
+// local classes
+//
+
+namespace
+{
+ class LLNullHTTPSender : public LLHTTPSender
+ {
+ virtual void send(const LLHost& host,
+ const std::string& message, const LLSD& body,
+ LLHTTPClient::ResponderPtr response) const
+ {
+ LL_WARNS("AppInit") << " attemped to send " << message << " to " << host
+ << " with null sender" << LL_ENDL;
+ }
+ };
+}
+
+void update_texture_fetch()
+{
+ LLAppViewer::getTextureCache()->update(1); // unpauses the texture cache thread
+ LLAppViewer::getImageDecodeThread()->update(1); // unpauses the image thread
+ LLAppViewer::getTextureFetch()->update(1); // unpauses the texture fetch thread
+ gTextureList.updateImages(0.10f);
+}
+
+// Returns false to skip other idle processing. Should only return
+// true when all initialization done.
+bool idle_startup()
+{
+ LLMemType mt1(LLMemType::MTYPE_STARTUP);
+
+ const F32 PRECACHING_DELAY = gSavedSettings.getF32("PrecachingDelay");
+ static LLTimer timeout;
+ static S32 timeout_count = 0;
+
+ static LLTimer login_time;
+
+ // until this is encapsulated, this little hack for the
+ // auth/transform loop will do.
+ static F32 progress = 0.10f;
+
+ static std::string auth_desc;
+ static std::string auth_message;
+
+ static LLVector3 initial_sun_direction(1.f, 0.f, 0.f);
+ static LLVector3 agent_start_position_region(10.f, 10.f, 10.f); // default for when no space server
+
+ // last location by default
+ static S32 agent_location_id = START_LOCATION_ID_LAST;
+ static S32 location_which = START_LOCATION_ID_LAST;
+
+ static bool show_connect_box = true;
+
+ //static bool stipend_since_login = false;
+
+ // HACK: These are things from the main loop that usually aren't done
+ // until initialization is complete, but need to be done here for things
+ // to work.
+ gIdleCallbacks.callFunctions();
+ gViewerWindow->updateUI();
+ LLMortician::updateClass();
+
+ const std::string delims (" ");
+ std::string system;
+ int begIdx, endIdx;
+ std::string osString = LLAppViewer::instance()->getOSInfo().getOSStringSimple();
+
+ begIdx = osString.find_first_not_of (delims);
+ endIdx = osString.find_first_of (delims, begIdx);
+ system = osString.substr (begIdx, endIdx - begIdx);
+ system += "Locale";
+
+ LLStringUtil::setLocale (LLTrans::getString(system));
+
+ if (!gNoRender)
+ {
+ //note: Removing this line will cause incorrect button size in the login screen. -- bao.
+ gTextureList.updateImages(0.01f) ;
+ }
+
+ if ( STATE_FIRST == LLStartUp::getStartupState() )
+ {
+ gViewerWindow->showCursor();
+ gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
+
+ /////////////////////////////////////////////////
+ //
+ // Initialize stuff that doesn't need data from simulators
+ //
+
+ if (LLFeatureManager::getInstance()->isSafe())
+ {
+ LLNotificationsUtil::add("DisplaySetToSafe");
+ }
+ else if ((gSavedSettings.getS32("LastFeatureVersion") < LLFeatureManager::getInstance()->getVersion()) &&
+ (gSavedSettings.getS32("LastFeatureVersion") != 0))
+ {
+ LLNotificationsUtil::add("DisplaySetToRecommended");
+ }
+ else if ((gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass()) &&
+ (gSavedSettings.getS32("LastGPUClass") != -1))
+ {
+ LLNotificationsUtil::add("DisplaySetToRecommended");
+ }
+ else if (!gViewerWindow->getInitAlert().empty())
+ {
+ LLNotificationsUtil::add(gViewerWindow->getInitAlert());
+ }
+
+ gSavedSettings.setS32("LastFeatureVersion", LLFeatureManager::getInstance()->getVersion());
+ gSavedSettings.setS32("LastGPUClass", LLFeatureManager::getInstance()->getGPUClass());
+
+ // load dynamic GPU/feature tables from website (S3)
+ LLFeatureManager::getInstance()->fetchHTTPTables();
+
+ std::string xml_file = LLUI::locateSkin("xui_version.xml");
+ LLXMLNodePtr root;
+ bool xml_ok = false;
+ if (LLXMLNode::parseFile(xml_file, root, NULL))
+ {
+ if( (root->hasName("xui_version") ) )
+ {
+ std::string value = root->getValue();
+ F32 version = 0.0f;
+ LLStringUtil::convertToF32(value, version);
+ if (version >= 1.0f)
+ {
+ xml_ok = true;
+ }
+ }
+ }
+ if (!xml_ok)
+ {
+ // If XML is bad, there's a good possibility that notifications.xml is ALSO bad.
+ // If that's so, then we'll get a fatal error on attempting to load it,
+ // which will display a nontranslatable error message that says so.
+ // Otherwise, we'll display a reasonable error message that IS translatable.
+ LLAppViewer::instance()->earlyExit("BadInstallation");
+ }
+ //
+ // Statistics stuff
+ //
+
+ // Load autopilot and stats stuff
+ gAgentPilot.load(gSavedSettings.getString("StatsPilotFile"));
+
+ //gErrorStream.setTime(gSavedSettings.getBOOL("LogTimestamps"));
+
+ // Load the throttle settings
+ gViewerThrottle.load();
+
+ if (ll_init_ares() == NULL || !gAres->isInitialized())
+ {
+ std::string diagnostic = "Could not start address resolution system";
+ LL_WARNS("AppInit") << diagnostic << LL_ENDL;
+ LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic));
+ }
+
+ //
+ // Initialize messaging system
+ //
+ LL_DEBUGS("AppInit") << "Initializing messaging system..." << LL_ENDL;
+
+ std::string message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message_template.msg");
+
+ LLFILE* found_template = NULL;
+ found_template = LLFile::fopen(message_template_path, "r"); /* Flawfinder: ignore */
+
+ #if LL_WINDOWS
+ // On the windows dev builds, unpackaged, the message_template.msg
+ // file will be located in:
+ // build-vc**/newview/<config>/app_settings
+ if (!found_template)
+ {
+ message_template_path = gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", "message_template.msg");
+ found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */
+ }
+ #elif LL_DARWIN
+ // On Mac dev builds, message_template.msg lives in:
+ // indra/build-*/newview/<config>/Second Life/Contents/Resources/app_settings
+ if (!found_template)
+ {
+ message_template_path =
+ gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE,
+ "../Resources/app_settings",
+ "message_template.msg");
+ found_template = LLFile::fopen(message_template_path.c_str(), "r"); /* Flawfinder: ignore */
+ }
+ #endif
+
+ if (found_template)
+ {
+ fclose(found_template);
+
+ U32 port = gSavedSettings.getU32("UserConnectionPort");
+
+ if ((NET_USE_OS_ASSIGNED_PORT == port) && // if nothing specified on command line (-port)
+ (gSavedSettings.getBOOL("ConnectionPortEnabled")))
+ {
+ port = gSavedSettings.getU32("ConnectionPort");
+ }
+
+ LLHTTPSender::setDefaultSender(new LLNullHTTPSender());
+
+ // TODO parameterize
+ const F32 circuit_heartbeat_interval = 5;
+ const F32 circuit_timeout = 100;
+
+ const LLUseCircuitCodeResponder* responder = NULL;
+ bool failure_is_fatal = true;
+
+ if(!start_messaging_system(
+ message_template_path,
+ port,
+ LLVersionInfo::getMajor(),
+ LLVersionInfo::getMinor(),
+ LLVersionInfo::getPatch(),
+ FALSE,
+ std::string(),
+ responder,
+ failure_is_fatal,
+ circuit_heartbeat_interval,
+ circuit_timeout))
+ {
+ std::string diagnostic = llformat(" Error: %d", gMessageSystem->getErrorCode());
+ LL_WARNS("AppInit") << diagnostic << LL_ENDL;
+ LLAppViewer::instance()->earlyExit("LoginFailedNoNetwork", LLSD().with("DIAGNOSTIC", diagnostic));
+ }
+
+ #if LL_WINDOWS
+ // On the windows dev builds, unpackaged, the message.xml file will
+ // be located in indra/build-vc**/newview/<config>/app_settings.
+ std::string message_path = gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS,"message.xml");
+
+ if (!LLFile::isfile(message_path.c_str()))
+ {
+ LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_EXECUTABLE, "app_settings", ""));
+ }
+ else
+ {
+ LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+ }
+ #else
+ LLMessageConfig::initClass("viewer", gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, ""));
+ #endif
+
+ }
+ else
+ {
+ LLAppViewer::instance()->earlyExit("MessageTemplateNotFound", LLSD().with("PATH", message_template_path));
+ }
+
+ if(gMessageSystem && gMessageSystem->isOK())
+ {
+ // Initialize all of the callbacks in case of bad message
+ // system data
+ LLMessageSystem* msg = gMessageSystem;
+ msg->setExceptionFunc(MX_UNREGISTERED_MESSAGE,
+ invalid_message_callback,
+ NULL);
+ msg->setExceptionFunc(MX_PACKET_TOO_SHORT,
+ invalid_message_callback,
+ NULL);
+
+ // running off end of a packet is now valid in the case
+ // when a reader has a newer message template than
+ // the sender
+ /*msg->setExceptionFunc(MX_RAN_OFF_END_OF_PACKET,
+ invalid_message_callback,
+ NULL);*/
+ msg->setExceptionFunc(MX_WROTE_PAST_BUFFER_SIZE,
+ invalid_message_callback,
+ NULL);
+
+ if (gSavedSettings.getBOOL("LogMessages"))
+ {
+ LL_DEBUGS("AppInit") << "Message logging activated!" << LL_ENDL;
+ msg->startLogging();
+ }
+
+ // start the xfer system. by default, choke the downloads
+ // a lot...
+ const S32 VIEWER_MAX_XFER = 3;
+ start_xfer_manager(gVFS);
+ gXferManager->setMaxIncomingXfers(VIEWER_MAX_XFER);
+ F32 xfer_throttle_bps = gSavedSettings.getF32("XferThrottle");
+ if (xfer_throttle_bps > 1.f)
+ {
+ gXferManager->setUseAckThrottling(TRUE);
+ gXferManager->setAckThrottleBPS(xfer_throttle_bps);
+ }
+ gAssetStorage = new LLViewerAssetStorage(msg, gXferManager, gVFS, gStaticVFS);
+
+
+ F32 dropPercent = gSavedSettings.getF32("PacketDropPercentage");
+ msg->mPacketRing.setDropPercentage(dropPercent);
+
+ F32 inBandwidth = gSavedSettings.getF32("InBandwidth");
+ F32 outBandwidth = gSavedSettings.getF32("OutBandwidth");
+ if (inBandwidth != 0.f)
+ {
+ LL_DEBUGS("AppInit") << "Setting packetring incoming bandwidth to " << inBandwidth << LL_ENDL;
+ msg->mPacketRing.setUseInThrottle(TRUE);
+ msg->mPacketRing.setInBandwidth(inBandwidth);
+ }
+ if (outBandwidth != 0.f)
+ {
+ LL_DEBUGS("AppInit") << "Setting packetring outgoing bandwidth to " << outBandwidth << LL_ENDL;
+ msg->mPacketRing.setUseOutThrottle(TRUE);
+ msg->mPacketRing.setOutBandwidth(outBandwidth);
+ }
+ }
+
+ LL_INFOS("AppInit") << "Message System Initialized." << LL_ENDL;
+
+ //-------------------------------------------------
+ // Init audio, which may be needed for prefs dialog
+ // or audio cues in connection UI.
+ //-------------------------------------------------
+
+ if (FALSE == gSavedSettings.getBOOL("NoAudio"))
+ {
+ gAudiop = NULL;
+
+#ifdef LL_OPENAL
+ if (!gAudiop
+#if !LL_WINDOWS
+ && NULL == getenv("LL_BAD_OPENAL_DRIVER")
+#endif // !LL_WINDOWS
+ )
+ {
+ gAudiop = (LLAudioEngine *) new LLAudioEngine_OpenAL();
+ }
+#endif
+
+#ifdef LL_FMOD
+ if (!gAudiop
+#if !LL_WINDOWS
+ && NULL == getenv("LL_BAD_FMOD_DRIVER")
+#endif // !LL_WINDOWS
+ )
+ {
+ gAudiop = (LLAudioEngine *) new LLAudioEngine_FMOD();
+ }
+#endif
+
+ if (gAudiop)
+ {
+#if LL_WINDOWS
+ // FMOD on Windows needs the window handle to stop playing audio
+ // when window is minimized. JC
+ void* window_handle = (HWND)gViewerWindow->getPlatformWindow();
+#else
+ void* window_handle = NULL;
+#endif
+ bool init = gAudiop->init(kAUDIO_NUM_SOURCES, window_handle);
+ if(init)
+ {
+ gAudiop->setMuted(TRUE);
+ }
+ else
+ {
+ LL_WARNS("AppInit") << "Unable to initialize audio engine" << LL_ENDL;
+ delete gAudiop;
+ gAudiop = NULL;
+ }
+
+ if (gAudiop)
+ {
+ // if the audio engine hasn't set up its own preferred handler for streaming audio then set up the generic streaming audio implementation which uses media plugins
+ if (NULL == gAudiop->getStreamingAudioImpl())
+ {
+ LL_INFOS("AppInit") << "Using media plugins to render streaming audio" << LL_ENDL;
+ gAudiop->setStreamingAudioImpl(new LLStreamingAudio_MediaPlugins());
+ }
+ }
+ }
+ }
+
+ LL_INFOS("AppInit") << "Audio Engine Initialized." << LL_ENDL;
+
+ if (LLTimer::knownBadTimer())
+ {
+ LL_WARNS("AppInit") << "Unreliable timers detected (may be bad PCI chipset)!!" << LL_ENDL;
+ }
+
+ //
+ // Log on to system
+ //
+ if (gUserCredential.isNull())
+ {
+ gUserCredential = gLoginHandler.initializeLoginInfo();
+ }
+ if (gUserCredential.isNull())
+ {
+ show_connect_box = TRUE;
+ }
+ else if (gSavedSettings.getBOOL("AutoLogin"))
+ {
+ gRememberPassword = TRUE;
+ gSavedSettings.setBOOL("RememberPassword", TRUE);
+ show_connect_box = false;
+ }
+ else
+ {
+ gRememberPassword = gSavedSettings.getBOOL("RememberPassword");
+ show_connect_box = TRUE;
+ }
+ // Go to the next startup state
+ LLStartUp::setStartupState( STATE_BROWSER_INIT );
+ return FALSE;
+ }
+
+
+ if (STATE_BROWSER_INIT == LLStartUp::getStartupState())
+ {
+ LL_DEBUGS("AppInit") << "STATE_BROWSER_INIT" << LL_ENDL;
+ std::string msg = LLTrans::getString("LoginInitializingBrowser");
+ set_startup_status(0.03f, msg.c_str(), gAgent.mMOTD.c_str());
+ display_startup();
+ // LLViewerMedia::initBrowser();
+ LLStartUp::setStartupState( STATE_LOGIN_SHOW );
+ return FALSE;
+ }
+
+
+ if (STATE_LOGIN_SHOW == LLStartUp::getStartupState())
+ {
+ LL_DEBUGS("AppInit") << "Initializing Window" << LL_ENDL;
+
+ // if we've gone backwards in the login state machine, to this state where we show the UI
+ // AND the debug setting to exit in this case is true, then go ahead and bail quickly
+ if ( mLoginStatePastUI && gSavedSettings.getBOOL("QuitOnLoginActivated") )
+ {
+ // no requirement for notification here - just exit
+ LLAppViewer::instance()->earlyExitNoNotify();
+ }
+
+ gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
+
+ timeout_count = 0;
+
+ if (show_connect_box)
+ {
+ // Load all the name information out of the login view
+ // NOTE: Hits "Attempted getFields with no login view shown" warning, since we don't
+ // show the login view until login_show() is called below.
+ if (gUserCredential.isNull())
+ {
+ gUserCredential = gLoginHandler.initializeLoginInfo();
+ }
+ if (gNoRender)
+ {
+ LL_ERRS("AppInit") << "Need to autologin or use command line with norender!" << LL_ENDL;
+ }
+ // Make sure the process dialog doesn't hide things
+ gViewerWindow->setShowProgress(FALSE);
+
+ initialize_edit_menu();
+
+ // Show the login dialog
+ login_show();
+ // connect dialog is already shown, so fill in the names
+ if (gUserCredential.notNull())
+ {
+ LLPanelLogin::setFields( gUserCredential, gRememberPassword);
+ }
+ LLPanelLogin::giveFocus();
+
+ gSavedSettings.setBOOL("FirstRunThisInstall", FALSE);
+
+ LLStartUp::setStartupState( STATE_LOGIN_WAIT ); // Wait for user input
+ }
+ else
+ {
+ // skip directly to message template verification
+ LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
+ }
+
+ // *NOTE: This is where LLViewerParcelMgr::getInstance() used to get allocated before becoming LLViewerParcelMgr::getInstance().
+
+ // *NOTE: This is where gHUDManager used to bet allocated before becoming LLHUDManager::getInstance().
+
+ // *NOTE: This is where gMuteList used to get allocated before becoming LLMuteList::getInstance().
+
+ // Login screen needs menus for preferences, but we can enter
+ // this startup phase more than once.
+ if (gLoginMenuBarView == NULL)
+ {
+ init_menus();
+ }
+
+ gViewerWindow->setNormalControlsVisible( FALSE );
+ gLoginMenuBarView->setVisible( TRUE );
+ gLoginMenuBarView->setEnabled( TRUE );
+ show_debug_menus();
+
+ // Hide the splash screen
+ LLSplashScreen::hide();
+
+ // Push our window frontmost
+ gViewerWindow->getWindow()->show();
+ display_startup();
+
+ // DEV-16927. The following code removes errant keystrokes that happen while the window is being
+ // first made visible.
+#ifdef _WIN32
+ MSG msg;
+ while( PeekMessage( &msg, /*All hWnds owned by this thread */ NULL, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE ) );
+#endif
+ timeout.reset();
+ return FALSE;
+ }
+
+ if (STATE_LOGIN_WAIT == LLStartUp::getStartupState())
+ {
+ // when we get to this state, we've already been past the login UI
+ // (possiblely automatically) - flag this so we can test in the
+ // STATE_LOGIN_SHOW state if we've gone backwards
+ mLoginStatePastUI = true;
+
+ // Don't do anything. Wait for the login view to call the login_callback,
+ // which will push us to the next state.
+
+ // Sleep so we don't spin the CPU
+ ms_sleep(1);
+ return FALSE;
+ }
+
+ if (STATE_LOGIN_CLEANUP == LLStartUp::getStartupState())
+ {
+ //reset the values that could have come in from a slurl
+ // DEV-42215: Make sure they're not empty -- gUserCredential
+ // might already have been set from gSavedSettings, and it's too bad
+ // to overwrite valid values with empty strings.
+
+ if (show_connect_box)
+ {
+ // TODO if not use viewer auth
+ // Load all the name information out of the login view
+ LLPanelLogin::getFields(gUserCredential, gRememberPassword);
+ // end TODO
+
+ // HACK: Try to make not jump on login
+ gKeyboard->resetKeys();
+ }
+
+ // when we get to this state, we've already been past the login UI
+ // (possiblely automatically) - flag this so we can test in the
+ // STATE_LOGIN_SHOW state if we've gone backwards
+ mLoginStatePastUI = true;
+
+ // save the credentials
+ std::string userid = "unknown";
+ if(gUserCredential.notNull())
+ {
+ userid = gUserCredential->userID();
+ gSecAPIHandler->saveCredential(gUserCredential, gRememberPassword);
+ }
+ gSavedSettings.setBOOL("RememberPassword", gRememberPassword);
+ LL_INFOS("AppInit") << "Attempting login as: " << userid << LL_ENDL;
+ gDebugInfo["LoginName"] = userid;
+
+ // create necessary directories
+ // *FIX: these mkdir's should error check
+ gDirUtilp->setLindenUserDir(userid);
+ LLFile::mkdir(gDirUtilp->getLindenUserDir());
+
+ // Set PerAccountSettingsFile to the default value.
+ std::string per_account_settings_file = LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount");
+ gSavedSettings.setString("PerAccountSettingsFile",
+ gDirUtilp->getExpandedFilename(LL_PATH_PER_SL_ACCOUNT,
+ LLAppViewer::instance()->getSettingsFilename("Default", "PerAccount")));
+
+ // Note: can't store warnings files per account because some come up before login
+
+ // Overwrite default user settings with user settings
+ LLAppViewer::instance()->loadSettingsFromDirectory("Account");
+
+ // Need to set the LastLogoff time here if we don't have one. LastLogoff is used for "Recent Items" calculation
+ // and startup time is close enough if we don't have a real value.
+ if (gSavedPerAccountSettings.getU32("LastLogoff") == 0)
+ {
+ gSavedPerAccountSettings.setU32("LastLogoff", time_corrected());
+ }
+
+ //Default the path if one isn't set.
+ // *NOTE: unable to check variable differ from "InstantMessageLogPath" because it was
+ // provided in pre 2.0 viewer. See EXT-6661
+ if (gSavedPerAccountSettings.getString("InstantMessageLogPath").empty())
+ {
+ gDirUtilp->setChatLogsDir(gDirUtilp->getOSUserAppDir());
+ gSavedPerAccountSettings.setString("InstantMessageLogPath", gDirUtilp->getChatLogsDir());
+ }
+ else
+ {
+ gDirUtilp->setChatLogsDir(gSavedPerAccountSettings.getString("InstantMessageLogPath"));
+ }
+ gDirUtilp->setPerAccountChatLogsDir(userid);
+
+ LLFile::mkdir(gDirUtilp->getChatLogsDir());
+ LLFile::mkdir(gDirUtilp->getPerAccountChatLogsDir());
+
+
+ //good a place as any to create user windlight directories
+ std::string user_windlight_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight", ""));
+ LLFile::mkdir(user_windlight_path_name.c_str());
+
+ std::string user_windlight_skies_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/skies", ""));
+ LLFile::mkdir(user_windlight_skies_path_name.c_str());
+
+ std::string user_windlight_water_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/water", ""));
+ LLFile::mkdir(user_windlight_water_path_name.c_str());
+
+ std::string user_windlight_days_path_name(gDirUtilp->getExpandedFilename( LL_PATH_USER_SETTINGS , "windlight/days", ""));
+ LLFile::mkdir(user_windlight_days_path_name.c_str());
+
+
+ if (show_connect_box)
+ {
+ LLSLURL slurl;
+ LLPanelLogin::closePanel();
+ }
+
+
+ // Load URL History File
+ LLURLHistory::loadFile("url_history.xml");
+ // Load location history
+ LLLocationHistory::getInstance()->load();
+
+ // Load Avatars icons cache
+ LLAvatarIconIDCache::getInstance()->load();
+
+ // Load media plugin cookies
+ LLViewerMedia::loadCookieFile();
+
+ //-------------------------------------------------
+ // Handle startup progress screen
+ //-------------------------------------------------
+
+ // on startup the user can request to go to their home,
+ // their last location, or some URL "-url //sim/x/y[/z]"
+ // All accounts have both a home and a last location, and we don't support
+ // more locations than that. Choose the appropriate one. JC
+ switch (LLStartUp::getStartSLURL().getType())
+ {
+ case LLSLURL::LOCATION:
+ agent_location_id = START_LOCATION_ID_URL;
+ location_which = START_LOCATION_ID_LAST;
+ break;
+ case LLSLURL::LAST_LOCATION:
+ agent_location_id = START_LOCATION_ID_LAST;
+ location_which = START_LOCATION_ID_LAST;
+ break;
+ default:
+ agent_location_id = START_LOCATION_ID_HOME;
+ location_which = START_LOCATION_ID_HOME;
+ break;
+ }
+
+ gViewerWindow->getWindow()->setCursor(UI_CURSOR_WAIT);
+
+ if (!gNoRender)
+ {
+ init_start_screen(agent_location_id);
+ }
+
+ // Display the startup progress bar.
+ gViewerWindow->setShowProgress(TRUE);
+ gViewerWindow->setProgressCancelButtonVisible(TRUE, LLTrans::getString("Quit"));
+
+ // Poke the VFS, which could potentially block for a while if
+ // Windows XP is acting up
+ set_startup_status(0.07f, LLTrans::getString("LoginVerifyingCache"), LLStringUtil::null);
+ display_startup();
+
+ gVFS->pokeFiles();
+
+ LLStartUp::setStartupState( STATE_LOGIN_AUTH_INIT );
+
+ return FALSE;
+ }
+
+ if(STATE_LOGIN_AUTH_INIT == LLStartUp::getStartupState())
+ {
+ gDebugInfo["GridName"] = LLGridManager::getInstance()->getGridLabel();
+
+ // Update progress status and the display loop.
+ auth_desc = LLTrans::getString("LoginInProgress");
+ set_startup_status(progress, auth_desc, auth_message);
+ progress += 0.02f;
+ display_startup();
+
+ // Setting initial values...
+ LLLoginInstance* login = LLLoginInstance::getInstance();
+ login->setNotificationsInterface(LLNotifications::getInstance());
+ if(gNoRender)
+ {
+ // HACK, skip optional updates if you're running drones
+ login->setSkipOptionalUpdate(true);
+ }
+
+ login->setSerialNumber(LLAppViewer::instance()->getSerialNumber());
+ login->setLastExecEvent(gLastExecEvent);
+ login->setUpdaterLauncher(boost::bind(&LLAppViewer::launchUpdater, LLAppViewer::instance()));
+
+ // This call to LLLoginInstance::connect() starts the
+ // authentication process.
+ login->connect(gUserCredential);
+
+ LLStartUp::setStartupState( STATE_LOGIN_CURL_UNSTUCK );
+ return FALSE;
+ }
+
+ if(STATE_LOGIN_CURL_UNSTUCK == LLStartUp::getStartupState())
+ {
+ // If we get here we have gotten past the potential stall
+ // in curl, so take "may appear frozen" out of progress bar. JC
+ auth_desc = LLTrans::getString("LoginInProgressNoFrozen");
+ set_startup_status(progress, auth_desc, auth_message);
+
+ LLStartUp::setStartupState( STATE_LOGIN_PROCESS_RESPONSE );
+ return FALSE;
+ }
+
+ if(STATE_LOGIN_PROCESS_RESPONSE == LLStartUp::getStartupState())
+ {
+ std::ostringstream emsg;
+ emsg << LLTrans::getString("LoginFailed") << "\n";
+ if(LLLoginInstance::getInstance()->authFailure())
+ {
+ LL_INFOS("LLStartup") << "Login failed, LLLoginInstance::getResponse(): "
+ << LLLoginInstance::getInstance()->getResponse() << LL_ENDL;
+ LLSD response = LLLoginInstance::getInstance()->getResponse();
+ // Still have error conditions that may need some
+ // sort of handling.
+ std::string reason_response = response["reason"];
+ std::string message_response = response["message"];
+
+ if(!message_response.empty())
+ {
+ // XUI: fix translation for strings returned during login
+ // We need a generic table for translations
+ std::string big_reason = LLAgent::sTeleportErrorMessages[ message_response ];
+ if ( big_reason.size() == 0 )
+ {
+ emsg << message_response;
+ }
+ else
+ {
+ emsg << big_reason;
+ }
+ }
+
+ if(reason_response == "key")
+ {
+ // Couldn't login because user/password is wrong
+ // Clear the credential
+ gUserCredential->clearAuthenticator();
+ }
+
+ if(reason_response == "update"
+ || reason_response == "optional")
+ {
+ // In the case of a needed update, quit.
+ // Its either downloading or declined.
+ // If optional was skipped this case shouldn't
+ // be reached.
+ LLLoginInstance::getInstance()->disconnect();
+ LLAppViewer::instance()->forceQuit();
+ }
+ else
+ {
+ if (reason_response != "tos")
+ {
+ // Don't pop up a notification in the TOS case because
+ // LLFloaterTOS::onCancel() already scolded the user.
+ std::string error_code;
+ if(response.has("errorcode"))
+ {
+ error_code = response["errorcode"].asString();
+ }
+ if ((reason_response == "CURLError") &&
+ (error_code == "SSL_CACERT" || error_code == "SSL_PEER_CERTIFICATE") &&
+ response.has("certificate"))
+ {
+ // This was a certificate error, so grab the certificate
+ // and throw up the appropriate dialog.
+ LLPointer<LLCertificate> certificate = gSecAPIHandler->getCertificate(response["certificate"]);
+ if(certificate)
+ {
+ LLSD args = transform_cert_args(certificate);
+
+ if(error_code == "SSL_CACERT")
+ {
+ // if we are handling an untrusted CA, throw up the dialog
+ // with the 'trust this CA' button.
+ LLNotificationsUtil::add("TrustCertificateError", args, response,
+ trust_cert_done);
+
+ show_connect_box = true;
+ }
+ else
+ {
+ // the certificate exception returns a unique string for each type of exception.
+ // we grab this string via the LLUserAuth object, and use that to grab the localized
+ // string.
+ args["REASON"] = LLTrans::getString(message_response);
+
+ LLNotificationsUtil::add("GeneralCertificateError", args, response,
+ general_cert_done);
+
+ reset_login();
+ gSavedSettings.setBOOL("AutoLogin", FALSE);
+ show_connect_box = true;
+
+ }
+
+ }
+ }
+ else
+ {
+ // This wasn't a certificate error, so throw up the normal
+ // notificatioin message.
+ LLSD args;
+ args["ERROR_MESSAGE"] = emsg.str();
+ LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
+ LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
+ }
+ }
+ //setup map of datetime strings to codes and slt & local time offset from utc
+ // *TODO: Does this need to be here?
+ LLStringOps::setupDatetimeInfo (false);
+ transition_back_to_login_panel(emsg.str());
+ show_connect_box = true;
+ }
+ }
+ else if(LLLoginInstance::getInstance()->authSuccess())
+ {
+ if(process_login_success_response())
+ {
+ // Pass the user information to the voice chat server interface.
+ LLVoiceClient::getInstance()->userAuthorized(gUserCredential->userID(), gAgentID);
+ // create the default proximal channel
+ LLVoiceChannel::initClass();
+ LLGridManager::getInstance()->setFavorite();
+ LLStartUp::setStartupState( STATE_WORLD_INIT);
+ }
+ else
+ {
+ LLSD args;
+ args["ERROR_MESSAGE"] = emsg.str();
+ LL_INFOS("LLStartup") << "Notification: " << args << LL_ENDL;
+ LLNotificationsUtil::add("ErrorMessage", args, LLSD(), login_alert_done);
+ transition_back_to_login_panel(emsg.str());
+ show_connect_box = true;
+ return FALSE;
+ }
+ }
+ return FALSE;
+ }
+
+ //---------------------------------------------------------------------
+ // World Init
+ //---------------------------------------------------------------------
+ if (STATE_WORLD_INIT == LLStartUp::getStartupState())
+ {
+ set_startup_status(0.30f, LLTrans::getString("LoginInitializingWorld"), gAgent.mMOTD);
+ display_startup();
+ // We should have an agent id by this point.
+ llassert(!(gAgentID == LLUUID::null));
+
+ // Finish agent initialization. (Requires gSavedSettings, builds camera)
+ gAgent.init();
+ gAgentCamera.init();
+ set_underclothes_menu_options();
+
+ // Since we connected, save off the settings so the user doesn't have to
+ // type the name/password again if we crash.
+ gSavedSettings.saveToFile(gSavedSettings.getString("ClientSettingsFile"), TRUE);
+ LLUIColorTable::instance().saveUserSettings();
+
+ //
+ // Initialize classes w/graphics stuff.
+ //
+ gTextureList.doPrefetchImages();
+ LLSurface::initClasses();
+
+ LLFace::initClass();
+
+ LLDrawable::initClass();
+
+ // init the shader managers
+ LLPostProcess::initClass();
+ LLWLParamManager::initClass();
+ LLWaterParamManager::initClass();
+
+ LLViewerObject::initVOClasses();
+
+ // Initialize all our tools. Must be done after saved settings loaded.
+ // NOTE: This also is where gToolMgr used to be instantiated before being turned into a singleton.
+ LLToolMgr::getInstance()->initTools();
+
+ // Pre-load floaters, like the world map, that are slow to spawn
+ // due to XML complexity.
+ gViewerWindow->initWorldUI();
+
+ display_startup();
+
+ // This is where we used to initialize gWorldp. Original comment said:
+ // World initialization must be done after above window init
+
+ // User might have overridden far clip
+ LLWorld::getInstance()->setLandFarClip(gAgentCamera.mDrawDistance);
+
+ // Before we create the first region, we need to set the agent's mOriginGlobal
+ // This is necessary because creating objects before this is set will result in a
+ // bad mPositionAgent cache.
+
+ gAgent.initOriginGlobal(from_region_handle(gFirstSimHandle));
+
+ LLWorld::getInstance()->addRegion(gFirstSimHandle, gFirstSim);
+
+ LLViewerRegion *regionp = LLWorld::getInstance()->getRegionFromHandle(gFirstSimHandle);
+ LL_INFOS("AppInit") << "Adding initial simulator " << regionp->getOriginGlobal() << LL_ENDL;
+
+ regionp->setSeedCapability(gFirstSimSeedCap);
+ LL_DEBUGS("AppInit") << "Waiting for seed grant ...." << LL_ENDL;
+
+ // Set agent's initial region to be the one we just created.
+ gAgent.setRegion(regionp);
+
+ // Set agent's initial position, which will be read by LLVOAvatar when the avatar
+ // object is created. I think this must be done after setting the region. JC
+ gAgent.setPositionAgent(agent_start_position_region);
+
+ display_startup();
+ LLStartUp::setStartupState( STATE_MULTIMEDIA_INIT );
+
+ return FALSE;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Load QuickTime/GStreamer and other multimedia engines, can be slow.
+ // Do it while we're waiting on the network for our seed capability. JC
+ //---------------------------------------------------------------------
+ if (STATE_MULTIMEDIA_INIT == LLStartUp::getStartupState())
+ {
+ LLStartUp::multimediaInit();
+ LLStartUp::setStartupState( STATE_FONT_INIT );
+ return FALSE;
+ }
+
+ // Loading fonts takes several seconds
+ if (STATE_FONT_INIT == LLStartUp::getStartupState())
+ {
+ LLStartUp::fontInit();
+ LLStartUp::setStartupState( STATE_SEED_GRANTED_WAIT );
+ return FALSE;
+ }
+
+ //---------------------------------------------------------------------
+ // Wait for Seed Cap Grant
+ //---------------------------------------------------------------------
+ if(STATE_SEED_GRANTED_WAIT == LLStartUp::getStartupState())
+ {
+ return FALSE;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Seed Capability Granted
+ // no newMessage calls should happen before this point
+ //---------------------------------------------------------------------
+ if (STATE_SEED_CAP_GRANTED == LLStartUp::getStartupState())
+ {
+ update_texture_fetch();
+
+ if ( gViewerWindow != NULL)
+ { // This isn't the first logon attempt, so show the UI
+ gViewerWindow->setNormalControlsVisible( TRUE );
+ }
+ gLoginMenuBarView->setVisible( FALSE );
+ gLoginMenuBarView->setEnabled( FALSE );
+
+ if (!gNoRender)
+ {
+ // direct logging to the debug console's line buffer
+ LLError::logToFixedBuffer(gDebugView->mDebugConsolep);
+
+ // set initial visibility of debug console
+ gDebugView->mDebugConsolep->setVisible(gSavedSettings.getBOOL("ShowDebugConsole"));
+ }
+
+ //
+ // Set message handlers
+ //
+ LL_INFOS("AppInit") << "Initializing communications..." << LL_ENDL;
+
+ // register callbacks for messages. . . do this after initial handshake to make sure that we don't catch any unwanted
+ register_viewer_callbacks(gMessageSystem);
+
+ // Debugging info parameters
+ gMessageSystem->setMaxMessageTime( 0.5f ); // Spam if decoding all msgs takes more than 500 ms
+
+ #ifndef LL_RELEASE_FOR_DOWNLOAD
+ gMessageSystem->setTimeDecodes( TRUE ); // Time the decode of each msg
+ gMessageSystem->setTimeDecodesSpamThreshold( 0.05f ); // Spam if a single msg takes over 50ms to decode
+ #endif
+
+ gXferManager->registerCallbacks(gMessageSystem);
+
+ LLStartUp::initNameCache();
+
+ // update the voice settings *after* gCacheName initialization
+ // so that we can construct voice UI that relies on the name cache
+ LLVoiceClient::getInstance()->updateSettings();
+
+ //gCacheName is required for nearby chat history loading
+ //so I just moved nearby history loading a few states further
+ if (!gNoRender && gSavedPerAccountSettings.getBOOL("LogShowHistory"))
+ {
+ LLNearbyChat* nearby_chat = LLNearbyChat::getInstance();
+ if (nearby_chat) nearby_chat->loadHistory();
+ }
+
+ // *Note: this is where gWorldMap used to be initialized.
+
+ // register null callbacks for audio until the audio system is initialized
+ gMessageSystem->setHandlerFuncFast(_PREHASH_SoundTrigger, null_message_callback, NULL);
+ gMessageSystem->setHandlerFuncFast(_PREHASH_AttachedSound, null_message_callback, NULL);
+
+ //reset statistics
+ LLViewerStats::getInstance()->resetStats();
+
+ display_startup();
+ //
+ // Set up region and surface defaults
+ //
+
+
+ // Sets up the parameters for the first simulator
+
+ LL_DEBUGS("AppInit") << "Initializing camera..." << LL_ENDL;
+ gFrameTime = totalTime();
+ F32 last_time = gFrameTimeSeconds;
+ gFrameTimeSeconds = (S64)(gFrameTime - gStartTime)/SEC_TO_MICROSEC;
+
+ gFrameIntervalSeconds = gFrameTimeSeconds - last_time;
+ if (gFrameIntervalSeconds < 0.f)
+ {
+ gFrameIntervalSeconds = 0.f;
+ }
+
+ // Make sure agent knows correct aspect ratio
+ // FOV limits depend upon aspect ratio so this needs to happen before initializing the FOV below
+ LLViewerCamera::getInstance()->setViewHeightInPixels(gViewerWindow->getWorldViewHeightRaw());
+ LLViewerCamera::getInstance()->setAspect(gViewerWindow->getWorldViewAspectRatio());
+ // Initialize FOV
+ LLViewerCamera::getInstance()->setDefaultFOV(gSavedSettings.getF32("CameraAngle"));
+
+ // Move agent to starting location. The position handed to us by
+ // the space server is in global coordinates, but the agent frame
+ // is in region local coordinates. Therefore, we need to adjust
+ // the coordinates handed to us to fit in the local region.
+
+ gAgent.setPositionAgent(agent_start_position_region);
+ gAgent.resetAxes(gAgentStartLookAt);
+ gAgentCamera.stopCameraAnimation();
+ gAgentCamera.resetCamera();
+
+ // Initialize global class data needed for surfaces (i.e. textures)
+ if (!gNoRender)
+ {
+ LL_DEBUGS("AppInit") << "Initializing sky..." << LL_ENDL;
+ // Initialize all of the viewer object classes for the first time (doing things like texture fetches.
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ gSky.init(initial_sun_direction);
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ }
+
+ LL_DEBUGS("AppInit") << "Decoding images..." << LL_ENDL;
+ // For all images pre-loaded into viewer cache, decode them.
+ // Need to do this AFTER we init the sky
+ const S32 DECODE_TIME_SEC = 2;
+ for (int i = 0; i < DECODE_TIME_SEC; i++)
+ {
+ F32 frac = (F32)i / (F32)DECODE_TIME_SEC;
+ set_startup_status(0.45f + frac*0.1f, LLTrans::getString("LoginDecodingImages"), gAgent.mMOTD);
+ display_startup();
+ gTextureList.decodeAllImages(1.f);
+ }
+ LLStartUp::setStartupState( STATE_WORLD_WAIT );
+
+ // JC - Do this as late as possible to increase likelihood Purify
+ // will run.
+ LLMessageSystem* msg = gMessageSystem;
+ if (!msg->mOurCircuitCode)
+ {
+ LL_WARNS("AppInit") << "Attempting to connect to simulator with a zero circuit code!" << LL_ENDL;
+ }
+
+ gUseCircuitCallbackCalled = false;
+
+ msg->enableCircuit(gFirstSim, TRUE);
+ // now, use the circuit info to tell simulator about us!
+ LL_INFOS("AppInit") << "viewer: UserLoginLocationReply() Enabling " << gFirstSim << " with code " << msg->mOurCircuitCode << LL_ENDL;
+ msg->newMessageFast(_PREHASH_UseCircuitCode);
+ msg->nextBlockFast(_PREHASH_CircuitCode);
+ msg->addU32Fast(_PREHASH_Code, msg->mOurCircuitCode);
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_ID, gAgent.getID());
+ msg->sendReliable(
+ gFirstSim,
+ gSavedSettings.getS32("UseCircuitCodeMaxRetries"),
+ FALSE,
+ gSavedSettings.getF32("UseCircuitCodeTimeout"),
+ use_circuit_callback,
+ NULL);
+
+ timeout.reset();
+
+ return FALSE;
+ }
+
+ //---------------------------------------------------------------------
+ // Agent Send
+ //---------------------------------------------------------------------
+ if(STATE_WORLD_WAIT == LLStartUp::getStartupState())
+ {
+ LL_DEBUGS("AppInit") << "Waiting for simulator ack...." << LL_ENDL;
+ set_startup_status(0.59f, LLTrans::getString("LoginWaitingForRegionHandshake"), gAgent.mMOTD);
+ if(gGotUseCircuitCodeAck)
+ {
+ LLStartUp::setStartupState( STATE_AGENT_SEND );
+ }
+ LLMessageSystem* msg = gMessageSystem;
+ while (msg->checkAllMessages(gFrameCount, gServicePump))
+ {
+ }
+ msg->processAcks();
+ return FALSE;
+ }
+
+ //---------------------------------------------------------------------
+ // Agent Send
+ //---------------------------------------------------------------------
+ if (STATE_AGENT_SEND == LLStartUp::getStartupState())
+ {
+ LL_DEBUGS("AppInit") << "Connecting to region..." << LL_ENDL;
+ set_startup_status(0.60f, LLTrans::getString("LoginConnectingToRegion"), gAgent.mMOTD);
+ // register with the message system so it knows we're
+ // expecting this message
+ LLMessageSystem* msg = gMessageSystem;
+ msg->setHandlerFuncFast(
+ _PREHASH_AgentMovementComplete,
+ process_agent_movement_complete);
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if(regionp)
+ {
+ send_complete_agent_movement(regionp->getHost());
+ gAssetStorage->setUpstream(regionp->getHost());
+ gCacheName->setUpstream(regionp->getHost());
+ msg->newMessageFast(_PREHASH_EconomyDataRequest);
+ gAgent.sendReliableMessage();
+ }
+
+ // Create login effect
+ // But not on first login, because you can't see your avatar then
+ if (!gAgent.isFirstLogin())
+ {
+ LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
+ effectp->setPositionGlobal(gAgent.getPositionGlobal());
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ LLHUDManager::getInstance()->sendEffects();
+ }
+
+ LLStartUp::setStartupState( STATE_AGENT_WAIT ); // Go to STATE_AGENT_WAIT
+
+ timeout.reset();
+ return FALSE;
+ }
+
+ //---------------------------------------------------------------------
+ // Agent Wait
+ //---------------------------------------------------------------------
+ if (STATE_AGENT_WAIT == LLStartUp::getStartupState())
+ {
+ LLMessageSystem* msg = gMessageSystem;
+ while (msg->checkAllMessages(gFrameCount, gServicePump))
+ {
+ if (gAgentMovementCompleted)
+ {
+ // Sometimes we have more than one message in the
+ // queue. break out of this loop and continue
+ // processing. If we don't, then this could skip one
+ // or more login steps.
+ break;
+ }
+ else
+ {
+ LL_DEBUGS("AppInit") << "Awaiting AvatarInitComplete, got "
+ << msg->getMessageName() << LL_ENDL;
+ }
+ }
+ msg->processAcks();
+
+ if (gAgentMovementCompleted)
+ {
+ LLStartUp::setStartupState( STATE_INVENTORY_SEND );
+ }
+
+ return FALSE;
+ }
+
+ //---------------------------------------------------------------------
+ // Inventory Send
+ //---------------------------------------------------------------------
+ if (STATE_INVENTORY_SEND == LLStartUp::getStartupState())
+ {
+ // Inform simulator of our language preference
+ LLAgentLanguage::update();
+
+ // unpack thin inventory
+ LLSD response = LLLoginInstance::getInstance()->getResponse();
+ //bool dump_buffer = false;
+
+ LLSD inv_lib_root = response["inventory-lib-root"];
+ if(inv_lib_root.isDefined())
+ {
+ // should only be one
+ LLSD id = inv_lib_root[0]["folder_id"];
+ if(id.isDefined())
+ {
+ gInventory.setLibraryRootFolderID(id.asUUID());
+ }
+ }
+
+ LLSD inv_lib_owner = response["inventory-lib-owner"];
+ if(inv_lib_owner.isDefined())
+ {
+ // should only be one
+ LLSD id = inv_lib_owner[0]["agent_id"];
+ if(id.isDefined())
+ {
+ gInventory.setLibraryOwnerID( LLUUID(id.asUUID()));
+ }
+ }
+
+ LLSD inv_skel_lib = response["inventory-skel-lib"];
+ if(inv_skel_lib.isDefined() && gInventory.getLibraryOwnerID().notNull())
+ {
+ if(!gInventory.loadSkeleton(inv_skel_lib, gInventory.getLibraryOwnerID()))
+ {
+ LL_WARNS("AppInit") << "Problem loading inventory-skel-lib" << LL_ENDL;
+ }
+ }
+
+ LLSD inv_skeleton = response["inventory-skeleton"];
+ if(inv_skeleton.isDefined())
+ {
+ if(!gInventory.loadSkeleton(inv_skeleton, gAgent.getID()))
+ {
+ LL_WARNS("AppInit") << "Problem loading inventory-skel-targets" << LL_ENDL;
+ }
+ }
+
+ LLSD buddy_list = response["buddy-list"];
+ if(buddy_list.isDefined())
+ {
+ LLAvatarTracker::buddy_map_t list;
+ LLUUID agent_id;
+ S32 has_rights = 0, given_rights = 0;
+ for(LLSD::array_const_iterator it = buddy_list.beginArray(),
+ end = buddy_list.endArray(); it != end; ++it)
+ {
+ LLSD buddy_id = (*it)["buddy_id"];
+ if(buddy_id.isDefined())
+ {
+ agent_id = buddy_id.asUUID();
+ }
+
+ LLSD buddy_rights_has = (*it)["buddy_rights_has"];
+ if(buddy_rights_has.isDefined())
+ {
+ has_rights = buddy_rights_has.asInteger();
+ }
+
+ LLSD buddy_rights_given = (*it)["buddy_rights_given"];
+ if(buddy_rights_given.isDefined())
+ {
+ given_rights = buddy_rights_given.asInteger();
+ }
+
+ list[agent_id] = new LLRelationship(given_rights, has_rights, false);
+ }
+ LLAvatarTracker::instance().addBuddyList(list);
+ }
+
+ bool show_hud = false;
+ LLSD tutorial_setting = response["tutorial_setting"];
+ if(tutorial_setting.isDefined())
+ {
+ for(LLSD::array_const_iterator it = tutorial_setting.beginArray(),
+ end = tutorial_setting.endArray(); it != end; ++it)
+ {
+ LLSD tutorial_url = (*it)["tutorial_url"];
+ if(tutorial_url.isDefined())
+ {
+ // Tutorial floater will append language code
+ gSavedSettings.setString("TutorialURL", tutorial_url.asString());
+ }
+
+ // For Viewer 2.0 we are not using the web-based tutorial
+ // If we reverse that decision, put this code back and use
+ // login.cgi to send a different URL with content that matches
+ // the Viewer 2.0 UI.
+ //LLSD use_tutorial = (*it)["use_tutorial"];
+ //if(use_tutorial.asString() == "true")
+ //{
+ // show_hud = true;
+ //}
+ }
+ }
+ // Either we want to show tutorial because this is the first login
+ // to a Linden Help Island or the user quit with the tutorial
+ // visible. JC
+ if (show_hud || gSavedSettings.getBOOL("ShowTutorial"))
+ {
+ LLFloaterReg::showInstance("hud", LLSD(), FALSE);
+ }
+
+ LLSD event_notifications = response["event_notifications"];
+ if(event_notifications.isDefined())
+ {
+ gEventNotifier.load(event_notifications);
+ }
+
+ LLSD classified_categories = response["classified_categories"];
+ if(classified_categories.isDefined())
+ {
+ LLClassifiedInfo::loadCategories(classified_categories);
+ }
+
+ // This method MUST be called before gInventory.findCategoryUUIDForType because of
+ // gInventory.mIsAgentInvUsable is set to true in the gInventory.buildParentChildMap.
+ gInventory.buildParentChildMap();
+
+ //all categories loaded. lets create "My Favorites" category
+ gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE,true);
+
+ // set up callbacks
+ llinfos << "Registering Callbacks" << llendl;
+ LLMessageSystem* msg = gMessageSystem;
+ llinfos << " Inventory" << llendl;
+ LLInventoryModel::registerCallbacks(msg);
+ llinfos << " AvatarTracker" << llendl;
+ LLAvatarTracker::instance().registerCallbacks(msg);
+ llinfos << " Landmark" << llendl;
+ LLLandmark::registerCallbacks(msg);
+
+ // request mute list
+ llinfos << "Requesting Mute List" << llendl;
+ LLMuteList::getInstance()->requestFromServer(gAgent.getID());
+
+ // Get L$ and ownership credit information
+ llinfos << "Requesting Money Balance" << llendl;
+ LLStatusBar::sendMoneyBalanceRequest();
+
+ // request all group information
+ llinfos << "Requesting Agent Data" << llendl;
+ gAgent.sendAgentDataUpdateRequest();
+
+ // Create the inventory views
+ llinfos << "Creating Inventory Views" << llendl;
+ LLFloaterReg::getInstance("inventory");
+
+ LLStartUp::setStartupState( STATE_MISC );
+ return FALSE;
+ }
+
+
+ //---------------------------------------------------------------------
+ // Misc
+ //---------------------------------------------------------------------
+ if (STATE_MISC == LLStartUp::getStartupState())
+ {
+ // We have a region, and just did a big inventory download.
+ // We can estimate the user's connection speed, and set their
+ // max bandwidth accordingly. JC
+ if (gSavedSettings.getBOOL("FirstLoginThisInstall"))
+ {
+ // This is actually a pessimistic computation, because TCP may not have enough
+ // time to ramp up on the (small) default inventory file to truly measure max
+ // bandwidth. JC
+ F64 rate_bps = LLLoginInstance::getInstance()->getLastTransferRateBPS();
+ const F32 FAST_RATE_BPS = 600.f * 1024.f;
+ const F32 FASTER_RATE_BPS = 750.f * 1024.f;
+ F32 max_bandwidth = gViewerThrottle.getMaxBandwidth();
+ if (rate_bps > FASTER_RATE_BPS
+ && rate_bps > max_bandwidth)
+ {
+ LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to "
+ << FASTER_RATE_BPS/1024.f
+ << " kbps" << LL_ENDL;
+ gViewerThrottle.setMaxBandwidth(FASTER_RATE_BPS / 1024.f);
+ }
+ else if (rate_bps > FAST_RATE_BPS
+ && rate_bps > max_bandwidth)
+ {
+ LL_DEBUGS("AppInit") << "Fast network connection, increasing max bandwidth to "
+ << FAST_RATE_BPS/1024.f
+ << " kbps" << LL_ENDL;
+ gViewerThrottle.setMaxBandwidth(FAST_RATE_BPS / 1024.f);
+ }
+
+ // Set the show start location to true, now that the user has logged
+ // on with this install.
+ gSavedSettings.setBOOL("ShowStartLocation", TRUE);
+ }
+
+ // We're successfully logged in.
+ gSavedSettings.setBOOL("FirstLoginThisInstall", FALSE);
+
+ LLFloaterReg::showInitialVisibleInstances();
+
+ // based on the comments, we've successfully logged in so we can delete the 'forced'
+ // URL that the updater set in settings.ini (in a mostly paranoid fashion)
+ std::string nextLoginLocation = gSavedSettings.getString( "NextLoginLocation" );
+ if ( nextLoginLocation.length() )
+ {
+ // clear it
+ gSavedSettings.setString( "NextLoginLocation", "" );
+
+ // and make sure it's saved
+ gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE );
+ LLUIColorTable::instance().saveUserSettings();
+ };
+
+ if (!gNoRender)
+ {
+ // JC: Initializing audio requests many sounds for download.
+ init_audio();
+
+ // JC: Initialize "active" gestures. This may also trigger
+ // many gesture downloads, if this is the user's first
+ // time on this machine or -purge has been run.
+ LLSD gesture_options
+ = LLLoginInstance::getInstance()->getResponse("gestures");
+ if (gesture_options.isDefined())
+ {
+ LL_DEBUGS("AppInit") << "Gesture Manager loading " << gesture_options.size()
+ << LL_ENDL;
+ uuid_vec_t item_ids;
+ for(LLSD::array_const_iterator resp_it = gesture_options.beginArray(),
+ end = gesture_options.endArray(); resp_it != end; ++resp_it)
+ {
+ // If the id is not specifed in the LLSD,
+ // the LLSD operator[]() will return a null LLUUID.
+ LLUUID item_id = (*resp_it)["item_id"];
+ LLUUID asset_id = (*resp_it)["asset_id"];
+
+ if (item_id.notNull() && asset_id.notNull())
+ {
+ // Could schedule and delay these for later.
+ const BOOL no_inform_server = FALSE;
+ const BOOL no_deactivate_similar = FALSE;
+ LLGestureMgr::instance().activateGestureWithAsset(item_id, asset_id,
+ no_inform_server,
+ no_deactivate_similar);
+ // We need to fetch the inventory items for these gestures
+ // so we have the names to populate the UI.
+ item_ids.push_back(item_id);
+ }
+ }
+ // no need to add gesture to inventory observer, it's already made in constructor
+ LLGestureMgr::instance().setFetchIDs(item_ids);
+ LLGestureMgr::instance().startFetch();
+ }
+ }
+ gDisplaySwapBuffers = TRUE;
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->setHandlerFuncFast(_PREHASH_SoundTrigger, process_sound_trigger);
+ msg->setHandlerFuncFast(_PREHASH_PreloadSound, process_preload_sound);
+ msg->setHandlerFuncFast(_PREHASH_AttachedSound, process_attached_sound);
+ msg->setHandlerFuncFast(_PREHASH_AttachedSoundGainChange, process_attached_sound_gain_change);
+
+ LL_DEBUGS("AppInit") << "Initialization complete" << LL_ENDL;
+
+ gRenderStartTime.reset();
+ gForegroundTime.reset();
+
+ // HACK: Inform simulator of window size.
+ // Do this here so it's less likely to race with RegisterNewAgent.
+ // TODO: Put this into RegisterNewAgent
+ // JC - 7/20/2002
+ gViewerWindow->sendShapeToSim();
+
+
+ // Ignore stipend information for now. Money history is on the web site.
+ // if needed, show the L$ history window
+ //if (stipend_since_login && !gNoRender)
+ //{
+ //}
+
+ // The reason we show the alert is because we want to
+ // reduce confusion for when you log in and your provided
+ // location is not your expected location. So, if this is
+ // your first login, then you do not have an expectation,
+ // thus, do not show this alert.
+ if (!gAgent.isFirstLogin())
+ {
+ llinfos << "gAgentStartLocation : " << gAgentStartLocation << llendl;
+ LLSLURL start_slurl = LLStartUp::getStartSLURL();
+
+ if (((start_slurl.getType() == LLSLURL::LOCATION) && (gAgentStartLocation == "url")) ||
+ ((start_slurl.getType() == LLSLURL::LAST_LOCATION) && (gAgentStartLocation == "last")) ||
+ ((start_slurl.getType() == LLSLURL::HOME_LOCATION) && (gAgentStartLocation == "home")))
+ {
+ // Start location is OK
+ // Disabled code to restore camera location and focus if logging in to default location
+ static bool samename = false;
+ if (samename)
+ {
+ // restore old camera pos
+ gAgentCamera.setFocusOnAvatar(FALSE, FALSE);
+ gAgentCamera.setCameraPosAndFocusGlobal(gSavedSettings.getVector3d("CameraPosOnLogout"), gSavedSettings.getVector3d("FocusPosOnLogout"), LLUUID::null);
+ BOOL limit_hit = FALSE;
+ gAgentCamera.calcCameraPositionTargetGlobal(&limit_hit);
+ if (limit_hit)
+ {
+ gAgentCamera.setFocusOnAvatar(TRUE, FALSE);
+ }
+ gAgentCamera.stopCameraAnimation();
+ }
+ }
+ else
+ {
+ std::string msg;
+ switch(start_slurl.getType())
+ {
+ case LLSLURL::LOCATION:
+ {
+
+ msg = "AvatarMovedDesired";
+ break;
+ }
+ case LLSLURL::HOME_LOCATION:
+ {
+ msg = "AvatarMovedHome";
+ break;
+ }
+ default:
+ {
+ msg = "AvatarMovedLast";
+ }
+ }
+ LLNotificationsUtil::add(msg);
+ }
+ }
+
+ //DEV-17797. get null folder. Any items found here moved to Lost and Found
+ LLInventoryModelBackgroundFetch::instance().findLostItems();
+
+ LLStartUp::setStartupState( STATE_PRECACHE );
+ timeout.reset();
+ return FALSE;
+ }
+
+ if (STATE_PRECACHE == LLStartUp::getStartupState())
+ {
+ F32 timeout_frac = timeout.getElapsedTimeF32()/PRECACHING_DELAY;
+
+ // We now have an inventory skeleton, so if this is a user's first
+ // login, we can start setting up their clothing and avatar
+ // appearance. This helps to avoid the generic "Ruth" avatar in
+ // the orientation island tutorial experience. JC
+ if (gAgent.isFirstLogin()
+ && !sInitialOutfit.empty() // registration set up an outfit
+ && !sInitialOutfitGender.empty() // and a gender
+ && isAgentAvatarValid() // can't wear clothes without object
+ && !gAgent.isGenderChosen() ) // nothing already loading
+ {
+ // Start loading the wearables, textures, gestures
+ LLStartUp::loadInitialOutfit( sInitialOutfit, sInitialOutfitGender );
+ }
+
+ // wait precache-delay and for agent's avatar or a lot longer.
+ if(((timeout_frac > 1.f) && isAgentAvatarValid())
+ || (timeout_frac > 3.f))
+ {
+ LLStartUp::setStartupState( STATE_WEARABLES_WAIT );
+ }
+ else
+ {
+ update_texture_fetch();
+ set_startup_status(0.60f + 0.30f * timeout_frac,
+ LLTrans::getString("LoginPrecaching"),
+ gAgent.mMOTD);
+ display_startup();
+ if (!LLViewerShaderMgr::sInitialized)
+ {
+ LLViewerShaderMgr::sInitialized = TRUE;
+ LLViewerShaderMgr::instance()->setShaders();
+ }
+ }
+
+ return TRUE;
+ }
+
+ if (STATE_WEARABLES_WAIT == LLStartUp::getStartupState())
+ {
+ static LLFrameTimer wearables_timer;
+
+ const F32 wearables_time = wearables_timer.getElapsedTimeF32();
+ const F32 MAX_WEARABLES_TIME = 10.f;
+
+ if (!gAgent.isGenderChosen())
+ {
+ // No point in waiting for clothing, we don't even
+ // know what gender we are. Pop a dialog to ask and
+ // proceed to draw the world. JC
+ //
+ // *NOTE: We might hit this case even if we have an
+ // initial outfit, but if the load hasn't started
+ // already then something is wrong so fall back
+ // to generic outfits. JC
+ LLNotificationsUtil::add("WelcomeChooseSex", LLSD(), LLSD(),
+ callback_choose_gender);
+ LLStartUp::setStartupState( STATE_CLEANUP );
+ return TRUE;
+ }
+
+ if (wearables_time > MAX_WEARABLES_TIME)
+ {
+ LLNotificationsUtil::add("ClothingLoading");
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_WEARABLES_TOO_LONG);
+ LLStartUp::setStartupState( STATE_CLEANUP );
+ return TRUE;
+ }
+
+ if (gAgent.isFirstLogin())
+ {
+ // wait for avatar to be completely loaded
+ if (isAgentAvatarValid()
+ && gAgentAvatarp->isFullyLoaded())
+ {
+ //llinfos << "avatar fully loaded" << llendl;
+ LLStartUp::setStartupState( STATE_CLEANUP );
+ return TRUE;
+ }
+ }
+ else
+ {
+ // OK to just get the wearables
+ if ( gAgentWearables.areWearablesLoaded() )
+ {
+ // We have our clothing, proceed.
+ //llinfos << "wearables loaded" << llendl;
+ LLStartUp::setStartupState( STATE_CLEANUP );
+ return TRUE;
+ }
+ }
+
+ update_texture_fetch();
+ set_startup_status(0.9f + 0.1f * wearables_time / MAX_WEARABLES_TIME,
+ LLTrans::getString("LoginDownloadingClothing").c_str(),
+ gAgent.mMOTD.c_str());
+ return TRUE;
+ }
+
+ if (STATE_CLEANUP == LLStartUp::getStartupState())
+ {
+ set_startup_status(1.0, "", "");
+
+ // Let the map know about the inventory.
+ LLFloaterWorldMap* floater_world_map = LLFloaterWorldMap::getInstance();
+ if(floater_world_map)
+ {
+ floater_world_map->observeInventory(&gInventory);
+ floater_world_map->observeFriends();
+ }
+ gViewerWindow->showCursor();
+ gViewerWindow->getWindow()->resetBusyCount();
+ gViewerWindow->getWindow()->setCursor(UI_CURSOR_ARROW);
+ LL_DEBUGS("AppInit") << "Done releasing bitmap" << LL_ENDL;
+ gViewerWindow->setShowProgress(FALSE);
+ gViewerWindow->setProgressCancelButtonVisible(FALSE);
+
+ // We're not away from keyboard, even though login might have taken
+ // a while. JC
+ gAgent.clearAFK();
+
+ // Have the agent start watching the friends list so we can update proxies
+ gAgent.observeFriends();
+ if (gSavedSettings.getBOOL("LoginAsGod"))
+ {
+ gAgent.requestEnterGodMode();
+ }
+
+ // Start automatic replay if the flag is set.
+ if (gSavedSettings.getBOOL("StatsAutoRun") || LLAgentPilot::sReplaySession)
+ {
+ LLUUID id;
+ LL_DEBUGS("AppInit") << "Starting automatic playback" << LL_ENDL;
+ gAgentPilot.startPlayback();
+ }
+
+ show_debug_menus(); // Debug menu visiblity and First Use trigger
+
+ // If we've got a startup URL, dispatch it
+ LLStartUp::dispatchURL();
+
+ // Retrieve information about the land data
+ // (just accessing this the first time will fetch it,
+ // then the data is cached for the viewer's lifetime)
+ LLProductInfoRequestManager::instance();
+
+ // *FIX:Mani - What do I do here?
+ // Need we really clear the Auth response data?
+ // Clean up the userauth stuff.
+ // LLUserAuth::getInstance()->reset();
+
+ LLStartUp::setStartupState( STATE_STARTED );
+
+ // Unmute audio if desired and setup volumes.
+ // Unmute audio if desired and setup volumes.
+ // This is a not-uncommon crash site, so surround it with
+ // llinfos output to aid diagnosis.
+ LL_INFOS("AppInit") << "Doing first audio_update_volume..." << LL_ENDL;
+ audio_update_volume();
+ LL_INFOS("AppInit") << "Done first audio_update_volume." << LL_ENDL;
+
+ // reset keyboard focus to sane state of pointing at world
+ gFocusMgr.setKeyboardFocus(NULL);
+
+#if 0 // sjb: enable for auto-enabling timer display
+ gDebugView->mFastTimerView->setVisible(TRUE);
+#endif
+
+ LLAppViewer::instance()->handleLoginComplete();
+
+ // reset timers now that we are running "logged in" logic
+ LLFastTimer::reset();
+
+ LLAgentPicksInfo::getInstance()->requestNumberOfPicks();
+
+ LLIMFloater::initIMFloater();
+
+ return TRUE;
+ }
+
+ LL_WARNS("AppInit") << "Reached end of idle_startup for state " << LLStartUp::getStartupState() << LL_ENDL;
+ return TRUE;
+}
+
+//
+// local function definition
+//
+
+void login_show()
+{
+ LL_INFOS("AppInit") << "Initializing Login Screen" << LL_ENDL;
+
+#ifdef LL_RELEASE_FOR_DOWNLOAD
+ BOOL bUseDebugLogin = gSavedSettings.getBOOL("UseDebugLogin");
+#else
+ BOOL bUseDebugLogin = TRUE;
+#endif
+
+ LLPanelLogin::show( gViewerWindow->getWindowRectScaled(),
+ bUseDebugLogin || gSavedSettings.getBOOL("SecondLifeEnterprise"),
+ login_callback, NULL );
+
+}
+
+// Callback for when login screen is closed. Option 0 = connect, option 1 = quit.
+void login_callback(S32 option, void *userdata)
+{
+ const S32 CONNECT_OPTION = 0;
+ const S32 QUIT_OPTION = 1;
+
+ if (CONNECT_OPTION == option)
+ {
+ LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
+ return;
+ }
+ else if (QUIT_OPTION == option) // *TODO: THIS CODE SEEMS TO BE UNREACHABLE!!!!! login_callback is never called with option equal to QUIT_OPTION
+ {
+ if (!gSavedSettings.getBOOL("RememberPassword"))
+ {
+ // turn off the setting and write out to disk
+ gSavedSettings.saveToFile( gSavedSettings.getString("ClientSettingsFile") , TRUE );
+ LLUIColorTable::instance().saveUserSettings();
+ }
+
+ // Next iteration through main loop should shut down the app cleanly.
+ LLAppViewer::instance()->userQuit();
+
+ if (LLAppViewer::instance()->quitRequested())
+ {
+ LLPanelLogin::closePanel();
+ }
+ return;
+ }
+ else
+ {
+ LL_WARNS("AppInit") << "Unknown login button clicked" << LL_ENDL;
+ }
+}
+
+void show_first_run_dialog()
+{
+ LLNotificationsUtil::add("FirstRun", LLSD(), LLSD(), first_run_dialog_callback);
+}
+
+bool first_run_dialog_callback(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ LL_DEBUGS("AppInit") << "First run dialog cancelling" << LL_ENDL;
+ LLWeb::loadURLExternal(LLTrans::getString("create_account_url") );
+ }
+
+ LLPanelLogin::giveFocus();
+ return false;
+}
+
+
+
+void set_startup_status(const F32 frac, const std::string& string, const std::string& msg)
+{
+ gViewerWindow->setProgressPercent(frac*100);
+ gViewerWindow->setProgressString(string);
+
+ gViewerWindow->setProgressMessage(msg);
+}
+
+bool login_alert_status(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ // Buttons
+ switch( option )
+ {
+ case 0: // OK
+ break;
+ // case 1: // Help
+ // LLWeb::loadURL(LLNotifications::instance().getGlobalString("SUPPORT_URL") );
+ // break;
+ case 2: // Teleport
+ // Restart the login process, starting at our home locaton
+ LLStartUp::setStartSLURL(LLSLURL(LLSLURL::SIM_LOCATION_HOME));
+ LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
+ break;
+ default:
+ LL_WARNS("AppInit") << "Missing case in login_alert_status switch" << LL_ENDL;
+ }
+
+ LLPanelLogin::giveFocus();
+ return false;
+}
+
+
+void use_circuit_callback(void**, S32 result)
+{
+ // bail if we're quitting.
+ if(LLApp::isExiting()) return;
+ if( !gUseCircuitCallbackCalled )
+ {
+ gUseCircuitCallbackCalled = true;
+ if (result)
+ {
+ // Make sure user knows something bad happened. JC
+ LL_WARNS("AppInit") << "Backing up to login screen!" << LL_ENDL;
+ LLNotificationsUtil::add("LoginPacketNeverReceived", LLSD(), LLSD(), login_alert_status);
+ reset_login();
+ }
+ else
+ {
+ gGotUseCircuitCodeAck = true;
+ }
+ }
+}
+
+void register_viewer_callbacks(LLMessageSystem* msg)
+{
+ msg->setHandlerFuncFast(_PREHASH_LayerData, process_layer_data );
+ msg->setHandlerFuncFast(_PREHASH_ImageData, LLViewerTextureList::receiveImageHeader );
+ msg->setHandlerFuncFast(_PREHASH_ImagePacket, LLViewerTextureList::receiveImagePacket );
+ msg->setHandlerFuncFast(_PREHASH_ObjectUpdate, process_object_update );
+ msg->setHandlerFunc("ObjectUpdateCompressed", process_compressed_object_update );
+ msg->setHandlerFunc("ObjectUpdateCached", process_cached_object_update );
+ msg->setHandlerFuncFast(_PREHASH_ImprovedTerseObjectUpdate, process_terse_object_update_improved );
+ msg->setHandlerFunc("SimStats", process_sim_stats);
+ msg->setHandlerFuncFast(_PREHASH_HealthMessage, process_health_message );
+ msg->setHandlerFuncFast(_PREHASH_EconomyData, process_economy_data);
+ msg->setHandlerFunc("RegionInfo", LLViewerRegion::processRegionInfo);
+
+ msg->setHandlerFuncFast(_PREHASH_ChatFromSimulator, process_chat_from_simulator);
+ msg->setHandlerFuncFast(_PREHASH_KillObject, process_kill_object, NULL);
+ msg->setHandlerFuncFast(_PREHASH_SimulatorViewerTimeMessage, process_time_synch, NULL);
+ msg->setHandlerFuncFast(_PREHASH_EnableSimulator, process_enable_simulator);
+ msg->setHandlerFuncFast(_PREHASH_DisableSimulator, process_disable_simulator);
+ msg->setHandlerFuncFast(_PREHASH_KickUser, process_kick_user, NULL);
+
+ msg->setHandlerFunc("CrossedRegion", process_crossed_region);
+ msg->setHandlerFuncFast(_PREHASH_TeleportFinish, process_teleport_finish);
+
+ msg->setHandlerFuncFast(_PREHASH_AlertMessage, process_alert_message);
+ msg->setHandlerFunc("AgentAlertMessage", process_agent_alert_message);
+ msg->setHandlerFuncFast(_PREHASH_MeanCollisionAlert, process_mean_collision_alert_message, NULL);
+ msg->setHandlerFunc("ViewerFrozenMessage", process_frozen_message);
+
+ msg->setHandlerFuncFast(_PREHASH_NameValuePair, process_name_value);
+ msg->setHandlerFuncFast(_PREHASH_RemoveNameValuePair, process_remove_name_value);
+ msg->setHandlerFuncFast(_PREHASH_AvatarAnimation, process_avatar_animation);
+ msg->setHandlerFuncFast(_PREHASH_AvatarAppearance, process_avatar_appearance);
+ msg->setHandlerFunc("AgentCachedTextureResponse", LLAgent::processAgentCachedTextureResponse);
+ msg->setHandlerFunc("RebakeAvatarTextures", LLVOAvatarSelf::processRebakeAvatarTextures);
+ msg->setHandlerFuncFast(_PREHASH_CameraConstraint, process_camera_constraint);
+ msg->setHandlerFuncFast(_PREHASH_AvatarSitResponse, process_avatar_sit_response);
+ msg->setHandlerFunc("SetFollowCamProperties", process_set_follow_cam_properties);
+ msg->setHandlerFunc("ClearFollowCamProperties", process_clear_follow_cam_properties);
+
+ msg->setHandlerFuncFast(_PREHASH_ImprovedInstantMessage, process_improved_im);
+ msg->setHandlerFuncFast(_PREHASH_ScriptQuestion, process_script_question);
+ msg->setHandlerFuncFast(_PREHASH_ObjectProperties, LLSelectMgr::processObjectProperties, NULL);
+ msg->setHandlerFuncFast(_PREHASH_ObjectPropertiesFamily, LLSelectMgr::processObjectPropertiesFamily, NULL);
+ msg->setHandlerFunc("ForceObjectSelect", LLSelectMgr::processForceObjectSelect);
+
+ msg->setHandlerFuncFast(_PREHASH_MoneyBalanceReply, process_money_balance_reply, NULL);
+ msg->setHandlerFuncFast(_PREHASH_CoarseLocationUpdate, LLWorld::processCoarseUpdate, NULL);
+ msg->setHandlerFuncFast(_PREHASH_ReplyTaskInventory, LLViewerObject::processTaskInv, NULL);
+ msg->setHandlerFuncFast(_PREHASH_DerezContainer, process_derez_container, NULL);
+ msg->setHandlerFuncFast(_PREHASH_ScriptRunningReply,
+ &LLLiveLSLEditor::processScriptRunningReply);
+
+ msg->setHandlerFuncFast(_PREHASH_DeRezAck, process_derez_ack);
+
+ msg->setHandlerFunc("LogoutReply", process_logout_reply);
+
+ //msg->setHandlerFuncFast(_PREHASH_AddModifyAbility,
+ // &LLAgent::processAddModifyAbility);
+ //msg->setHandlerFuncFast(_PREHASH_RemoveModifyAbility,
+ // &LLAgent::processRemoveModifyAbility);
+ msg->setHandlerFuncFast(_PREHASH_AgentDataUpdate,
+ &LLAgent::processAgentDataUpdate);
+ msg->setHandlerFuncFast(_PREHASH_AgentGroupDataUpdate,
+ &LLAgent::processAgentGroupDataUpdate);
+ msg->setHandlerFunc("AgentDropGroup",
+ &LLAgent::processAgentDropGroup);
+ // land ownership messages
+ msg->setHandlerFuncFast(_PREHASH_ParcelOverlay,
+ LLViewerParcelMgr::processParcelOverlay);
+ msg->setHandlerFuncFast(_PREHASH_ParcelProperties,
+ LLViewerParcelMgr::processParcelProperties);
+ msg->setHandlerFunc("ParcelAccessListReply",
+ LLViewerParcelMgr::processParcelAccessListReply);
+ msg->setHandlerFunc("ParcelDwellReply",
+ LLViewerParcelMgr::processParcelDwellReply);
+
+ msg->setHandlerFunc("AvatarPropertiesReply",
+ &LLAvatarPropertiesProcessor::processAvatarPropertiesReply);
+ msg->setHandlerFunc("AvatarInterestsReply",
+ &LLAvatarPropertiesProcessor::processAvatarInterestsReply);
+ msg->setHandlerFunc("AvatarGroupsReply",
+ &LLAvatarPropertiesProcessor::processAvatarGroupsReply);
+ // ratings deprecated
+ //msg->setHandlerFuncFast(_PREHASH_AvatarStatisticsReply,
+ // LLPanelAvatar::processAvatarStatisticsReply);
+ msg->setHandlerFunc("AvatarNotesReply",
+ &LLAvatarPropertiesProcessor::processAvatarNotesReply);
+ msg->setHandlerFunc("AvatarPicksReply",
+ &LLAvatarPropertiesProcessor::processAvatarPicksReply);
+ msg->setHandlerFunc("AvatarClassifiedReply",
+ &LLAvatarPropertiesProcessor::processAvatarClassifiedsReply);
+
+ msg->setHandlerFuncFast(_PREHASH_CreateGroupReply,
+ LLGroupMgr::processCreateGroupReply);
+ msg->setHandlerFuncFast(_PREHASH_JoinGroupReply,
+ LLGroupMgr::processJoinGroupReply);
+ msg->setHandlerFuncFast(_PREHASH_EjectGroupMemberReply,
+ LLGroupMgr::processEjectGroupMemberReply);
+ msg->setHandlerFuncFast(_PREHASH_LeaveGroupReply,
+ LLGroupMgr::processLeaveGroupReply);
+ msg->setHandlerFuncFast(_PREHASH_GroupProfileReply,
+ LLGroupMgr::processGroupPropertiesReply);
+
+ // ratings deprecated
+ // msg->setHandlerFuncFast(_PREHASH_ReputationIndividualReply,
+ // LLFloaterRate::processReputationIndividualReply);
+
+ msg->setHandlerFuncFast(_PREHASH_AgentWearablesUpdate,
+ LLAgentWearables::processAgentInitialWearablesUpdate );
+
+ msg->setHandlerFunc("ScriptControlChange",
+ LLAgent::processScriptControlChange );
+
+ msg->setHandlerFuncFast(_PREHASH_ViewerEffect, LLHUDManager::processViewerEffect);
+
+ msg->setHandlerFuncFast(_PREHASH_GrantGodlikePowers, process_grant_godlike_powers);
+
+ msg->setHandlerFuncFast(_PREHASH_GroupAccountSummaryReply,
+ LLPanelGroupLandMoney::processGroupAccountSummaryReply);
+ msg->setHandlerFuncFast(_PREHASH_GroupAccountDetailsReply,
+ LLPanelGroupLandMoney::processGroupAccountDetailsReply);
+ msg->setHandlerFuncFast(_PREHASH_GroupAccountTransactionsReply,
+ LLPanelGroupLandMoney::processGroupAccountTransactionsReply);
+
+ msg->setHandlerFuncFast(_PREHASH_UserInfoReply,
+ process_user_info_reply);
+
+ msg->setHandlerFunc("RegionHandshake", process_region_handshake, NULL);
+
+ msg->setHandlerFunc("TeleportStart", process_teleport_start );
+ msg->setHandlerFunc("TeleportProgress", process_teleport_progress);
+ msg->setHandlerFunc("TeleportFailed", process_teleport_failed, NULL);
+ msg->setHandlerFunc("TeleportLocal", process_teleport_local, NULL);
+
+ msg->setHandlerFunc("ImageNotInDatabase", LLViewerTextureList::processImageNotInDatabase, NULL);
+
+ msg->setHandlerFuncFast(_PREHASH_GroupMembersReply,
+ LLGroupMgr::processGroupMembersReply);
+ msg->setHandlerFunc("GroupRoleDataReply",
+ LLGroupMgr::processGroupRoleDataReply);
+ msg->setHandlerFunc("GroupRoleMembersReply",
+ LLGroupMgr::processGroupRoleMembersReply);
+ msg->setHandlerFunc("GroupTitlesReply",
+ LLGroupMgr::processGroupTitlesReply);
+ // Special handler as this message is sometimes used for group land.
+ msg->setHandlerFunc("PlacesReply", process_places_reply);
+ msg->setHandlerFunc("GroupNoticesListReply", LLPanelGroupNotices::processGroupNoticesListReply);
+
+ msg->setHandlerFunc("AvatarPickerReply", LLFloaterAvatarPicker::processAvatarPickerReply);
+
+ msg->setHandlerFunc("MapBlockReply", LLWorldMapMessage::processMapBlockReply);
+ msg->setHandlerFunc("MapItemReply", LLWorldMapMessage::processMapItemReply);
+ msg->setHandlerFunc("EventInfoReply", LLEventNotifier::processEventInfoReply);
+
+ msg->setHandlerFunc("PickInfoReply", &LLAvatarPropertiesProcessor::processPickInfoReply);
+// msg->setHandlerFunc("ClassifiedInfoReply", LLPanelClassified::processClassifiedInfoReply);
+ msg->setHandlerFunc("ClassifiedInfoReply", LLAvatarPropertiesProcessor::processClassifiedInfoReply);
+ msg->setHandlerFunc("ParcelInfoReply", LLRemoteParcelInfoProcessor::processParcelInfoReply);
+ msg->setHandlerFunc("ScriptDialog", process_script_dialog);
+ msg->setHandlerFunc("LoadURL", process_load_url);
+ msg->setHandlerFunc("ScriptTeleportRequest", process_script_teleport_request);
+ msg->setHandlerFunc("EstateCovenantReply", process_covenant_reply);
+
+ // calling cards
+ msg->setHandlerFunc("OfferCallingCard", process_offer_callingcard);
+ msg->setHandlerFunc("AcceptCallingCard", process_accept_callingcard);
+ msg->setHandlerFunc("DeclineCallingCard", process_decline_callingcard);
+
+ msg->setHandlerFunc("ParcelObjectOwnersReply", LLPanelLandObjects::processParcelObjectOwnersReply);
+
+ msg->setHandlerFunc("InitiateDownload", process_initiate_download);
+ msg->setHandlerFunc("LandStatReply", LLFloaterTopObjects::handle_land_reply);
+ msg->setHandlerFunc("GenericMessage", process_generic_message);
+
+ msg->setHandlerFuncFast(_PREHASH_FeatureDisabled, process_feature_disabled_message);
+}
+
+void asset_callback_nothing(LLVFS*, const LLUUID&, LLAssetType::EType, void*, S32)
+{
+ // nothing
+}
+
+// *HACK: Must match name in Library or agent inventory
+const std::string ROOT_GESTURES_FOLDER = "Gestures";
+const std::string COMMON_GESTURES_FOLDER = "Common Gestures";
+const std::string MALE_GESTURES_FOLDER = "Male Gestures";
+const std::string FEMALE_GESTURES_FOLDER = "Female Gestures";
+const std::string SPEECH_GESTURES_FOLDER = "Speech Gestures";
+const std::string OTHER_GESTURES_FOLDER = "Other Gestures";
+const S32 OPT_CLOSED_WINDOW = -1;
+const S32 OPT_MALE = 0;
+const S32 OPT_FEMALE = 1;
+const S32 OPT_TRUST_CERT = 0;
+const S32 OPT_CANCEL_TRUST = 1;
+
+bool callback_choose_gender(const LLSD& notification, const LLSD& response)
+{
+
+ // These defaults are returned from the server on login. They are set in login.xml.
+ // If no default is returned from the server, they are retrieved from settings.xml.
+
+ S32 option = LLNotification::getSelectedOption(notification, response);
+ switch(option)
+ {
+ case OPT_MALE:
+ LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultMaleAvatar"), "male" );
+ break;
+
+ case OPT_FEMALE:
+ case OPT_CLOSED_WINDOW:
+ default:
+ LLStartUp::loadInitialOutfit( gSavedSettings.getString("DefaultFemaleAvatar"), "female" );
+ break;
+ }
+ return false;
+}
+
+void LLStartUp::copyLibraryGestures(const std::string& same_gender_gestures)
+{
+ llinfos << "Copying library gestures" << llendl;
+
+ // Copy gestures
+ LLUUID lib_gesture_cat_id =
+ gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE,false,true);
+ if (lib_gesture_cat_id.isNull())
+ {
+ llwarns << "Unable to copy gestures, source category not found" << llendl;
+ }
+ LLUUID dst_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_GESTURE);
+
+ std::vector<std::string> gesture_folders_to_copy;
+ gesture_folders_to_copy.push_back(MALE_GESTURES_FOLDER);
+ gesture_folders_to_copy.push_back(FEMALE_GESTURES_FOLDER);
+ gesture_folders_to_copy.push_back(COMMON_GESTURES_FOLDER);
+ gesture_folders_to_copy.push_back(SPEECH_GESTURES_FOLDER);
+ gesture_folders_to_copy.push_back(OTHER_GESTURES_FOLDER);
+
+ for(std::vector<std::string>::iterator it = gesture_folders_to_copy.begin();
+ it != gesture_folders_to_copy.end();
+ ++it)
+ {
+ std::string& folder_name = *it;
+
+ LLPointer<LLInventoryCallback> cb(NULL);
+
+ if (folder_name == same_gender_gestures ||
+ folder_name == COMMON_GESTURES_FOLDER ||
+ folder_name == OTHER_GESTURES_FOLDER)
+ {
+ cb = new ActivateGestureCallback;
+ }
+
+
+ LLUUID cat_id = findDescendentCategoryIDByName(lib_gesture_cat_id,folder_name);
+ if (cat_id.isNull())
+ {
+ llwarns << "failed to find gesture folder for " << folder_name << llendl;
+ }
+ else
+ {
+ llinfos << "initiating fetch and copy for " << folder_name << " cat_id " << cat_id << llendl;
+ LLAppearanceMgr* app_mgr = LLAppearanceMgr::getInstance();
+ callAfterCategoryFetch(cat_id,
+ boost::bind(&LLAppearanceMgr::shallowCopyCategory,
+ app_mgr,
+ cat_id,
+ dst_id,
+ cb));
+ }
+ }
+}
+
+void LLStartUp::loadInitialOutfit( const std::string& outfit_folder_name,
+ const std::string& gender_name )
+{
+ llinfos << "starting" << llendl;
+
+ // Not going through the processAgentInitialWearables path, so need to set this here.
+ LLAppearanceMgr::instance().setAttachmentInvLinkEnable(true);
+ // Initiate creation of COF, since we're also bypassing that.
+ gInventory.findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT);
+
+ S32 gender = 0;
+ std::string same_gender_gestures;
+ if (gender_name == "male")
+ {
+ gender = OPT_MALE;
+ same_gender_gestures = MALE_GESTURES_FOLDER;
+ }
+ else
+ {
+ gender = OPT_FEMALE;
+ same_gender_gestures = FEMALE_GESTURES_FOLDER;
+ }
+
+ // try to find the outfit - if not there, create some default
+ // wearables.
+ LLUUID cat_id = findDescendentCategoryIDByName(
+ gInventory.getLibraryRootFolderID(),
+ outfit_folder_name);
+ if (cat_id.isNull())
+ {
+ gAgentWearables.createStandardWearables(gender);
+ }
+ else
+ {
+ sWearablesLoadedCon = gAgentWearables.addLoadedCallback(LLStartUp::saveInitialOutfit);
+
+ bool do_copy = true;
+ bool do_append = false;
+ LLViewerInventoryCategory *cat = gInventory.getCategory(cat_id);
+ LLAppearanceMgr::instance().wearInventoryCategory(cat, do_copy, do_append);
+ }
+
+ // Copy gestures
+ copyLibraryGestures(same_gender_gestures);
+
+ // This is really misnamed -- it means we have started loading
+ // an outfit/shape that will give the avatar a gender eventually. JC
+ gAgent.setGenderChosen(TRUE);
+
+}
+
+//static
+void LLStartUp::saveInitialOutfit()
+{
+ if (sInitialOutfit.empty()) return;
+
+ if (sWearablesLoadedCon.connected())
+ {
+ sWearablesLoadedCon.disconnect();
+ }
+ LLAppearanceMgr::getInstance()->makeNewOutfitLinks(sInitialOutfit,false);
+}
+
+std::string& LLStartUp::getInitialOutfitName()
+{
+ return sInitialOutfit;
+}
+
+// Loads a bitmap to display during load
+void init_start_screen(S32 location_id)
+{
+ if (gStartTexture.notNull())
+ {
+ gStartTexture = NULL;
+ LL_INFOS("AppInit") << "re-initializing start screen" << LL_ENDL;
+ }
+
+ LL_DEBUGS("AppInit") << "Loading startup bitmap..." << LL_ENDL;
+
+ std::string temp_str = gDirUtilp->getLindenUserDir() + gDirUtilp->getDirDelimiter();
+
+ if ((S32)START_LOCATION_ID_LAST == location_id)
+ {
+ temp_str += SCREEN_LAST_FILENAME;
+ }
+ else
+ {
+ temp_str += SCREEN_HOME_FILENAME;
+ }
+
+ LLPointer<LLImageBMP> start_image_bmp = new LLImageBMP;
+
+ // Turn off start screen to get around the occasional readback
+ // driver bug
+ if(!gSavedSettings.getBOOL("UseStartScreen"))
+ {
+ LL_INFOS("AppInit") << "Bitmap load disabled" << LL_ENDL;
+ return;
+ }
+ else if(!start_image_bmp->load(temp_str) )
+ {
+ LL_WARNS("AppInit") << "Bitmap load failed" << LL_ENDL;
+ return;
+ }
+
+ gStartImageWidth = start_image_bmp->getWidth();
+ gStartImageHeight = start_image_bmp->getHeight();
+
+ LLPointer<LLImageRaw> raw = new LLImageRaw;
+ if (!start_image_bmp->decode(raw, 0.0f))
+ {
+ LL_WARNS("AppInit") << "Bitmap decode failed" << LL_ENDL;
+ gStartTexture = NULL;
+ return;
+ }
+
+ raw->expandToPowerOfTwo();
+ gStartTexture = LLViewerTextureManager::getLocalTexture(raw.get(), FALSE) ;
+}
+
+
+// frees the bitmap
+void release_start_screen()
+{
+ LL_DEBUGS("AppInit") << "Releasing bitmap..." << LL_ENDL;
+ gStartTexture = NULL;
+}
+
+
+// static
+std::string LLStartUp::startupStateToString(EStartupState state)
+{
+#define RTNENUM(E) case E: return #E
+ switch(state){
+ RTNENUM( STATE_FIRST );
+ RTNENUM( STATE_BROWSER_INIT );
+ RTNENUM( STATE_LOGIN_SHOW );
+ RTNENUM( STATE_LOGIN_WAIT );
+ RTNENUM( STATE_LOGIN_CLEANUP );
+ RTNENUM( STATE_LOGIN_AUTH_INIT );
+ RTNENUM( STATE_LOGIN_CURL_UNSTUCK );
+ RTNENUM( STATE_LOGIN_PROCESS_RESPONSE );
+ RTNENUM( STATE_WORLD_INIT );
+ RTNENUM( STATE_MULTIMEDIA_INIT );
+ RTNENUM( STATE_FONT_INIT );
+ RTNENUM( STATE_SEED_GRANTED_WAIT );
+ RTNENUM( STATE_SEED_CAP_GRANTED );
+ RTNENUM( STATE_WORLD_WAIT );
+ RTNENUM( STATE_AGENT_SEND );
+ RTNENUM( STATE_AGENT_WAIT );
+ RTNENUM( STATE_INVENTORY_SEND );
+ RTNENUM( STATE_MISC );
+ RTNENUM( STATE_PRECACHE );
+ RTNENUM( STATE_WEARABLES_WAIT );
+ RTNENUM( STATE_CLEANUP );
+ RTNENUM( STATE_STARTED );
+ default:
+ return llformat("(state #%d)", state);
+ }
+#undef RTNENUM
+}
+
+// static
+void LLStartUp::setStartupState( EStartupState state )
+{
+ LL_INFOS("AppInit") << "Startup state changing from " <<
+ getStartupStateString() << " to " <<
+ startupStateToString(state) << LL_ENDL;
+ gStartupState = state;
+ postStartupState();
+}
+
+void LLStartUp::postStartupState()
+{
+ LLSD stateInfo;
+ stateInfo["str"] = getStartupStateString();
+ stateInfo["enum"] = gStartupState;
+ sStateWatcher->post(stateInfo);
+}
+
+
+void reset_login()
+{
+ gAgentWearables.cleanup();
+ gAgentCamera.cleanup();
+ gAgent.cleanup();
+ LLWorld::getInstance()->destroyClass();
+
+ LLStartUp::setStartupState( STATE_LOGIN_SHOW );
+
+ if ( gViewerWindow )
+ { // Hide menus and normal buttons
+ gViewerWindow->setNormalControlsVisible( FALSE );
+ gLoginMenuBarView->setVisible( TRUE );
+ gLoginMenuBarView->setEnabled( TRUE );
+ }
+
+ // Hide any other stuff
+ LLFloaterReg::hideVisibleInstances();
+}
+
+//---------------------------------------------------------------------------
+
+// Initialize all plug-ins except the web browser (which was initialized
+// early, before the login screen). JC
+void LLStartUp::multimediaInit()
+{
+ LL_DEBUGS("AppInit") << "Initializing Multimedia...." << LL_ENDL;
+ std::string msg = LLTrans::getString("LoginInitializingMultimedia");
+ set_startup_status(0.42f, msg.c_str(), gAgent.mMOTD.c_str());
+ display_startup();
+
+ // LLViewerMedia::initClass();
+ LLViewerParcelMedia::initClass();
+}
+
+void LLStartUp::fontInit()
+{
+ LL_DEBUGS("AppInit") << "Initializing fonts...." << LL_ENDL;
+ std::string msg = LLTrans::getString("LoginInitializingFonts");
+ set_startup_status(0.45f, msg.c_str(), gAgent.mMOTD.c_str());
+ display_startup();
+
+ LLFontGL::loadDefaultFonts();
+}
+
+void LLStartUp::initNameCache()
+{
+ // Can be called multiple times
+ if ( gCacheName ) return;
+
+ gCacheName = new LLCacheName(gMessageSystem);
+ gCacheName->addObserver(&callback_cache_name);
+ gCacheName->localizeCacheName("waiting", LLTrans::getString("AvatarNameWaiting"));
+ gCacheName->localizeCacheName("nobody", LLTrans::getString("AvatarNameNobody"));
+ gCacheName->localizeCacheName("none", LLTrans::getString("GroupNameNone"));
+ // Load stored cache if possible
+ LLAppViewer::instance()->loadNameCache();
+
+ // Start cache in not-running state until we figure out if we have
+ // capabilities for display name lookup
+ LLAvatarNameCache::initClass(false);
+ LLAvatarNameCache::setUseDisplayNames(gSavedSettings.getBOOL("UseDisplayNames"));
+}
+
+void LLStartUp::cleanupNameCache()
+{
+ LLAvatarNameCache::cleanupClass();
+
+ delete gCacheName;
+ gCacheName = NULL;
+}
+
+bool LLStartUp::dispatchURL()
+{
+ // ok, if we've gotten this far and have a startup URL
+ if (!getStartSLURL().isValid())
+ {
+ return false;
+ }
+ if(getStartSLURL().getType() != LLSLURL::APP)
+ {
+
+ // If we started with a location, but we're already
+ // at that location, don't pop dialogs open.
+ LLVector3 pos = gAgent.getPositionAgent();
+ LLVector3 slurlpos = getStartSLURL().getPosition();
+ F32 dx = pos.mV[VX] - slurlpos.mV[VX];
+ F32 dy = pos.mV[VY] - slurlpos.mV[VY];
+ const F32 SLOP = 2.f; // meters
+
+ if( getStartSLURL().getRegion() != gAgent.getRegion()->getName()
+ || (dx*dx > SLOP*SLOP)
+ || (dy*dy > SLOP*SLOP) )
+ {
+ LLURLDispatcher::dispatch(getStartSLURL().getSLURLString(),
+ NULL, false);
+ }
+ return true;
+ }
+ return false;
+}
+
+void LLStartUp::setStartSLURL(const LLSLURL& slurl)
+{
+ sStartSLURL = slurl;
+ switch(slurl.getType())
+ {
+ case LLSLURL::HOME_LOCATION:
+ {
+ gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_HOME);
+ break;
+ }
+ case LLSLURL::LAST_LOCATION:
+ {
+ gSavedSettings.setString("LoginLocation", LLSLURL::SIM_LOCATION_LAST);
+ break;
+ }
+ default:
+ LLGridManager::getInstance()->setGridChoice(slurl.getGrid());
+ break;
+ }
+}
+
+bool login_alert_done(const LLSD& notification, const LLSD& response)
+{
+ LLPanelLogin::giveFocus();
+ return false;
+}
+
+// parse the certificate information into args for the
+// certificate notifications
+LLSD transform_cert_args(LLPointer<LLCertificate> cert)
+{
+ LLSD args = LLSD::emptyMap();
+ std::string value;
+ LLSD cert_info;
+ cert->getLLSD(cert_info);
+ // convert all of the elements in the cert into
+ // args for the xml dialog, so we have flexability to
+ // display various parts of the cert by only modifying
+ // the cert alert dialog xml.
+ for(LLSD::map_iterator iter = cert_info.beginMap();
+ iter != cert_info.endMap();
+ iter++)
+ {
+ // key usage and extended key usage
+ // are actually arrays, and we want to format them as comma separated
+ // strings, so special case those.
+ LLSDSerialize::toXML(cert_info[iter->first], std::cout);
+ if((iter->first== std::string(CERT_KEY_USAGE)) |
+ (iter->first == std::string(CERT_EXTENDED_KEY_USAGE)))
+ {
+ value = "";
+ LLSD usage = cert_info[iter->first];
+ for (LLSD::array_iterator usage_iter = usage.beginArray();
+ usage_iter != usage.endArray();
+ usage_iter++)
+ {
+
+ if(usage_iter != usage.beginArray())
+ {
+ value += ", ";
+ }
+
+ value += (*usage_iter).asString();
+ }
+
+ }
+ else
+ {
+ value = iter->second.asString();
+ }
+
+ std::string name = iter->first;
+ std::transform(name.begin(), name.end(), name.begin(),
+ (int(*)(int))toupper);
+ args[name.c_str()] = value;
+ }
+ return args;
+}
+
+
+// when we handle a cert error, give focus back to the login panel
+void general_cert_done(const LLSD& notification, const LLSD& response)
+{
+ LLStartUp::setStartupState( STATE_LOGIN_SHOW );
+ LLPanelLogin::giveFocus();
+}
+
+// check to see if the user wants to trust the cert.
+// if they do, add it to the cert store and
+void trust_cert_done(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotification::getSelectedOption(notification, response);
+ switch(option)
+ {
+ case OPT_TRUST_CERT:
+ {
+ LLPointer<LLCertificate> cert = gSecAPIHandler->getCertificate(notification["payload"]["certificate"]);
+ LLPointer<LLCertificateStore> store = gSecAPIHandler->getCertificateStore(gSavedSettings.getString("CertStore"));
+ store->add(cert);
+ store->save();
+ LLStartUp::setStartupState( STATE_LOGIN_CLEANUP );
+ break;
+ }
+ case OPT_CANCEL_TRUST:
+ reset_login();
+ gSavedSettings.setBOOL("AutoLogin", FALSE);
+ LLStartUp::setStartupState( STATE_LOGIN_SHOW );
+ default:
+ LLPanelLogin::giveFocus();
+ break;
+ }
+
+}
+
+void apply_udp_blacklist(const std::string& csv)
+{
+
+ std::string::size_type start = 0;
+ std::string::size_type comma = 0;
+ do
+ {
+ comma = csv.find(",", start);
+ if (comma == std::string::npos)
+ {
+ comma = csv.length();
+ }
+ std::string item(csv, start, comma-start);
+
+ lldebugs << "udp_blacklist " << item << llendl;
+ gMessageSystem->banUdpMessage(item);
+
+ start = comma + 1;
+
+ }
+ while(comma < csv.length());
+
+}
+
+bool process_login_success_response()
+{
+ LLSD response = LLLoginInstance::getInstance()->getResponse();
+
+ std::string text(response["udp_blacklist"]);
+ if(!text.empty())
+ {
+ apply_udp_blacklist(text);
+ }
+
+ // unpack login data needed by the application
+ text = response["agent_id"].asString();
+ if(!text.empty()) gAgentID.set(text);
+ gDebugInfo["AgentID"] = text;
+
+ // Agent id needed for parcel info request in LLUrlEntryParcel
+ // to resolve parcel name.
+ LLUrlEntryParcel::setAgentID(gAgentID);
+
+ text = response["session_id"].asString();
+ if(!text.empty()) gAgentSessionID.set(text);
+ gDebugInfo["SessionID"] = text;
+
+ // Session id needed for parcel info request in LLUrlEntryParcel
+ // to resolve parcel name.
+ LLUrlEntryParcel::setSessionID(gAgentSessionID);
+
+ text = response["secure_session_id"].asString();
+ if(!text.empty()) gAgent.mSecureSessionID.set(text);
+
+ // if the response contains a display name, use that,
+ // otherwise if the response contains a first and/or last name,
+ // use those. Otherwise use the credential identifier
+
+ gDisplayName = "";
+ if (response.has("display_name"))
+ {
+ gDisplayName.assign(response["display_name"].asString());
+ if(!gDisplayName.empty())
+ {
+ // Remove quotes from string. Login.cgi sends these to force
+ // names that look like numbers into strings.
+ LLStringUtil::replaceChar(gDisplayName, '"', ' ');
+ LLStringUtil::trim(gDisplayName);
+ }
+ }
+ if(gDisplayName.empty())
+ {
+ if(response.has("first_name"))
+ {
+ gDisplayName.assign(response["first_name"].asString());
+ LLStringUtil::replaceChar(gDisplayName, '"', ' ');
+ LLStringUtil::trim(gDisplayName);
+ }
+ if(response.has("last_name"))
+ {
+ text.assign(response["last_name"].asString());
+ LLStringUtil::replaceChar(text, '"', ' ');
+ LLStringUtil::trim(text);
+ if(!gDisplayName.empty())
+ {
+ gDisplayName += " ";
+ }
+ gDisplayName += text;
+ }
+ }
+ if(gDisplayName.empty())
+ {
+ gDisplayName.assign(gUserCredential->asString());
+ }
+
+ // this is their actual ability to access content
+ text = response["agent_access_max"].asString();
+ if (!text.empty())
+ {
+ // agent_access can be 'A', 'M', and 'PG'.
+ gAgent.setMaturity(text[0]);
+ }
+
+ // this is the value of their preference setting for that content
+ // which will always be <= agent_access_max
+ text = response["agent_region_access"].asString();
+ if (!text.empty())
+ {
+ U32 preferredMaturity = (U32)LLAgent::convertTextToMaturity(text[0]);
+
+ gSavedSettings.setU32("PreferredMaturity", preferredMaturity);
+ }
+ // During the AO transition, this flag will be true. Then the flag will
+ // go away. After the AO transition, this code and all the code that
+ // uses it can be deleted.
+ text = response["ao_transition"].asString();
+ if (!text.empty())
+ {
+ if (text == "1")
+ {
+ gAgent.setAOTransition();
+ }
+ }
+
+ text = response["start_location"].asString();
+ if(!text.empty())
+ {
+ gAgentStartLocation.assign(text);
+ }
+
+ text = response["circuit_code"].asString();
+ if(!text.empty())
+ {
+ gMessageSystem->mOurCircuitCode = strtoul(text.c_str(), NULL, 10);
+ }
+ std::string sim_ip_str = response["sim_ip"];
+ std::string sim_port_str = response["sim_port"];
+ if(!sim_ip_str.empty() && !sim_port_str.empty())
+ {
+ U32 sim_port = strtoul(sim_port_str.c_str(), NULL, 10);
+ gFirstSim.set(sim_ip_str, sim_port);
+ if (gFirstSim.isOk())
+ {
+ gMessageSystem->enableCircuit(gFirstSim, TRUE);
+ }
+ }
+ std::string region_x_str = response["region_x"];
+ std::string region_y_str = response["region_y"];
+ if(!region_x_str.empty() && !region_y_str.empty())
+ {
+ U32 region_x = strtoul(region_x_str.c_str(), NULL, 10);
+ U32 region_y = strtoul(region_y_str.c_str(), NULL, 10);
+ gFirstSimHandle = to_region_handle(region_x, region_y);
+ }
+
+ const std::string look_at_str = response["look_at"];
+ if (!look_at_str.empty())
+ {
+ size_t len = look_at_str.size();
+ LLMemoryStream mstr((U8*)look_at_str.c_str(), len);
+ LLSD sd = LLSDSerialize::fromNotation(mstr, len);
+ gAgentStartLookAt = ll_vector3_from_sd(sd);
+ }
+
+ text = response["seed_capability"].asString();
+ if (!text.empty()) gFirstSimSeedCap = text;
+
+ text = response["seconds_since_epoch"].asString();
+ if(!text.empty())
+ {
+ U32 server_utc_time = strtoul(text.c_str(), NULL, 10);
+ if(server_utc_time)
+ {
+ time_t now = time(NULL);
+ gUTCOffset = (server_utc_time - now);
+ }
+ }
+
+ // this is the base used to construct help URLs
+ text = response["help_url_format"].asString();
+ if (!text.empty())
+ {
+ // replace the default help URL format
+ gSavedSettings.setString("HelpURLFormat",text);
+
+ // don't fall back to Standalone's pre-connection static help
+ gSavedSettings.setBOOL("HelpUseLocal", false);
+ }
+
+ std::string home_location = response["home"];
+ if(!home_location.empty())
+ {
+ size_t len = home_location.size();
+ LLMemoryStream mstr((U8*)home_location.c_str(), len);
+ LLSD sd = LLSDSerialize::fromNotation(mstr, len);
+ S32 region_x = sd["region_handle"][0].asInteger();
+ S32 region_y = sd["region_handle"][1].asInteger();
+ U64 region_handle = to_region_handle(region_x, region_y);
+ LLVector3 position = ll_vector3_from_sd(sd["position"]);
+ gAgent.setHomePosRegion(region_handle, position);
+ }
+
+ gAgent.mMOTD.assign(response["message"]);
+
+ // Options...
+ // Each 'option' is an array of submaps.
+ // It appears that we only ever use the first element of the array.
+ LLUUID inv_root_folder_id = response["inventory-root"][0]["folder_id"];
+ if(inv_root_folder_id.notNull())
+ {
+ gInventory.setRootFolderID(inv_root_folder_id);
+ //gInventory.mock(gAgent.getInventoryRootID());
+ }
+
+ LLSD login_flags = response["login-flags"][0];
+ if(login_flags.size())
+ {
+ std::string flag = login_flags["ever_logged_in"];
+ if(!flag.empty())
+ {
+ gAgent.setFirstLogin((flag == "N") ? TRUE : FALSE);
+ }
+
+ /* Flag is currently ignored by the viewer.
+ flag = login_flags["stipend_since_login"];
+ if(flag == "Y")
+ {
+ stipend_since_login = true;
+ }
+ */
+
+ flag = login_flags["gendered"].asString();
+ if(flag == "Y")
+ {
+ gAgent.setGenderChosen(TRUE);
+ }
+
+ bool pacific_daylight_time = false;
+ flag = login_flags["daylight_savings"].asString();
+ if(flag == "Y")
+ {
+ pacific_daylight_time = (flag == "Y");
+ }
+
+ //setup map of datetime strings to codes and slt & local time offset from utc
+ LLStringOps::setupDatetimeInfo(pacific_daylight_time);
+ }
+
+ // set up the voice configuration. Ultimately, we should pass this up as part of each voice
+ // channel if we need to move to multiple voice servers per grid.
+ LLSD voice_config_info = response["voice-config"];
+ if(voice_config_info.has("VoiceServerType"))
+ {
+ gSavedSettings.setString("VoiceServerType", voice_config_info["VoiceServerType"].asString());
+ }
+
+ // Request the map server url
+ std::string map_server_url = response["map-server-url"];
+ if(!map_server_url.empty())
+ {
+ // We got an answer from the grid -> use that for map for the current session
+ gSavedSettings.setString("CurrentMapServerURL", map_server_url);
+ LL_INFOS("LLStartup") << "map-server-url : we got an answer from the grid : " << map_server_url << LL_ENDL;
+ }
+ else
+ {
+ // No answer from the grid -> use the default setting for current session
+ map_server_url = gSavedSettings.getString("MapServerURL");
+ gSavedSettings.setString("CurrentMapServerURL", map_server_url);
+ LL_INFOS("LLStartup") << "map-server-url : no map-server-url answer, we use the default setting for the map : " << map_server_url << LL_ENDL;
+ }
+
+ // Default male and female avatars allowing the user to choose their avatar on first login.
+ // These may be passed up by SLE to allow choice of enterprise avatars instead of the standard
+ // "new ruth." Not to be confused with 'initial-outfit' below
+ LLSD newuser_config = response["newuser-config"][0];
+ if(newuser_config.has("DefaultFemaleAvatar"))
+ {
+ gSavedSettings.setString("DefaultFemaleAvatar", newuser_config["DefaultFemaleAvatar"].asString());
+ }
+ if(newuser_config.has("DefaultMaleAvatar"))
+ {
+ gSavedSettings.setString("DefaultMaleAvatar", newuser_config["DefaultMaleAvatar"].asString());
+ }
+
+ // Initial outfit for the user.
+ // QUESTION: Why can't we simply simply set the users outfit directly
+ // from a web page into the user info on the server? - Roxie
+ LLSD initial_outfit = response["initial-outfit"][0];
+ if(initial_outfit.size())
+ {
+ std::string flag = initial_outfit["folder_name"];
+ if(!flag.empty())
+ {
+ // Initial outfit is a folder in your inventory,
+ // must be an exact folder-name match.
+ sInitialOutfit = flag;
+ }
+
+ flag = initial_outfit["gender"].asString();
+ if(!flag.empty())
+ {
+ sInitialOutfitGender = flag;
+ }
+ }
+
+ LLSD global_textures = response["global-textures"][0];
+ if(global_textures.size())
+ {
+ // Extract sun and moon texture IDs. These are used
+ // in the LLVOSky constructor, but I can't figure out
+ // how to pass them in. JC
+ LLUUID id = global_textures["sun_texture_id"];
+ if(id.notNull())
+ {
+ gSunTextureID = id;
+ }
+
+ id = global_textures["moon_texture_id"];
+ if(id.notNull())
+ {
+ gMoonTextureID = id;
+ }
+
+ id = global_textures["cloud_texture_id"];
+ if(id.notNull())
+ {
+ gCloudTextureID = id;
+ }
+ }
+
+ // Set the location of the snapshot sharing config endpoint
+ std::string snapshot_config_url = response["snapshot_config_url"];
+ if(!snapshot_config_url.empty())
+ {
+ gSavedSettings.setString("SnapshotConfigURL", snapshot_config_url);
+ }
+
+ // Start the process of fetching the OpenID session cookie for this user login
+ std::string openid_url = response["openid_url"];
+ if(!openid_url.empty())
+ {
+ std::string openid_token = response["openid_token"];
+ LLViewerMedia::openIDSetup(openid_url, openid_token);
+ }
+
+ if(response.has("max-agent-groups")) {
+ std::string max_agent_groups(response["max-agent-groups"]);
+ gMaxAgentGroups = atoi(max_agent_groups.c_str());
+ LL_INFOS("LLStartup") << "gMaxAgentGroups read from login.cgi: "
+ << gMaxAgentGroups << LL_ENDL;
+ }
+ else {
+ gMaxAgentGroups = DEFAULT_MAX_AGENT_GROUPS;
+ LL_INFOS("LLStartup") << "using gMaxAgentGroups default: "
+ << gMaxAgentGroups << LL_ENDL;
+ }
+
+ bool success = false;
+ // JC: gesture loading done below, when we have an asset system
+ // in place. Don't delete/clear gUserCredentials until then.
+ if(gAgentID.notNull()
+ && gAgentSessionID.notNull()
+ && gMessageSystem->mOurCircuitCode
+ && gFirstSim.isOk()
+ && gInventory.getRootFolderID().notNull())
+ {
+ success = true;
+ }
+
+ return success;
+}
+
+void transition_back_to_login_panel(const std::string& emsg)
+{
+ if (gNoRender)
+ {
+ LL_WARNS("AppInit") << "Failed to login!" << LL_ENDL;
+ LL_WARNS("AppInit") << emsg << LL_ENDL;
+ exit(0);
+ }
+
+ // Bounce back to the login screen.
+ reset_login(); // calls LLStartUp::setStartupState( STATE_LOGIN_SHOW );
+ gSavedSettings.setBOOL("AutoLogin", FALSE);
+}
diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp
index f54214b95c..7fb52c1939 100644
--- a/indra/newview/lltexturecache.cpp
+++ b/indra/newview/lltexturecache.cpp
@@ -1419,22 +1419,21 @@ void LLTextureCache::readHeaderCache()
}
}
}
- if (num_entries > sCacheMaxEntries)
+ if (num_entries - empty_entries > sCacheMaxEntries)
{
// Special case: cache size was reduced, need to remove entries
// Note: After we prune entries, we will call this again and create the LRU
- U32 entries_to_purge = (num_entries-empty_entries) - sCacheMaxEntries;
+ U32 entries_to_purge = (num_entries - empty_entries) - sCacheMaxEntries;
llinfos << "Texture Cache Entries: " << num_entries << " Max: " << sCacheMaxEntries << " Empty: " << empty_entries << " Purging: " << entries_to_purge << llendl;
- if (entries_to_purge > 0)
+ // We can exit the following loop with the given condition, since if we'd reach the end of the lru set we'd have:
+ // purge_list.size() = lru.size() = num_entries - empty_entries = entries_to_purge + sCacheMaxEntries >= entries_to_purge
+ // So, it's certain that iter will never reach lru.end() first.
+ std::set<lru_data_t>::iterator iter = lru.begin();
+ while (purge_list.size() < entries_to_purge)
{
- for (std::set<lru_data_t>::iterator iter = lru.begin(); iter != lru.end(); ++iter)
- {
- purge_list.insert(iter->second);
- if (purge_list.size() >= entries_to_purge)
- break;
- }
+ purge_list.insert(iter->second);
+ ++iter;
}
- llassert_always(purge_list.size() >= entries_to_purge);
}
else
{
diff --git a/indra/newview/lltoast.cpp b/indra/newview/lltoast.cpp
index fd5582d6f7..e0b07ed408 100644
--- a/indra/newview/lltoast.cpp
+++ b/indra/newview/lltoast.cpp
@@ -99,7 +99,6 @@ LLToast::Params::Params()
LLToast::LLToast(const LLToast::Params& p)
: LLModalDialog(LLSD(), p.is_modal),
- mPanel(p.panel),
mToastLifetime(p.lifetime_secs),
mToastFadingTime(p.fading_time_secs),
mNotificationID(p.notif_id),
@@ -108,6 +107,7 @@ LLToast::LLToast(const LLToast::Params& p)
mCanBeStored(p.can_be_stored),
mHideBtnEnabled(p.enable_hide_btn),
mHideBtn(NULL),
+ mPanel(NULL),
mNotification(p.notification),
mIsHidden(false),
mHideBtnPressed(false),
@@ -128,9 +128,9 @@ LLToast::LLToast(const LLToast::Params& p)
setBackgroundOpaque(TRUE); // *TODO: obsolete
updateTransparency();
- if(mPanel)
+ if(p.panel())
{
- insertPanel(mPanel);
+ insertPanel(p.panel);
}
if(mHideBtnEnabled)
@@ -309,6 +309,7 @@ void LLToast::reshapeToPanel()
void LLToast::insertPanel(LLPanel* panel)
{
+ mPanel = panel;
mWrapperPanel->addChild(panel);
reshapeToPanel();
}
diff --git a/indra/newview/lltoolpie.cpp b/indra/newview/lltoolpie.cpp
index 562b9219b4..582f50ba37 100644
--- a/indra/newview/lltoolpie.cpp
+++ b/indra/newview/lltoolpie.cpp
@@ -79,8 +79,11 @@ static ECursorType cursor_from_parcel_media(U8 click_action);
LLToolPie::LLToolPie()
: LLTool(std::string("Pie")),
- mGrabMouseButtonDown( FALSE ),
- mMouseOutsideSlop( FALSE ),
+ mMouseButtonDown( false ),
+ mMouseOutsideSlop( false ),
+ mMouseSteerX(-1),
+ mMouseSteerY(-1),
+ mAbortClickToWalk(false),
mClickAction(0),
mClickActionBuyEnabled( gSavedSettings.getBOOL("ClickActionBuyEnabled") ),
mClickActionPayEnabled( gSavedSettings.getBOOL("ClickActionPayEnabled") )
@@ -99,12 +102,17 @@ BOOL LLToolPie::handleAnyMouseClick(S32 x, S32 y, MASK mask, EClickType clicktyp
BOOL LLToolPie::handleMouseDown(S32 x, S32 y, MASK mask)
{
+ mMouseOutsideSlop = FALSE;
+ mMouseDownX = x;
+ mMouseDownY = y;
+
//left mouse down always picks transparent
mPick = gViewerWindow->pickImmediate(x, y, TRUE);
mPick.mKeyMask = mask;
- mGrabMouseButtonDown = TRUE;
+
+ mMouseButtonDown = true;
- pickLeftMouseDownCallback();
+ handleLeftClickPick();
return TRUE;
}
@@ -119,7 +127,7 @@ BOOL LLToolPie::handleRightMouseDown(S32 x, S32 y, MASK mask)
// claim not handled so UI focus stays same
- pickRightMouseDownCallback();
+ handleRightClickPick();
return FALSE;
}
@@ -136,7 +144,7 @@ BOOL LLToolPie::handleScrollWheel(S32 x, S32 y, S32 clicks)
}
// True if you selected an object.
-BOOL LLToolPie::pickLeftMouseDownCallback()
+BOOL LLToolPie::handleLeftClickPick()
{
S32 x = mPick.mMousePt.mX;
S32 y = mPick.mMousePt.mY;
@@ -292,7 +300,12 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
}
// put focus back "in world"
- gFocusMgr.setKeyboardFocus(NULL);
+ if (gFocusMgr.getKeyboardFocus())
+ {
+ // don't click to walk on attempt to give focus to world
+ mAbortClickToWalk = true;
+ gFocusMgr.setKeyboardFocus(NULL);
+ }
BOOL touchable = (object && object->flagHandleTouch())
|| (parent && parent->flagHandleTouch());
@@ -304,6 +317,7 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
)
{
gGrabTransientTool = this;
+ mMouseButtonDown = false;
LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolGrab::getInstance() );
return LLToolGrab::getInstance()->handleObjectHit( mPick );
}
@@ -319,9 +333,9 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
if (!gSavedSettings.getBOOL("LeftClickShowMenu"))
{
// mouse already released
- if (!mGrabMouseButtonDown)
+ if (!mMouseButtonDown)
{
- return TRUE;
+ return true;
}
while( object && object->isAttachment() && !object->flagHandleTouch())
@@ -333,9 +347,10 @@ BOOL LLToolPie::pickLeftMouseDownCallback()
}
object = (LLViewerObject*)object->getParent();
}
- if (object && object == gAgentAvatarp)
+ if (object && object == gAgentAvatarp && !gSavedSettings.getBOOL("ClickToWalk"))
{
// we left clicked on avatar, switch to focus mode
+ mMouseButtonDown = false;
LLToolMgr::getInstance()->setTransientTool(LLToolCamera::getInstance());
gViewerWindow->hideCursor();
LLToolCamera::getInstance()->setMouseCapture(TRUE);
@@ -513,7 +528,28 @@ void LLToolPie::selectionPropertiesReceived()
BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
{
+ if (!mMouseOutsideSlop
+ && mMouseButtonDown
+ && gSavedSettings.getBOOL("ClickToWalk"))
+ {
+ S32 delta_x = x - mMouseDownX;
+ S32 delta_y = y - mMouseDownY;
+ S32 threshold = gSavedSettings.getS32("DragAndDropDistanceThreshold");
+ if (delta_x * delta_x + delta_y * delta_y > threshold * threshold)
+ {
+ startCameraSteering();
+ }
+ }
+
mHoverPick = gViewerWindow->pickImmediate(x, y, FALSE);
+
+ if (inCameraSteerMode())
+ {
+ steerCameraWithMouse(x, y);
+ gViewerWindow->setCursor(UI_CURSOR_TOOLGRAB);
+ return TRUE;
+ }
+
// perform a separate pick that detects transparent objects since they respond to 1-click actions
LLPickInfo click_action_pick = gViewerWindow->pickImmediate(x, y, TRUE);
@@ -584,39 +620,62 @@ BOOL LLToolPie::handleHover(S32 x, S32 y, MASK mask)
BOOL LLToolPie::handleMouseUp(S32 x, S32 y, MASK mask)
{
LLViewerObject* obj = mPick.getObject();
-
- handleMediaMouseUp();
-
U8 click_action = final_click_action(obj);
- if (click_action != CLICK_ACTION_NONE)
+
+ // let media have first pass at click
+ if (handleMediaMouseUp() || LLViewerMediaFocus::getInstance()->getFocus())
+ {
+ mAbortClickToWalk = true;
+ }
+ stopCameraSteering();
+ mMouseButtonDown = false;
+
+ if (click_action == CLICK_ACTION_NONE // not doing 1-click action
+ && gSavedSettings.getBOOL("ClickToWalk") // click to walk enabled
+ && !gAgent.getFlying() // don't auto-navigate while flying until that works
+ && !mAbortClickToWalk // another behavior hasn't cancelled click to walk
+ && !mPick.mPosGlobal.isExactlyZero() // valid coordinates for pick
+ && (mPick.mPickType == LLPickInfo::PICK_LAND // we clicked on land
+ || mPick.mObjectID.notNull())) // or on an object
{
- switch(click_action)
+ // handle special cases of steering picks
+ LLViewerObject* avatar_object = mPick.getObject();
+
+ // get pointer to avatar
+ while (avatar_object && !avatar_object->isAvatar())
{
- // NOTE: mClickActionBuyEnabled flag enables/disables BUY action but setting cursor to default is okay
- case CLICK_ACTION_BUY:
- // NOTE: mClickActionPayEnabled flag enables/disables PAY action but setting cursor to default is okay
- case CLICK_ACTION_PAY:
- case CLICK_ACTION_OPEN:
- case CLICK_ACTION_ZOOM:
- case CLICK_ACTION_PLAY:
- case CLICK_ACTION_OPEN_MEDIA:
- // Because these actions open UI dialogs, we won't change
- // the cursor again until the next hover and GL pick over
- // the world. Keep the cursor an arrow, assuming that
- // after the user moves off the UI, they won't be on the
- // same object anymore.
- gViewerWindow->setCursor(UI_CURSOR_ARROW);
- // Make sure the hover-picked object is ignored.
- //gToolTipView->resetLastHoverObject();
- break;
- default:
- break;
+ avatar_object = (LLViewerObject*)avatar_object->getParent();
+ }
+
+ if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
+ {
+ const F64 SELF_CLICK_WALK_DISTANCE = 3.0;
+ // pretend we picked some point a bit in front of avatar
+ mPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * SELF_CLICK_WALK_DISTANCE;
}
+ gAgentCamera.setFocusOnAvatar(TRUE, TRUE);
+ if(mAutoPilotDestination) { mAutoPilotDestination->markDead(); }
+ mAutoPilotDestination = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
+ mAutoPilotDestination->setPositionGlobal(mPick.mPosGlobal);
+ mAutoPilotDestination->setPixelSize(5);
+ mAutoPilotDestination->setColor(LLColor4U(50, 50, 200));
+ mAutoPilotDestination->setDuration(3.f);
+
+ handle_go_to();
+ mAbortClickToWalk = false;
+
+ return TRUE;
+ }
+ gViewerWindow->setCursor(UI_CURSOR_ARROW);
+ if (hasMouseCapture())
+ {
+ setMouseCapture(FALSE);
}
- mGrabMouseButtonDown = FALSE;
LLToolMgr::getInstance()->clearTransientTool();
gAgentCamera.setLookAt(LOOKAT_TARGET_CONVERSATION, obj); // maybe look at object/person clicked on
+
+ mAbortClickToWalk = false;
return LLTool::handleMouseUp(x, y, mask);
}
@@ -936,7 +995,7 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
p.click_callback(boost::bind(showAvatarInspector, hover_object->getID()));
p.visible_time_near(6.f);
p.visible_time_far(3.f);
- p.delay_time(0.35f);
+ p.delay_time(gSavedSettings.getF32("AvatarInspectorTooltipDelay"));
p.wrap(false);
LLToolTipMgr::instance().show(p);
@@ -1054,7 +1113,7 @@ BOOL LLToolPie::handleTooltipObject( LLViewerObject* hover_object, std::string l
p.click_homepage_callback(boost::bind(VisitHomePage, mHoverPick));
p.visible_time_near(6.f);
p.visible_time_far(3.f);
- p.delay_time(0.35f);
+ p.delay_time(gSavedSettings.getF32("ObjectInspectorTooltipDelay"));
p.wrap(false);
LLToolTipMgr::instance().show(p);
@@ -1237,6 +1296,10 @@ void LLToolPie::VisitHomePage(const LLPickInfo& info)
}
}
+void LLToolPie::handleSelect()
+{
+ mAbortClickToWalk = true;
+}
void LLToolPie::handleDeselect()
{
@@ -1275,10 +1338,20 @@ void LLToolPie::stopEditing()
void LLToolPie::onMouseCaptureLost()
{
- mMouseOutsideSlop = FALSE;
+ stopCameraSteering();
+ mMouseButtonDown = false;
handleMediaMouseUp();
}
+void LLToolPie::stopCameraSteering()
+{
+ mMouseOutsideSlop = false;
+}
+
+bool LLToolPie::inCameraSteerMode()
+{
+ return mMouseButtonDown && mMouseOutsideSlop && gSavedSettings.getBOOL("ClickToWalk");
+}
// true if x,y outside small box around start_x,start_y
BOOL LLToolPie::outsideSlop(S32 x, S32 y, S32 start_x, S32 start_y)
@@ -1444,8 +1517,6 @@ bool LLToolPie::handleMediaMouseUp()
mMediaMouseCaptureID.setNull();
- setMouseCapture(FALSE);
-
result = true;
}
@@ -1508,7 +1579,7 @@ static ECursorType cursor_from_parcel_media(U8 click_action)
// True if we handled the event.
-BOOL LLToolPie::pickRightMouseDownCallback()
+BOOL LLToolPie::handleRightClickPick()
{
S32 x = mPick.mMousePt.mX;
S32 y = mPick.mMousePt.mY;
@@ -1630,10 +1701,148 @@ BOOL LLToolPie::pickRightMouseDownCallback()
void LLToolPie::showVisualContextMenuEffect()
{
- // VEFFECT: ShowPie
- LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE);
- effectp->setPositionGlobal(mPick.mPosGlobal);
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- effectp->setDuration(0.25f);
+ // VEFFECT: ShowPie
+ LLHUDEffectSpiral *effectp = (LLHUDEffectSpiral *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_SPHERE, TRUE);
+ effectp->setPositionGlobal(mPick.mPosGlobal);
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ effectp->setDuration(0.25f);
+}
+
+
+bool intersect_ray_with_sphere( const LLVector3& ray_pt, const LLVector3& ray_dir, const LLVector3& sphere_center, F32 sphere_radius, LLVector3& intersection_pt)
+{
+ // do ray/sphere intersection by solving quadratic equation
+ LLVector3 sphere_to_ray_start_vec = ray_pt - sphere_center;
+ F32 B = 2.f * ray_dir * sphere_to_ray_start_vec;
+ F32 C = sphere_to_ray_start_vec.lengthSquared() - (sphere_radius * sphere_radius);
+
+ F32 discriminant = B*B - 4.f*C;
+ if (discriminant > 0.f)
+ { // intersection detected, now find closest one
+ F32 t0 = (-B - sqrtf(discriminant)) / 2.f;
+ if (t0 > 0.f)
+ {
+ intersection_pt = ray_pt + ray_dir * t0;
+ }
+ else
+ {
+ F32 t1 = (-B + sqrtf(discriminant)) / 2.f;
+ intersection_pt = ray_pt + ray_dir * t1;
+ }
+ return true;
+ }
+
+ return false;
+}
+
+void LLToolPie::startCameraSteering()
+{
+ mMouseOutsideSlop = true;
+ mAbortClickToWalk = true;
+ if (gAgentCamera.getFocusOnAvatar())
+ {
+ mSteerPick = mPick;
+
+ // handle special cases of steering picks
+ LLViewerObject* avatar_object = mSteerPick.getObject();
+
+ // get pointer to avatar
+ while (avatar_object && !avatar_object->isAvatar())
+ {
+ avatar_object = (LLViewerObject*)avatar_object->getParent();
+ }
+
+ // if clicking on own avatar...
+ if (avatar_object && ((LLVOAvatar*)avatar_object)->isSelf())
+ {
+ // ...project pick point a few meters in front of avatar
+ mSteerPick.mPosGlobal = gAgent.getPositionGlobal() + LLVector3d(LLViewerCamera::instance().getAtAxis()) * 3.0;
+ }
+
+ if (!mSteerPick.isValid())
+ {
+ mSteerPick.mPosGlobal = gAgent.getPosGlobalFromAgent(
+ LLViewerCamera::instance().getOrigin() + gViewerWindow->mouseDirectionGlobal(mSteerPick.mMousePt.mX, mSteerPick.mMousePt.mY) * 100.f);
+ }
+
+ setMouseCapture(TRUE);
+
+ mMouseSteerX = mMouseDownX;
+ mMouseSteerY = mMouseDownY;
+ const LLVector3 camera_to_rotation_center = gAgent.getFrameAgent().getOrigin() - LLViewerCamera::instance().getOrigin();
+ const LLVector3 rotation_center_to_pick = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal) - gAgent.getFrameAgent().getOrigin();
+
+ mClockwise = camera_to_rotation_center * rotation_center_to_pick < 0.f;
+ if (mMouseSteerGrabPoint) { mMouseSteerGrabPoint->markDead(); }
+ mMouseSteerGrabPoint = (LLHUDEffectBlob *)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_BLOB, FALSE);
+ mMouseSteerGrabPoint->setPositionGlobal(mSteerPick.mPosGlobal);
+ mMouseSteerGrabPoint->setColor(LLColor4U(50, 50, 200));
+ mMouseSteerGrabPoint->setPixelSize(5);
+ mMouseSteerGrabPoint->setDuration(2.f);
+ }
+}
+
+void LLToolPie::steerCameraWithMouse(S32 x, S32 y)
+{
+ const F32 MIN_ROTATION_RADIUS_FRACTION = 0.2f;
+
+ const LLVector3 pick_pos = gAgent.getPosAgentFromGlobal(mSteerPick.mPosGlobal);
+ const LLVector3 rotation_center = gAgent.getFrameAgent().getOrigin();
+ // FIXME: get this to work with camera tilt (i.e. sitting on a rotating object)
+ const LLVector3 rotation_up_axis(LLVector3::z_axis);
+
+ LLVector3 object_rotation_center = rotation_center + parallel_component(pick_pos - rotation_center, rotation_up_axis);
+ F32 min_rotation_radius = MIN_ROTATION_RADIUS_FRACTION * dist_vec(rotation_center, LLViewerCamera::instance().getOrigin());;
+ F32 pick_distance_from_rotation_center = llclamp(dist_vec(pick_pos, object_rotation_center), min_rotation_radius, F32_MAX);
+
+ LLVector3 mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(x, y), rotation_up_axis);
+ mouse_ray.normalize();
+
+ LLVector3 old_mouse_ray = orthogonal_component(gViewerWindow->mouseDirectionGlobal(mMouseSteerX, mMouseSteerY), rotation_up_axis);
+ old_mouse_ray.normalize();
+
+ LLVector3 camera_pos = gAgentCamera.getCameraPositionAgent();
+ LLVector3 camera_to_rotation_center = object_rotation_center - camera_pos;
+ LLVector3 adjusted_camera_pos = camera_pos + projected_vec(camera_to_rotation_center, rotation_up_axis);
+ LLVector3 rotation_fwd_axis = LLViewerCamera::instance().getAtAxis() - projected_vec(LLViewerCamera::instance().getAtAxis(), rotation_up_axis);
+ rotation_fwd_axis.normalize();
+ F32 pick_dist = dist_vec(pick_pos, adjusted_camera_pos);
+
+ LLVector3 mouse_on_sphere;
+ bool mouse_hit_sphere = intersect_ray_with_sphere(adjusted_camera_pos + (mouse_ray * pick_dist * 1.1f),
+ -1.f * mouse_ray,
+ object_rotation_center,
+ pick_distance_from_rotation_center,
+ mouse_on_sphere);
+
+ LLVector3 old_mouse_on_sphere;
+ intersect_ray_with_sphere(adjusted_camera_pos + (old_mouse_ray * pick_dist * 1.1f),
+ -1.f * old_mouse_ray,
+ object_rotation_center,
+ pick_distance_from_rotation_center,
+ old_mouse_on_sphere);
+
+ if (mouse_hit_sphere)
+ {
+ // calculate rotation frame in screen space
+ LLVector3 screen_rotation_up_axis = orthogonal_component(rotation_up_axis, LLViewerCamera::instance().getAtAxis());
+ screen_rotation_up_axis.normalize();
+
+ LLVector3 screen_rotation_left_axis = screen_rotation_up_axis % LLViewerCamera::instance().getAtAxis();
+
+ LLVector3 rotation_furthest_pt = object_rotation_center + pick_distance_from_rotation_center * rotation_fwd_axis;
+ F32 mouse_lateral_distance = llclamp(((mouse_on_sphere - rotation_furthest_pt) * screen_rotation_left_axis) / pick_distance_from_rotation_center, -1.f, 1.f);
+ F32 old_mouse_lateral_distance = llclamp(((old_mouse_on_sphere - rotation_furthest_pt) * screen_rotation_left_axis) / pick_distance_from_rotation_center, -1.f, 1.f);
+
+ F32 yaw_angle = asinf(mouse_lateral_distance);
+ F32 old_yaw_angle = asinf(old_mouse_lateral_distance);
+
+ F32 delta_angle = yaw_angle - old_yaw_angle;
+ if (!mClockwise) delta_angle *= -1.f;
+
+ gAgent.yaw(delta_angle);
+ mMouseSteerX = x;
+ mMouseSteerY = y;
+ }
}
diff --git a/indra/newview/lltoolpie.h b/indra/newview/lltoolpie.h
index 77200a1da4..22e77a3159 100644
--- a/indra/newview/lltoolpie.h
+++ b/indra/newview/lltoolpie.h
@@ -30,6 +30,7 @@
#include "lltool.h"
#include "lluuid.h"
#include "llviewerwindow.h" // for LLPickInfo
+#include "llhudeffectblob.h" // for LLPointer<LLHudEffectBlob>, apparently
class LLViewerObject;
class LLObjectSelection;
@@ -56,6 +57,7 @@ public:
virtual void stopEditing();
virtual void onMouseCaptureLost();
+ virtual void handleSelect();
virtual void handleDeselect();
virtual LLTool* getOverrideTool(MASK mask);
@@ -75,8 +77,8 @@ public:
private:
BOOL outsideSlop (S32 x, S32 y, S32 start_x, S32 start_y);
- BOOL pickLeftMouseDownCallback();
- BOOL pickRightMouseDownCallback();
+ BOOL handleLeftClickPick();
+ BOOL handleRightClickPick();
BOOL useClickAction (MASK mask, LLViewerObject* object,LLViewerObject* parent);
void showVisualContextMenuEffect();
@@ -88,12 +90,26 @@ private:
BOOL handleTooltipLand(std::string line, std::string tooltip_msg);
BOOL handleTooltipObject( LLViewerObject* hover_object, std::string line, std::string tooltip_msg);
+ void steerCameraWithMouse(S32 x, S32 y);
+ void startCameraSteering();
+ void stopCameraSteering();
+ bool inCameraSteerMode();
+
private:
- BOOL mGrabMouseButtonDown;
- BOOL mMouseOutsideSlop; // for this drag, has mouse moved outside slop region
+ bool mMouseButtonDown;
+ bool mMouseOutsideSlop; // for this drag, has mouse moved outside slop region
+ S32 mMouseDownX;
+ S32 mMouseDownY;
+ S32 mMouseSteerX;
+ S32 mMouseSteerY;
+ LLPointer<LLHUDEffectBlob> mAutoPilotDestination;
+ LLPointer<LLHUDEffectBlob> mMouseSteerGrabPoint;
+ bool mClockwise;
+ bool mAbortClickToWalk;
LLUUID mMediaMouseCaptureID;
LLPickInfo mPick;
LLPickInfo mHoverPick;
+ LLPickInfo mSteerPick;
LLPointer<LLViewerObject> mClickActionObject;
U8 mClickAction;
LLSafeHandle<LLObjectSelection> mLeftClickSelection;
diff --git a/indra/newview/llurldispatcher.cpp b/indra/newview/llurldispatcher.cpp
index bd4d3c2b78..ebbb045f0a 100644
--- a/indra/newview/llurldispatcher.cpp
+++ b/indra/newview/llurldispatcher.cpp
@@ -180,7 +180,7 @@ bool LLURLDispatcherImpl::dispatchRegion(const LLSLURL& slurl, bool right_mouse)
LLWorldMapMessage::getInstance()->sendNamedRegionRequest(slurl.getRegion(),
LLURLDispatcherImpl::regionNameCallback,
slurl.getSLURLString(),
- false); // don't teleport
+ LLUI::sSettingGroups["config"]->getBOOL("SLURLTeleportDirectly")); // don't teleport
return true;
}
diff --git a/indra/newview/llviewermedia.cpp b/indra/newview/llviewermedia.cpp
index 900081b8c6..499165135a 100644
--- a/indra/newview/llviewermedia.cpp
+++ b/indra/newview/llviewermedia.cpp
@@ -59,6 +59,8 @@
#include "lluuid.h"
#include "llkeyboard.h"
#include "llmutelist.h"
+#include "llpanelprofile.h"
+#include "llappviewer.h"
//#include "llfirstuse.h"
#include "llwindow.h"
@@ -292,6 +294,43 @@ public:
};
+class LLViewerMediaWebProfileResponder : public LLHTTPClient::Responder
+{
+LOG_CLASS(LLViewerMediaWebProfileResponder);
+public:
+ LLViewerMediaWebProfileResponder(std::string host)
+ {
+ mHost = host;
+ }
+
+ ~LLViewerMediaWebProfileResponder()
+ {
+ }
+
+ /* virtual */ void completedHeader(U32 status, const std::string& reason, const LLSD& content)
+ {
+ LL_WARNS("MediaAuth") << "status = " << status << ", reason = " << reason << LL_ENDL;
+ LL_WARNS("MediaAuth") << content << LL_ENDL;
+
+ std::string cookie = content["set-cookie"].asString();
+
+ LLViewerMedia::getCookieStore()->setCookiesFromHost(cookie, mHost);
+ }
+
+ void completedRaw(
+ U32 status,
+ const std::string& reason,
+ const LLChannelDescriptors& channels,
+ const LLIOPipe::buffer_ptr_t& buffer)
+ {
+ // This is just here to disable the default behavior (attempting to parse the response as llsd).
+ // We don't care about the content of the response, only the set-cookie header.
+ }
+
+ std::string mHost;
+};
+
+
LLPluginCookieStore *LLViewerMedia::sCookieStore = NULL;
LLURL LLViewerMedia::sOpenIDURL;
std::string LLViewerMedia::sOpenIDCookie;
@@ -1351,6 +1390,19 @@ void LLViewerMedia::setOpenIDCookie()
// *HACK: Doing this here is nasty, find a better way.
LLWebSharing::instance().setOpenIDCookie(sOpenIDCookie);
+
+ // Do a web profile get so we can store the cookie
+ LLSD headers = LLSD::emptyMap();
+ headers["Accept"] = "*/*";
+ headers["Cookie"] = sOpenIDCookie;
+ headers["User-Agent"] = getCurrentUserAgent();
+
+ std::string profile_url = getProfileURL("");
+ LLURL raw_profile_url( profile_url.c_str() );
+
+ LLHTTPClient::get(profile_url,
+ new LLViewerMediaWebProfileResponder(raw_profile_url.getAuthority()),
+ headers);
}
}
@@ -1833,17 +1885,12 @@ bool LLViewerMediaImpl::initializePlugin(const std::string& media_type)
media_source->ignore_ssl_cert_errors(true);
}
- // NOTE: Removed as per STORM-927 - SSL handshake failed - setting local self-signed certs like this
- // seems to screw things up big time. For now, devs will need to add these certs locally and Qt will pick them up.
-// // start by assuming the default CA file will be used
-// std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "lindenlab.pem" );
-// // default turned off so pick up the user specified path
-// if( ! gSavedSettings.getBOOL("BrowserUseDefaultCAFile"))
-// {
-// ca_path = gSavedSettings.getString("BrowserCAFilePath");
-// }
-// // set the path to the CA.pem file
-// media_source->addCertificateFilePath( ca_path );
+ // the correct way to deal with certs it to load ours from CA.pem and append them to the ones
+ // Qt/WebKit loads from your system location.
+ // Note: This needs the new CA.pem file with the Equifax Secure Certificate Authority
+ // cert at the bottom: (MIIDIDCCAomgAwIBAgIENd70zzANBg)
+ std::string ca_path = gDirUtilp->getExpandedFilename( LL_PATH_APP_SETTINGS, "CA.pem" );
+ media_source->addCertificateFilePath( ca_path );
media_source->proxy_setup(gSavedSettings.getBOOL("BrowserProxyEnabled"), gSavedSettings.getString("BrowserProxyAddress"), gSavedSettings.getS32("BrowserProxyPort"));
diff --git a/indra/newview/llviewermenu.cpp b/indra/newview/llviewermenu.cpp
index 425fe4eafb..add24e5216 100644
--- a/indra/newview/llviewermenu.cpp
+++ b/indra/newview/llviewermenu.cpp
@@ -1,8104 +1,8174 @@
-/**
- * @file llviewermenu.cpp
- * @brief Builds menus out of items.
- *
- * $LicenseInfo:firstyear=2002&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-#include "llviewermenu.h"
-
-// linden library includes
-#include "llavatarnamecache.h" // IDEVO
-#include "llfloaterreg.h"
-#include "llcombobox.h"
-#include "llinventorypanel.h"
-#include "llnotifications.h"
-#include "llnotificationsutil.h"
-
-// newview includes
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llagentwearables.h"
-#include "llagentpilot.h"
-#include "llbottomtray.h"
-#include "llcompilequeue.h"
-#include "llconsole.h"
-#include "lldebugview.h"
-#include "llfilepicker.h"
-#include "llfirstuse.h"
-#include "llfloaterbuy.h"
-#include "llfloaterbuycontents.h"
-#include "llbuycurrencyhtml.h"
-#include "llfloatergodtools.h"
-#include "llfloaterinventory.h"
-#include "llfloaterland.h"
-#include "llfloaterpay.h"
-#include "llfloaterreporter.h"
-#include "llfloatersearch.h"
-#include "llfloaterscriptdebug.h"
-#include "llfloatersnapshot.h"
-#include "llfloatertools.h"
-#include "llfloaterworldmap.h"
-#include "llavataractions.h"
-#include "lllandmarkactions.h"
-#include "llgroupmgr.h"
-#include "lltooltip.h"
-#include "llhints.h"
-#include "llhudeffecttrail.h"
-#include "llhudmanager.h"
-#include "llimview.h"
-#include "llinventorybridge.h"
-#include "llinventorydefines.h"
-#include "llinventoryfunctions.h"
-#include "llpanellogin.h"
-#include "llpanelblockedlist.h"
-#include "llmenucommands.h"
-#include "llmoveview.h"
-#include "llparcel.h"
-#include "llrootview.h"
-#include "llselectmgr.h"
-#include "llsidetray.h"
-#include "llstatusbar.h"
-#include "lltextureview.h"
-#include "lltoolcomp.h"
-#include "lltoolmgr.h"
-#include "lltoolpie.h"
-#include "lltoolselectland.h"
-#include "lltrans.h"
-#include "llviewergenericmessage.h"
-#include "llviewerhelp.h"
-#include "llviewermenufile.h" // init_menu_file()
-#include "llviewermessage.h"
-#include "llviewernetwork.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerstats.h"
-#include "llvoavatarself.h"
-#include "llworldmap.h"
-#include "pipeline.h"
-#include "llviewerjoystick.h"
-#include "llwlanimator.h"
-#include "llwlparammanager.h"
-#include "llfloatercamera.h"
-#include "lluilistener.h"
-#include "llappearancemgr.h"
-#include "lltrans.h"
-#include "lleconomy.h"
-#include "boost/unordered_map.hpp"
-
-using namespace LLVOAvatarDefines;
-
-static boost::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels;
-
-BOOL enable_land_build(void*);
-BOOL enable_object_build(void*);
-
-LLVOAvatar* find_avatar_from_object( LLViewerObject* object );
-LLVOAvatar* find_avatar_from_object( const LLUUID& object_id );
-
-void handle_test_load_url(void*);
-
-//
-// Evil hackish imported globals
-
-//extern BOOL gHideSelectedObjects;
-//extern BOOL gAllowSelectAvatar;
-//extern BOOL gDebugAvatarRotation;
-extern BOOL gDebugClicks;
-extern BOOL gDebugWindowProc;
-//extern BOOL gDebugTextEditorTips;
-//extern BOOL gDebugSelectMgr;
-
-//
-// Globals
-//
-
-LLMenuBarGL *gMenuBarView = NULL;
-LLViewerMenuHolderGL *gMenuHolder = NULL;
-LLMenuGL *gPopupMenuView = NULL;
-LLMenuGL *gEditMenu = NULL;
-LLMenuBarGL *gLoginMenuBarView = NULL;
-
-// Pie menus
-LLContextMenu *gMenuAvatarSelf = NULL;
-LLContextMenu *gMenuAvatarOther = NULL;
-LLContextMenu *gMenuObject = NULL;
-LLContextMenu *gMenuAttachmentSelf = NULL;
-LLContextMenu *gMenuAttachmentOther = NULL;
-LLContextMenu *gMenuLand = NULL;
-
-const std::string SAVE_INTO_INVENTORY("Save Object Back to My Inventory");
-const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents");
-
-LLMenuGL* gAttachSubMenu = NULL;
-LLMenuGL* gDetachSubMenu = NULL;
-LLMenuGL* gTakeOffClothes = NULL;
-LLContextMenu* gAttachScreenPieMenu = NULL;
-LLContextMenu* gAttachPieMenu = NULL;
-LLContextMenu* gAttachBodyPartPieMenus[8];
-LLContextMenu* gDetachPieMenu = NULL;
-LLContextMenu* gDetachScreenPieMenu = NULL;
-LLContextMenu* gDetachBodyPartPieMenus[8];
-
-LLMenuItemCallGL* gAFKMenu = NULL;
-LLMenuItemCallGL* gBusyMenu = NULL;
-
-//
-// Local prototypes
-
-// File Menu
-const char* upload_pick(void* data);
-void handle_compress_image(void*);
-
-
-// Edit menu
-void handle_dump_group_info(void *);
-void handle_dump_capabilities_info(void *);
-
-// Advanced->Consoles menu
-void handle_region_dump_settings(void*);
-void handle_region_dump_temp_asset_data(void*);
-void handle_region_clear_temp_asset_data(void*);
-
-// Object pie menu
-BOOL sitting_on_selection();
-
-void near_sit_object();
-//void label_sit_or_stand(std::string& label, void*);
-// buy and take alias into the same UI positions, so these
-// declarations handle this mess.
-BOOL is_selection_buy_not_take();
-S32 selection_price();
-BOOL enable_take();
-void handle_take();
-void handle_object_show_inspector();
-void handle_avatar_show_inspector();
-bool confirm_take(const LLSD& notification, const LLSD& response);
-
-void handle_buy_object(LLSaleInfo sale_info);
-void handle_buy_contents(LLSaleInfo sale_info);
-
-// Land pie menu
-void near_sit_down_point(BOOL success, void *);
-
-// Avatar pie menu
-
-// Debug menu
-
-
-void velocity_interpolate( void* );
-
-void handle_rebake_textures(void*);
-BOOL check_admin_override(void*);
-void handle_admin_override_toggle(void*);
-#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-void handle_toggle_hacked_godmode(void*);
-BOOL check_toggle_hacked_godmode(void*);
-bool enable_toggle_hacked_godmode(void*);
-#endif
-
-void toggle_show_xui_names(void *);
-BOOL check_show_xui_names(void *);
-
-// Debug UI
-
-void handle_buy_currency_test(void*);
-
-void handle_god_mode(void*);
-
-// God menu
-void handle_leave_god_mode(void*);
-
-
-void handle_reset_view();
-
-void handle_duplicate_in_place(void*);
-
-
-void handle_object_owner_self(void*);
-void handle_object_owner_permissive(void*);
-void handle_object_lock(void*);
-void handle_object_asset_ids(void*);
-void force_take_copy(void*);
-#ifdef _CORY_TESTING
-void force_export_copy(void*);
-void force_import_geometry(void*);
-#endif
-
-void handle_force_parcel_owner_to_me(void*);
-void handle_force_parcel_to_content(void*);
-void handle_claim_public_land(void*);
-
-void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry
-void reload_vertex_shader(void *);
-void handle_disconnect_viewer(void *);
-
-void force_error_breakpoint(void *);
-void force_error_llerror(void *);
-void force_error_bad_memory_access(void *);
-void force_error_infinite_loop(void *);
-void force_error_software_exception(void *);
-void force_error_driver_crash(void *);
-
-void handle_force_delete(void*);
-void print_object_info(void*);
-void print_agent_nvpairs(void*);
-void toggle_debug_menus(void*);
-void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status);
-void dump_select_mgr(void*);
-
-void dump_inventory(void*);
-void toggle_visibility(void*);
-BOOL get_visibility(void*);
-
-// Avatar Pie menu
-void request_friendship(const LLUUID& agent_id);
-
-// Tools menu
-void handle_selected_texture_info(void*);
-
-void handle_dump_followcam(void*);
-void handle_viewer_enable_message_log(void*);
-void handle_viewer_disable_message_log(void*);
-
-BOOL enable_buy_land(void*);
-
-// Help menu
-
-void handle_test_male(void *);
-void handle_test_female(void *);
-void handle_toggle_pg(void*);
-void handle_dump_attachments(void *);
-void handle_dump_avatar_local_textures(void*);
-void handle_debug_avatar_textures(void*);
-void handle_grab_baked_texture(void*);
-BOOL enable_grab_baked_texture(void*);
-void handle_dump_region_object_cache(void*);
-
-BOOL enable_save_into_inventory(void*);
-BOOL enable_save_into_task_inventory(void*);
-
-BOOL enable_detach(const LLSD& = LLSD());
-void menu_toggle_attached_lights(void* user_data);
-void menu_toggle_attached_particles(void* user_data);
-
-class LLMenuParcelObserver : public LLParcelObserver
-{
-public:
- LLMenuParcelObserver();
- ~LLMenuParcelObserver();
- virtual void changed();
-};
-
-static LLMenuParcelObserver* gMenuParcelObserver = NULL;
-
-static LLUIListener sUIListener;
-
-LLMenuParcelObserver::LLMenuParcelObserver()
-{
- LLViewerParcelMgr::getInstance()->addObserver(this);
-}
-
-LLMenuParcelObserver::~LLMenuParcelObserver()
-{
- LLViewerParcelMgr::getInstance()->removeObserver(this);
-}
-
-void LLMenuParcelObserver::changed()
-{
- gMenuHolder->childSetEnabled("Land Buy Pass", LLPanelLandGeneral::enableBuyPass(NULL));
-
- BOOL buyable = enable_buy_land(NULL);
- gMenuHolder->childSetEnabled("Land Buy", buyable);
- gMenuHolder->childSetEnabled("Buy Land...", buyable);
-}
-
-
-void initialize_menus();
-
-//-----------------------------------------------------------------------------
-// Initialize main menus
-//
-// HOW TO NAME MENUS:
-//
-// First Letter Of Each Word Is Capitalized, Even At Or And
-//
-// Items that lead to dialog boxes end in "..."
-//
-// Break up groups of more than 6 items with separators
-//-----------------------------------------------------------------------------
-
-void set_underclothes_menu_options()
-{
- if (gMenuHolder && gAgent.isTeen())
- {
- gMenuHolder->getChild<LLView>("Self Underpants")->setVisible(FALSE);
- gMenuHolder->getChild<LLView>("Self Undershirt")->setVisible(FALSE);
- }
- if (gMenuBarView && gAgent.isTeen())
- {
- gMenuBarView->getChild<LLView>("Menu Underpants")->setVisible(FALSE);
- gMenuBarView->getChild<LLView>("Menu Undershirt")->setVisible(FALSE);
- }
-}
-
-void init_menus()
-{
- S32 top = gViewerWindow->getRootView()->getRect().getHeight();
-
- // Initialize actions
- initialize_menus();
-
- ///
- /// Popup menu
- ///
- /// The popup menu is now populated by the show_context_menu()
- /// method.
-
- LLMenuGL::Params menu_params;
- menu_params.name = "Popup";
- menu_params.visible = false;
- gPopupMenuView = LLUICtrlFactory::create<LLMenuGL>(menu_params);
- gMenuHolder->addChild( gPopupMenuView );
-
- ///
- /// Context menus
- ///
-
- const widget_registry_t& registry =
- LLViewerMenuHolderGL::child_registry_t::instance();
- gEditMenu = LLUICtrlFactory::createFromFile<LLMenuGL>("menu_edit.xml", gMenuHolder, registry);
- gMenuAvatarSelf = LLUICtrlFactory::createFromFile<LLContextMenu>(
- "menu_avatar_self.xml", gMenuHolder, registry);
- gMenuAvatarOther = LLUICtrlFactory::createFromFile<LLContextMenu>(
- "menu_avatar_other.xml", gMenuHolder, registry);
-
- gDetachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach HUD", true);
- gDetachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach", true);
-
- gMenuObject = LLUICtrlFactory::createFromFile<LLContextMenu>(
- "menu_object.xml", gMenuHolder, registry);
-
- gAttachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach HUD");
- gAttachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach");
-
- gMenuAttachmentSelf = LLUICtrlFactory::createFromFile<LLContextMenu>(
- "menu_attachment_self.xml", gMenuHolder, registry);
- gMenuAttachmentOther = LLUICtrlFactory::createFromFile<LLContextMenu>(
- "menu_attachment_other.xml", gMenuHolder, registry);
-
- gMenuLand = LLUICtrlFactory::createFromFile<LLContextMenu>(
- "menu_land.xml", gMenuHolder, registry);
-
- ///
- /// set up the colors
- ///
- LLColor4 color;
-
- LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor");
-
- gMenuAvatarSelf->setBackgroundColor( context_menu_color );
- gMenuAvatarOther->setBackgroundColor( context_menu_color );
- gMenuObject->setBackgroundColor( context_menu_color );
- gMenuAttachmentSelf->setBackgroundColor( context_menu_color );
- gMenuAttachmentOther->setBackgroundColor( context_menu_color );
-
- gMenuLand->setBackgroundColor( context_menu_color );
-
- color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" );
- gPopupMenuView->setBackgroundColor( color );
-
- // If we are not in production, use a different color to make it apparent.
- if (LLGridManager::getInstance()->isInProductionGrid())
- {
- color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
- }
- else
- {
- color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
- }
- gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
- gMenuBarView->setRect(LLRect(0, top, 0, top - MENU_BAR_HEIGHT));
- gMenuBarView->setBackgroundColor( color );
-
- LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder");
- menu_bar_holder->addChild(gMenuBarView);
-
- gViewerWindow->setMenuBackgroundColor(false,
- LLGridManager::getInstance()->isInProductionGrid());
-
- // Assume L$10 for now, the server will tell us the real cost at login
- // *TODO:Also fix cost in llfolderview.cpp for Inventory menus
- const std::string upload_cost("10");
- gMenuHolder->childSetLabelArg("Upload Image", "[COST]", upload_cost);
- gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", upload_cost);
- gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", upload_cost);
- gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", upload_cost);
-
- gAFKMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Away", TRUE);
- gBusyMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Busy", TRUE);
- gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE);
- gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE);
-
-#if !MEM_TRACK_MEM
- // Don't display the Memory console menu if the feature is turned off
- LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", TRUE);
- if (memoryMenu)
- {
- memoryMenu->setVisible(FALSE);
- }
-#endif
-
- gMenuBarView->createJumpKeys();
-
- // Let land based option enable when parcel changes
- gMenuParcelObserver = new LLMenuParcelObserver();
-
- gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
- gLoginMenuBarView->arrangeAndClear();
- LLRect menuBarRect = gLoginMenuBarView->getRect();
- menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight());
- gLoginMenuBarView->setRect(menuBarRect);
- gLoginMenuBarView->setBackgroundColor( color );
- menu_bar_holder->addChild(gLoginMenuBarView);
-
- // tooltips are on top of EVERYTHING, including menus
- gViewerWindow->getRootView()->sendChildToFront(gToolTipView);
-}
-
-///////////////////
-// SHOW CONSOLES //
-///////////////////
-
-
-class LLAdvancedToggleConsole : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string console_type = userdata.asString();
- if ("texture" == console_type)
- {
- toggle_visibility( (void*)gTextureView );
- }
- else if ("debug" == console_type)
- {
- toggle_visibility( (void*)static_cast<LLUICtrl*>(gDebugView->mDebugConsolep));
- }
- else if (gTextureSizeView && "texture size" == console_type)
- {
- toggle_visibility( (void*)gTextureSizeView );
- }
- else if (gTextureCategoryView && "texture category" == console_type)
- {
- toggle_visibility( (void*)gTextureCategoryView );
- }
- else if ("fast timers" == console_type)
- {
- toggle_visibility( (void*)gDebugView->mFastTimerView );
- }
-#if MEM_TRACK_MEM
- else if ("memory view" == console_type)
- {
- toggle_visibility( (void*)gDebugView->mMemoryView );
- }
-#endif
- return true;
- }
-};
-class LLAdvancedCheckConsole : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string console_type = userdata.asString();
- bool new_value = false;
- if ("texture" == console_type)
- {
- new_value = get_visibility( (void*)gTextureView );
- }
- else if ("debug" == console_type)
- {
- new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) );
- }
- else if (gTextureSizeView && "texture size" == console_type)
- {
- new_value = get_visibility( (void*)gTextureSizeView );
- }
- else if (gTextureCategoryView && "texture category" == console_type)
- {
- new_value = get_visibility( (void*)gTextureCategoryView );
- }
- else if ("fast timers" == console_type)
- {
- new_value = get_visibility( (void*)gDebugView->mFastTimerView );
- }
-#if MEM_TRACK_MEM
- else if ("memory view" == console_type)
- {
- new_value = get_visibility( (void*)gDebugView->mMemoryView );
- }
-#endif
-
- return new_value;
- }
-};
-
-
-//////////////////////////
-// DUMP INFO TO CONSOLE //
-//////////////////////////
-
-
-class LLAdvancedDumpInfoToConsole : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string info_type = userdata.asString();
- if ("region" == info_type)
- {
- handle_region_dump_settings(NULL);
- }
- else if ("group" == info_type)
- {
- handle_dump_group_info(NULL);
- }
- else if ("capabilities" == info_type)
- {
- handle_dump_capabilities_info(NULL);
- }
- return true;
- }
-};
-
-
-//////////////
-// HUD INFO //
-//////////////
-
-
-class LLAdvancedToggleHUDInfo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string info_type = userdata.asString();
-
- if ("camera" == info_type)
- {
- gDisplayCameraPos = !(gDisplayCameraPos);
- }
- else if ("wind" == info_type)
- {
- gDisplayWindInfo = !(gDisplayWindInfo);
- }
- else if ("fov" == info_type)
- {
- gDisplayFOV = !(gDisplayFOV);
- }
- else if ("badge" == info_type)
- {
- gDisplayBadge = !(gDisplayBadge);
- }
- return true;
- }
-};
-
-class LLAdvancedCheckHUDInfo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string info_type = userdata.asString();
- bool new_value = false;
- if ("camera" == info_type)
- {
- new_value = gDisplayCameraPos;
- }
- else if ("wind" == info_type)
- {
- new_value = gDisplayWindInfo;
- }
- else if ("fov" == info_type)
- {
- new_value = gDisplayFOV;
- }
- else if ("badge" == info_type)
- {
- new_value = gDisplayBadge;
- }
- return new_value;
- }
-};
-
-
-//////////////
-// FLYING //
-//////////////
-
-class LLAdvancedAgentFlyingInfo : public view_listener_t
-{
- bool handleEvent(const LLSD&)
- {
- return gAgent.getFlying();
- }
-};
-
-
-///////////////////////
-// CLEAR GROUP CACHE //
-///////////////////////
-
-class LLAdvancedClearGroupCache : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLGroupMgr::debugClearAllGroups(NULL);
- return true;
- }
-};
-
-
-
-
-/////////////////
-// RENDER TYPE //
-/////////////////
-U32 render_type_from_string(std::string render_type)
-{
- if ("simple" == render_type)
- {
- return LLPipeline::RENDER_TYPE_SIMPLE;
- }
- else if ("alpha" == render_type)
- {
- return LLPipeline::RENDER_TYPE_ALPHA;
- }
- else if ("tree" == render_type)
- {
- return LLPipeline::RENDER_TYPE_TREE;
- }
- else if ("character" == render_type)
- {
- return LLPipeline::RENDER_TYPE_AVATAR;
- }
- else if ("surfacePath" == render_type)
- {
- return LLPipeline::RENDER_TYPE_TERRAIN;
- }
- else if ("sky" == render_type)
- {
- return LLPipeline::RENDER_TYPE_SKY;
- }
- else if ("water" == render_type)
- {
- return LLPipeline::RENDER_TYPE_WATER;
- }
- else if ("ground" == render_type)
- {
- return LLPipeline::RENDER_TYPE_GROUND;
- }
- else if ("volume" == render_type)
- {
- return LLPipeline::RENDER_TYPE_VOLUME;
- }
- else if ("grass" == render_type)
- {
- return LLPipeline::RENDER_TYPE_GRASS;
- }
- else if ("clouds" == render_type)
- {
- return LLPipeline::RENDER_TYPE_CLOUDS;
- }
- else if ("particles" == render_type)
- {
- return LLPipeline::RENDER_TYPE_PARTICLES;
- }
- else if ("bump" == render_type)
- {
- return LLPipeline::RENDER_TYPE_BUMP;
- }
- else
- {
- return 0;
- }
-}
-
-
-class LLAdvancedToggleRenderType : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- U32 render_type = render_type_from_string( userdata.asString() );
- if ( render_type != 0 )
- {
- LLPipeline::toggleRenderTypeControl( (void*)render_type );
- }
- return true;
- }
-};
-
-
-class LLAdvancedCheckRenderType : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- U32 render_type = render_type_from_string( userdata.asString() );
- bool new_value = false;
-
- if ( render_type != 0 )
- {
- new_value = LLPipeline::hasRenderTypeControl( (void*)render_type );
- }
-
- return new_value;
- }
-};
-
-
-/////////////
-// FEATURE //
-/////////////
-U32 feature_from_string(std::string feature)
-{
- if ("ui" == feature)
- {
- return LLPipeline::RENDER_DEBUG_FEATURE_UI;
- }
- else if ("selected" == feature)
- {
- return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED;
- }
- else if ("highlighted" == feature)
- {
- return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED;
- }
- else if ("dynamic textures" == feature)
- {
- return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES;
- }
- else if ("foot shadows" == feature)
- {
- return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS;
- }
- else if ("fog" == feature)
- {
- return LLPipeline::RENDER_DEBUG_FEATURE_FOG;
- }
- else if ("fr info" == feature)
- {
- return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO;
- }
- else if ("flexible" == feature)
- {
- return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE;
- }
- else
- {
- return 0;
- }
-};
-
-
-class LLAdvancedToggleFeature : public view_listener_t{
- bool handleEvent(const LLSD& userdata)
- {
- U32 feature = feature_from_string( userdata.asString() );
- if ( feature != 0 )
- {
- LLPipeline::toggleRenderDebugFeature( (void*)feature );
- }
- return true;
- }
-};
-
-class LLAdvancedCheckFeature : public view_listener_t
-{bool handleEvent(const LLSD& userdata)
-{
- U32 feature = feature_from_string( userdata.asString() );
- bool new_value = false;
-
- if ( feature != 0 )
- {
- new_value = LLPipeline::toggleRenderDebugFeatureControl( (void*)feature );
- }
-
- return new_value;
-}
-};
-
-void LLDestinationAndAvatarShow(const LLSD& value)
-{
- S32 panel_idx = value.isDefined() ? value.asInteger() : -1;
- LLView* container = gViewerWindow->getRootView()->getChildView("avatar_picker_and_destination_guide_container");
- LLMediaCtrl* destinations = container->findChild<LLMediaCtrl>("destination_guide_contents");
- LLMediaCtrl* avatar_picker = container->findChild<LLMediaCtrl>("avatar_picker_contents");
-
- switch(panel_idx)
- {
- case 0:
- container->setVisible(true);
- destinations->setVisible(true);
- avatar_picker->setVisible(false);
- LLFirstUse::notUsingDestinationGuide(false);
- break;
- case 1:
- container->setVisible(true);
- destinations->setVisible(false);
- avatar_picker->setVisible(true);
- LLFirstUse::notUsingAvatarPicker(false);
- break;
- default:
- container->setVisible(false);
- destinations->setVisible(false);
- avatar_picker->setVisible(false);
- break;
- }
-};
-
-
-//////////////////
-// INFO DISPLAY //
-//////////////////
-U32 info_display_from_string(std::string info_display)
-{
- if ("verify" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_VERIFY;
- }
- else if ("bboxes" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_BBOXES;
- }
- else if ("points" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_POINTS;
- }
- else if ("octree" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_OCTREE;
- }
- else if ("shadow frusta" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA;
- }
- else if ("occlusion" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_OCCLUSION;
- }
- else if ("render batches" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_BATCH_SIZE;
- }
- else if ("update type" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_UPDATE_TYPE;
- }
- else if ("texture anim" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM;
- }
- else if ("texture priority" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY;
- }
- else if ("shame" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_SHAME;
- }
- else if ("texture area" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_TEXTURE_AREA;
- }
- else if ("face area" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_FACE_AREA;
- }
- else if ("lights" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_LIGHTS;
- }
- else if ("particles" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_PARTICLES;
- }
- else if ("composition" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_COMPOSITION;
- }
- else if ("glow" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_GLOW;
- }
- else if ("collision skeleton" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME;
- }
- else if ("raycast" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_RAYCAST;
- }
- else if ("agent target" == info_display)
- {
- return LLPipeline::RENDER_DEBUG_AGENT_TARGET;
- }
- else
- {
- return 0;
- }
-};
-
-class LLAdvancedToggleInfoDisplay : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- U32 info_display = info_display_from_string( userdata.asString() );
-
- if ( info_display != 0 )
- {
- LLPipeline::toggleRenderDebug( (void*)info_display );
- }
-
- return true;
- }
-};
-
-
-class LLAdvancedCheckInfoDisplay : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- U32 info_display = info_display_from_string( userdata.asString() );
- bool new_value = false;
-
- if ( info_display != 0 )
- {
- new_value = LLPipeline::toggleRenderDebugControl( (void*)info_display );
- }
-
- return new_value;
- }
-};
-
-
-///////////////////////////
-//// RANDOMIZE FRAMERATE //
-///////////////////////////
-
-
-class LLAdvancedToggleRandomizeFramerate : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gRandomizeFramerate = !(gRandomizeFramerate);
- return true;
- }
-};
-
-class LLAdvancedCheckRandomizeFramerate : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gRandomizeFramerate;
- return new_value;
- }
-};
-
-void run_vectorize_perf_test(void *)
-{
- gSavedSettings.setBOOL("VectorizePerfTest", TRUE);
-}
-
-
-////////////////////////////////
-// RUN Vectorized Perform Test//
-////////////////////////////////
-
-
-class LLAdvancedVectorizePerfTest : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- run_vectorize_perf_test(NULL);
- return true;
- }
-};
-
-///////////////////////////
-//// PERIODIC SLOW FRAME //
-///////////////////////////
-
-
-class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gPeriodicSlowFrame = !(gPeriodicSlowFrame);
- return true;
- }
-};
-
-class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gPeriodicSlowFrame;
- return new_value;
- }
-};
-
-
-
-////////////////
-// FRAME TEST //
-////////////////
-
-
-class LLAdvancedToggleFrameTest : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLPipeline::sRenderFrameTest = !(LLPipeline::sRenderFrameTest);
- return true;
- }
-};
-
-class LLAdvancedCheckFrameTest : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLPipeline::sRenderFrameTest;
- return new_value;
- }
-};
-
-
-///////////////////////////
-// SELECTED TEXTURE INFO //
-///////////////////////////
-
-
-class LLAdvancedSelectedTextureInfo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_selected_texture_info(NULL);
- return true;
- }
-};
-
-//////////////////////
-// TOGGLE WIREFRAME //
-//////////////////////
-
-class LLAdvancedToggleWireframe : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gUseWireframe = !(gUseWireframe);
- LLPipeline::updateRenderDeferred();
- gPipeline.resetVertexBuffers();
- return true;
- }
-};
-
-class LLAdvancedCheckWireframe : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gUseWireframe;
- return new_value;
- }
-};
-
-//////////////////////
-// TEXTURE ATLAS //
-//////////////////////
-
-class LLAdvancedToggleTextureAtlas : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLViewerTexture::sUseTextureAtlas = !LLViewerTexture::sUseTextureAtlas;
- gSavedSettings.setBOOL("EnableTextureAtlas", LLViewerTexture::sUseTextureAtlas) ;
- return true;
- }
-};
-
-class LLAdvancedCheckTextureAtlas : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLViewerTexture::sUseTextureAtlas; // <-- make this using LLCacheControl
- return new_value;
- }
-};
-
-//////////////////////////
-// DUMP SCRIPTED CAMERA //
-//////////////////////////
-
-class LLAdvancedDumpScriptedCamera : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_dump_followcam(NULL);
- return true;
-}
-};
-
-
-
-//////////////////////////////
-// DUMP REGION OBJECT CACHE //
-//////////////////////////////
-
-
-class LLAdvancedDumpRegionObjectCache : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
-{
- handle_dump_region_object_cache(NULL);
- return true;
- }
-};
-
-class LLAdvancedBuyCurrencyTest : public view_listener_t
- {
- bool handleEvent(const LLSD& userdata)
- {
- handle_buy_currency_test(NULL);
- return true;
- }
-};
-
-
-/////////////////////
-// DUMP SELECT MGR //
-/////////////////////
-
-
-class LLAdvancedDumpSelectMgr : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- dump_select_mgr(NULL);
- return true;
- }
-};
-
-
-
-////////////////////
-// DUMP INVENTORY //
-////////////////////
-
-
-class LLAdvancedDumpInventory : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- dump_inventory(NULL);
- return true;
- }
-};
-
-
-
-////////////////////////////////
-// PRINT SELECTED OBJECT INFO //
-////////////////////////////////
-
-
-class LLAdvancedPrintSelectedObjectInfo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- print_object_info(NULL);
- return true;
- }
-};
-
-
-
-//////////////////////
-// PRINT AGENT INFO //
-//////////////////////
-
-
-class LLAdvancedPrintAgentInfo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- print_agent_nvpairs(NULL);
- return true;
- }
-};
-
-
-
-////////////////////////////////
-// PRINT TEXTURE MEMORY STATS //
-////////////////////////////////
-
-
-class LLAdvancedPrintTextureMemoryStats : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- output_statistics(NULL);
- return true;
- }
-};
-
-//////////////////
-// DEBUG CLICKS //
-//////////////////
-
-
-class LLAdvancedToggleDebugClicks : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gDebugClicks = !(gDebugClicks);
- return true;
- }
-};
-
-class LLAdvancedCheckDebugClicks : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gDebugClicks;
- return new_value;
- }
-};
-
-
-
-/////////////////
-// DEBUG VIEWS //
-/////////////////
-
-
-class LLAdvancedToggleDebugViews : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLView::sDebugRects = !(LLView::sDebugRects);
- return true;
- }
-};
-
-class LLAdvancedCheckDebugViews : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLView::sDebugRects;
- return new_value;
- }
-};
-
-
-
-///////////////////////
-// XUI NAME TOOLTIPS //
-///////////////////////
-
-
-class LLAdvancedToggleXUINameTooltips : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- toggle_show_xui_names(NULL);
- return true;
- }
-};
-
-class LLAdvancedCheckXUINameTooltips : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = check_show_xui_names(NULL);
- return new_value;
- }
-};
-
-
-
-////////////////////////
-// DEBUG MOUSE EVENTS //
-////////////////////////
-
-
-class LLAdvancedToggleDebugMouseEvents : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling);
- return true;
- }
-};
-
-class LLAdvancedCheckDebugMouseEvents : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLView::sDebugMouseHandling;
- return new_value;
- }
-};
-
-
-
-////////////////
-// DEBUG KEYS //
-////////////////
-
-
-class LLAdvancedToggleDebugKeys : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLView::sDebugKeys = !(LLView::sDebugKeys);
- return true;
- }
-};
-
-class LLAdvancedCheckDebugKeys : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLView::sDebugKeys;
- return new_value;
- }
-};
-
-
-
-///////////////////////
-// DEBUG WINDOW PROC //
-///////////////////////
-
-
-class LLAdvancedToggleDebugWindowProc : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gDebugWindowProc = !(gDebugWindowProc);
- return true;
- }
-};
-
-class LLAdvancedCheckDebugWindowProc : public view_listener_t
- {
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gDebugWindowProc;
- return new_value;
- }
-};
-
-// ------------------------------XUI MENU ---------------------------
-
-class LLAdvancedSendTestIms : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLIMModel::instance().testMessages();
- return true;
-}
-};
-
-
-///////////////
-// XUI NAMES //
-///////////////
-
-
-class LLAdvancedToggleXUINames : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- toggle_show_xui_names(NULL);
- return true;
- }
-};
-
-class LLAdvancedCheckXUINames : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = check_show_xui_names(NULL);
- return new_value;
- }
-};
-
-
-////////////////////////
-// GRAB BAKED TEXTURE //
-////////////////////////
-
-
-class LLAdvancedGrabBakedTexture : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string texture_type = userdata.asString();
- if ("iris" == texture_type)
- {
- handle_grab_baked_texture( (void*)BAKED_EYES );
- }
- else if ("head" == texture_type)
- {
- handle_grab_baked_texture( (void*)BAKED_HEAD );
- }
- else if ("upper" == texture_type)
- {
- handle_grab_baked_texture( (void*)BAKED_UPPER );
- }
- else if ("lower" == texture_type)
- {
- handle_grab_baked_texture( (void*)BAKED_LOWER );
- }
- else if ("skirt" == texture_type)
- {
- handle_grab_baked_texture( (void*)BAKED_SKIRT );
- }
- else if ("hair" == texture_type)
- {
- handle_grab_baked_texture( (void*)BAKED_HAIR );
- }
-
- return true;
- }
-};
-
-class LLAdvancedEnableGrabBakedTexture : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
-{
- std::string texture_type = userdata.asString();
- bool new_value = false;
-
- if ("iris" == texture_type)
- {
- new_value = enable_grab_baked_texture( (void*)BAKED_EYES );
- }
- else if ("head" == texture_type)
- {
- new_value = enable_grab_baked_texture( (void*)BAKED_HEAD );
- }
- else if ("upper" == texture_type)
- {
- new_value = enable_grab_baked_texture( (void*)BAKED_UPPER );
- }
- else if ("lower" == texture_type)
- {
- new_value = enable_grab_baked_texture( (void*)BAKED_LOWER );
- }
- else if ("skirt" == texture_type)
- {
- new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT );
- }
- else if ("hair" == texture_type)
- {
- new_value = enable_grab_baked_texture( (void*)BAKED_HAIR );
- }
-
- return new_value;
-}
-};
-
-///////////////////////
-// APPEARANCE TO XML //
-///////////////////////
-
-
-class LLAdvancedAppearanceToXML : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar::dumpArchetypeXML(NULL);
- return true;
- }
-};
-
-
-
-///////////////////////////////
-// TOGGLE CHARACTER GEOMETRY //
-///////////////////////////////
-
-
-class LLAdvancedToggleCharacterGeometry : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_god_request_avatar_geometry(NULL);
- return true;
-}
-};
-
-
- /////////////////////////////
-// TEST MALE / TEST FEMALE //
-/////////////////////////////
-
-class LLAdvancedTestMale : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_test_male(NULL);
- return true;
- }
-};
-
-
-class LLAdvancedTestFemale : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_test_female(NULL);
- return true;
- }
-};
-
-
-
-///////////////
-// TOGGLE PG //
-///////////////
-
-
-class LLAdvancedTogglePG : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_toggle_pg(NULL);
- return true;
- }
-};
-
-
-class LLAdvancedForceParamsToDefault : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLAgent::clearVisualParams(NULL);
- return true;
- }
-};
-
-
-
-//////////////////////////
-// RELOAD VERTEX SHADER //
-//////////////////////////
-
-
-class LLAdvancedReloadVertexShader : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- reload_vertex_shader(NULL);
- return true;
- }
-};
-
-
-
-////////////////////
-// ANIMATION INFO //
-////////////////////
-
-
-class LLAdvancedToggleAnimationInfo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug);
- return true;
- }
-};
-
-class LLAdvancedCheckAnimationInfo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLVOAvatar::sShowAnimationDebug;
- return new_value;
- }
-};
-
-
-//////////////////
-// SHOW LOOK AT //
-//////////////////
-
-
-class LLAdvancedToggleShowLookAt : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt);
- return true;
- }
-};
-
-class LLAdvancedCheckShowLookAt : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLHUDEffectLookAt::sDebugLookAt;
- return new_value;
- }
-};
-
-
-
-///////////////////
-// SHOW POINT AT //
-///////////////////
-
-
-class LLAdvancedToggleShowPointAt : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt);
- return true;
- }
-};
-
-class LLAdvancedCheckShowPointAt : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLHUDEffectPointAt::sDebugPointAt;
- return new_value;
- }
-};
-
-
-
-/////////////////////////
-// DEBUG JOINT UPDATES //
-/////////////////////////
-
-
-class LLAdvancedToggleDebugJointUpdates : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug);
- return true;
- }
-};
-
-class LLAdvancedCheckDebugJointUpdates : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLVOAvatar::sJointDebug;
- return new_value;
- }
-};
-
-
-
-/////////////////
-// DISABLE LOD //
-/////////////////
-
-
-class LLAdvancedToggleDisableLOD : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD);
- return true;
- }
-};
-
-class LLAdvancedCheckDisableLOD : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLViewerJoint::sDisableLOD;
- return new_value;
- }
-};
-
-
-
-/////////////////////////
-// DEBUG CHARACTER VIS //
-/////////////////////////
-
-
-class LLAdvancedToggleDebugCharacterVis : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible);
- return true;
- }
-};
-
-class LLAdvancedCheckDebugCharacterVis : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLVOAvatar::sDebugInvisible;
- return new_value;
- }
-};
-
-
-//////////////////////
-// DUMP ATTACHMENTS //
-//////////////////////
-
-
-class LLAdvancedDumpAttachments : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_dump_attachments(NULL);
- return true;
- }
-};
-
-
-
-/////////////////////
-// REBAKE TEXTURES //
-/////////////////////
-
-
-class LLAdvancedRebakeTextures : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_rebake_textures(NULL);
- return true;
- }
-};
-
-
-#if 1 //ndef LL_RELEASE_FOR_DOWNLOAD
-///////////////////////////
-// DEBUG AVATAR TEXTURES //
-///////////////////////////
-
-
-class LLAdvancedDebugAvatarTextures : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (gAgent.isGodlike())
- {
- handle_debug_avatar_textures(NULL);
- }
- return true;
- }
-};
-
-////////////////////////////////
-// DUMP AVATAR LOCAL TEXTURES //
-////////////////////////////////
-
-
-class LLAdvancedDumpAvatarLocalTextures : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
-#ifndef LL_RELEASE_FOR_DOWNLOAD
- handle_dump_avatar_local_textures(NULL);
-#endif
- return true;
- }
-};
-
-#endif
-
-/////////////////
-// MESSAGE LOG //
-/////////////////
-
-
-class LLAdvancedEnableMessageLog : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_viewer_enable_message_log(NULL);
- return true;
- }
-};
-
-class LLAdvancedDisableMessageLog : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_viewer_disable_message_log(NULL);
- return true;
- }
-};
-
-/////////////////
-// DROP PACKET //
-/////////////////
-
-
-class LLAdvancedDropPacket : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gMessageSystem->mPacketRing.dropPackets(1);
- return true;
- }
-};
-
-
-
-/////////////////
-// AGENT PILOT //
-/////////////////
-
-
-class LLAdvancedAgentPilot : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string command = userdata.asString();
- if ("start playback" == command)
- {
- LLAgentPilot::startPlayback(NULL);
- }
- else if ("stop playback" == command)
- {
- LLAgentPilot::stopPlayback(NULL);
- }
- else if ("start record" == command)
- {
- LLAgentPilot::startRecord(NULL);
- }
- else if ("stop record" == command)
- {
- LLAgentPilot::saveRecord(NULL);
- }
-
- return true;
- }
-};
-
-
-
-//////////////////////
-// AGENT PILOT LOOP //
-//////////////////////
-
-
-class LLAdvancedToggleAgentPilotLoop : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLAgentPilot::sLoop = !(LLAgentPilot::sLoop);
- return true;
- }
-};
-
-class LLAdvancedCheckAgentPilotLoop : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLAgentPilot::sLoop;
- return new_value;
- }
-};
-
-
-/////////////////////////
-// SHOW OBJECT UPDATES //
-/////////////////////////
-
-
-class LLAdvancedToggleShowObjectUpdates : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gShowObjectUpdates = !(gShowObjectUpdates);
- return true;
- }
-};
-
-class LLAdvancedCheckShowObjectUpdates : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gShowObjectUpdates;
- return new_value;
- }
-};
-
-
-
-////////////////////
-// COMPRESS IMAGE //
-////////////////////
-
-
-class LLAdvancedCompressImage : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_compress_image(NULL);
- return true;
- }
-};
-
-
-
-/////////////////////////
-// SHOW DEBUG SETTINGS //
-/////////////////////////
-
-
-class LLAdvancedShowDebugSettings : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLFloaterReg::showInstance("settings_debug",userdata);
- return true;
- }
-};
-
-
-
-////////////////////////
-// VIEW ADMIN OPTIONS //
-////////////////////////
-
-class LLAdvancedEnableViewAdminOptions : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- // Don't enable in god mode since the admin menu is shown anyway.
- // Only enable if the user has set the appropriate debug setting.
- bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu");
- return new_value;
- }
-};
-
-class LLAdvancedToggleViewAdminOptions : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_admin_override_toggle(NULL);
- return true;
- }
-};
-
-class LLAdvancedCheckViewAdminOptions : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = check_admin_override(NULL) || gAgent.isGodlike();
- return new_value;
- }
-};
-
-/////////////////////////////////////
-// Enable Object Object Occlusion ///
-/////////////////////////////////////
-class LLAdvancedEnableObjectObjectOcclusion: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
-
- bool new_value = gGLManager.mHasOcclusionQuery; // && LLFeatureManager::getInstance()->isFeatureAvailable(userdata.asString());
- return new_value;
-}
-};
-
-/////////////////////////////////////
-// Enable Framebuffer Objects ///
-/////////////////////////////////////
-class LLAdvancedEnableRenderFBO: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gGLManager.mHasFramebufferObject;
- return new_value;
- }
-};
-
-/////////////////////////////////////
-// Enable Deferred Rendering ///
-/////////////////////////////////////
-class LLAdvancedEnableRenderDeferred: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT > 0) &&
- LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0;
- return new_value;
- }
-};
-
-/////////////////////////////////////
-// Enable Deferred Rendering sub-options
-/////////////////////////////////////
-class LLAdvancedEnableRenderDeferredOptions: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && gSavedSettings.getBOOL("RenderDeferred");
- return new_value;
- }
-};
-
-
-
-//////////////////
-// ADMIN STATUS //
-//////////////////
-
-
-class LLAdvancedRequestAdminStatus : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_god_mode(NULL);
- return true;
- }
-};
-
-class LLAdvancedLeaveAdminStatus : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_leave_god_mode(NULL);
- return true;
- }
-};
-
-//////////////////////////
-// Advanced > Debugging //
-//////////////////////////
-
-
-class LLAdvancedForceErrorBreakpoint : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- force_error_breakpoint(NULL);
- return true;
- }
-};
-
-class LLAdvancedForceErrorLlerror : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- force_error_llerror(NULL);
- return true;
- }
-};
-class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- force_error_bad_memory_access(NULL);
- return true;
- }
-};
-
-class LLAdvancedForceErrorInfiniteLoop : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- force_error_infinite_loop(NULL);
- return true;
- }
-};
-
-class LLAdvancedForceErrorSoftwareException : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- force_error_software_exception(NULL);
- return true;
- }
-};
-
-class LLAdvancedForceErrorDriverCrash : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- force_error_driver_crash(NULL);
- return true;
- }
-};
-
-class LLAdvancedForceErrorDisconnectViewer : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_disconnect_viewer(NULL);
- return true;
-}
-};
-
-
-#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-
-class LLAdvancedHandleToggleHackedGodmode : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_toggle_hacked_godmode(NULL);
- return true;
- }
-};
-
-class LLAdvancedCheckToggleHackedGodmode : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- check_toggle_hacked_godmode(NULL);
- return true;
- }
-};
-
-class LLAdvancedEnableToggleHackedGodmode : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = enable_toggle_hacked_godmode(NULL);
- return new_value;
- }
-};
-#endif
-
-
-//
-////-------------------------------------------------------------------
-//// Advanced menu
-////-------------------------------------------------------------------
-
-//////////////////
-// ADMIN MENU //
-//////////////////
-
-// Admin > Object
-class LLAdminForceTakeCopy : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- force_take_copy(NULL);
- return true;
- }
-};
-
-class LLAdminHandleObjectOwnerSelf : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_object_owner_self(NULL);
- return true;
- }
-};
-class LLAdminHandleObjectOwnerPermissive : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_object_owner_permissive(NULL);
- return true;
- }
-};
-
-class LLAdminHandleForceDelete : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_force_delete(NULL);
- return true;
- }
-};
-
-class LLAdminHandleObjectLock : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_object_lock(NULL);
- return true;
- }
-};
-
-class LLAdminHandleObjectAssetIDs: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_object_asset_ids(NULL);
- return true;
- }
-};
-
-//Admin >Parcel
-class LLAdminHandleForceParcelOwnerToMe: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_force_parcel_owner_to_me(NULL);
- return true;
- }
-};
-class LLAdminHandleForceParcelToContent: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_force_parcel_to_content(NULL);
- return true;
- }
-};
-class LLAdminHandleClaimPublicLand: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_claim_public_land(NULL);
- return true;
- }
-};
-
-// Admin > Region
-class LLAdminHandleRegionDumpTempAssetData: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_region_dump_temp_asset_data(NULL);
- return true;
- }
-};
-//Admin (Top Level)
-
-class LLAdminOnSaveState: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLPanelRegionTools::onSaveState(NULL);
- return true;
-}
-};
-
-
-//-----------------------------------------------------------------------------
-// cleanup_menus()
-//-----------------------------------------------------------------------------
-void cleanup_menus()
-{
- delete gMenuParcelObserver;
- gMenuParcelObserver = NULL;
-
- delete gMenuAvatarSelf;
- gMenuAvatarSelf = NULL;
-
- delete gMenuAvatarOther;
- gMenuAvatarOther = NULL;
-
- delete gMenuObject;
- gMenuObject = NULL;
-
- delete gMenuAttachmentSelf;
- gMenuAttachmentSelf = NULL;
-
- delete gMenuAttachmentOther;
- gMenuAttachmentSelf = NULL;
-
- delete gMenuLand;
- gMenuLand = NULL;
-
- delete gMenuBarView;
- gMenuBarView = NULL;
-
- delete gPopupMenuView;
- gPopupMenuView = NULL;
-
- delete gMenuHolder;
- gMenuHolder = NULL;
-}
-
-//-----------------------------------------------------------------------------
-// Object pie menu
-//-----------------------------------------------------------------------------
-
-class LLObjectReportAbuse : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if (objectp)
- {
- LLFloaterReporter::showFromObject(objectp->getID());
- }
- return true;
- }
-};
-
-// Enabled it you clicked an object
-class LLObjectEnableReportAbuse : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0;
- return new_value;
- }
-};
-
-void handle_object_touch()
-{
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if (!object) return;
-
- LLPickInfo pick = LLToolPie::getInstance()->getPick();
-
- LLMessageSystem *msg = gMessageSystem;
-
- msg->newMessageFast(_PREHASH_ObjectGrab);
- msg->nextBlockFast( _PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast( _PREHASH_ObjectData);
- msg->addU32Fast( _PREHASH_LocalID, object->mLocalID);
- msg->addVector3Fast(_PREHASH_GrabOffset, LLVector3::zero );
- msg->nextBlock("SurfaceInfo");
- msg->addVector3("UVCoord", LLVector3(pick.mUVCoords));
- msg->addVector3("STCoord", LLVector3(pick.mSTCoords));
- msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace);
- msg->addVector3("Position", pick.mIntersection);
- msg->addVector3("Normal", pick.mNormal);
- msg->addVector3("Binormal", pick.mBinormal);
- msg->sendMessage( object->getRegion()->getHost());
-
- // *NOTE: Hope the packets arrive safely and in order or else
- // there will be some problems.
- // *TODO: Just fix this bad assumption.
- msg->newMessageFast(_PREHASH_ObjectDeGrab);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_LocalID, object->mLocalID);
- msg->nextBlock("SurfaceInfo");
- msg->addVector3("UVCoord", LLVector3(pick.mUVCoords));
- msg->addVector3("STCoord", LLVector3(pick.mSTCoords));
- msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace);
- msg->addVector3("Position", pick.mIntersection);
- msg->addVector3("Normal", pick.mNormal);
- msg->addVector3("Binormal", pick.mBinormal);
- msg->sendMessage(object->getRegion()->getHost());
-}
-
-static void init_default_item_label(const std::string& item_name)
-{
- boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
- if (it == sDefaultItemLabels.end())
- {
- // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value
- // (doesn't seem to matter much ATM).
- LLStringExplicit default_label = gMenuHolder->childGetValue(item_name).asString();
- if (!default_label.empty())
- {
- sDefaultItemLabels.insert(std::pair<std::string, LLStringExplicit>(item_name, default_label));
- }
- }
-}
-
-static LLStringExplicit get_default_item_label(const std::string& item_name)
-{
- LLStringExplicit res("");
- boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
- if (it != sDefaultItemLabels.end())
- {
- res = it->second;
- }
-
- return res;
-}
-
-
-bool enable_object_touch(LLUICtrl* ctrl)
-{
- LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-
- bool new_value = obj && obj->flagHandleTouch();
-
- std::string item_name = ctrl->getName();
- init_default_item_label(item_name);
-
- // Update label based on the node touch name if available.
- LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
- if (node && node->mValid && !node->mTouchName.empty())
- {
- gMenuHolder->childSetText(item_name, node->mTouchName);
- }
- else
- {
- gMenuHolder->childSetText(item_name, get_default_item_label(item_name));
- }
-
- return new_value;
-};
-
-//void label_touch(std::string& label, void*)
-//{
-// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
-// if (node && node->mValid && !node->mTouchName.empty())
-// {
-// label.assign(node->mTouchName);
-// }
-// else
-// {
-// label.assign("Touch");
-// }
-//}
-
-void handle_object_open()
-{
- LLFloaterReg::showInstance("openobject");
-}
-
-bool enable_object_open()
-{
- // Look for contents in root object, which is all the LLFloaterOpenObject
- // understands.
- LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if (!obj) return false;
-
- LLViewerObject* root = obj->getRootEdit();
- if (!root) return false;
-
- return root->allowOpen();
-}
-
-
-class LLViewJoystickFlycam : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_toggle_flycam();
- return true;
- }
-};
-
-class LLViewCheckJoystickFlycam : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera();
- return new_value;
- }
-};
-
-void handle_toggle_flycam()
-{
- LLViewerJoystick::getInstance()->toggleFlycam();
-}
-
-class LLObjectBuild : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") )
- {
- // zoom in if we're looking at the avatar
- gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
- gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
- gAgentCamera.cameraZoomIn(0.666f);
- gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD );
- gViewerWindow->moveCursorToCenter();
- }
- else if ( gSavedSettings.getBOOL("EditCameraMovement") )
- {
- gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
- gViewerWindow->moveCursorToCenter();
- }
-
- LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
- LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() );
-
- // Could be first use
- //LLFirstUse::useBuild();
- return true;
- }
-};
-
-
-void handle_object_edit()
-{
- LLViewerParcelMgr::getInstance()->deselectLand();
-
- if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit())
- {
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
-
- if (selection->getSelectType() == SELECT_TYPE_HUD || !gSavedSettings.getBOOL("EditCameraMovement"))
- {
- // always freeze camera in space, even if camera doesn't move
- // so, for example, follow cam scripts can't affect you when in build mode
- gAgentCamera.setFocusGlobal(gAgentCamera.calcFocusPositionTargetGlobal(), LLUUID::null);
- gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
- }
- else
- {
- gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
- LLViewerObject* selected_objectp = selection->getFirstRootObject();
- if (selected_objectp)
- {
- // zoom in on object center instead of where we clicked, as we need to see the manipulator handles
- gAgentCamera.setFocusGlobal(selected_objectp->getPositionGlobal(), selected_objectp->getID());
- gAgentCamera.cameraZoomIn(0.666f);
- gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD );
- gViewerWindow->moveCursorToCenter();
- }
- }
- }
-
- LLFloaterReg::showInstance("build");
-
- LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
- gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() );
-
- LLViewerJoystick::getInstance()->moveObjects(true);
- LLViewerJoystick::getInstance()->setNeedsReset(true);
-
- // Could be first use
- //LLFirstUse::useBuild();
- return;
-}
-
-void handle_object_inspect()
-{
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- LLViewerObject* selected_objectp = selection->getFirstRootObject();
- if (selected_objectp)
- {
- LLSD key;
- key["task"] = "task";
- LLSideTray::getInstance()->showPanel("sidepanel_inventory", key);
- }
-
- /*
- // Old floater properties
- LLFloaterReg::showInstance("inspect", LLSD());
- */
-}
-
-//---------------------------------------------------------------------------
-// Land pie menu
-//---------------------------------------------------------------------------
-class LLLandBuild : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLViewerParcelMgr::getInstance()->deselectLand();
-
- if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") )
- {
- // zoom in if we're looking at the avatar
- gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
- gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
- gAgentCamera.cameraZoomIn(0.666f);
- gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD );
- gViewerWindow->moveCursorToCenter();
- }
- else if ( gSavedSettings.getBOOL("EditCameraMovement") )
- {
- // otherwise just move focus
- gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
- gViewerWindow->moveCursorToCenter();
- }
-
-
- LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
- LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() );
-
- // Could be first use
- //LLFirstUse::useBuild();
- return true;
- }
-};
-
-class LLLandBuyPass : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLPanelLandGeneral::onClickBuyPass((void *)FALSE);
- return true;
- }
-};
-
-class LLLandEnableBuyPass : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLPanelLandGeneral::enableBuyPass(NULL);
- return new_value;
- }
-};
-
-// BUG: Should really check if CLICK POINT is in a parcel where you can build.
-BOOL enable_land_build(void*)
-{
- if (gAgent.isGodlike()) return TRUE;
- if (gAgent.inPrelude()) return FALSE;
-
- BOOL can_build = FALSE;
- LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
- if (agent_parcel)
- {
- can_build = agent_parcel->getAllowModify();
- }
- return can_build;
-}
-
-// BUG: Should really check if OBJECT is in a parcel where you can build.
-BOOL enable_object_build(void*)
-{
- if (gAgent.isGodlike()) return TRUE;
- if (gAgent.inPrelude()) return FALSE;
-
- BOOL can_build = FALSE;
- LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
- if (agent_parcel)
- {
- can_build = agent_parcel->getAllowModify();
- }
- return can_build;
-}
-
-bool enable_object_edit()
-{
- // *HACK: The new "prelude" Help Islands have a build sandbox area,
- // so users need the Edit and Create pie menu options when they are
- // there. Eventually this needs to be replaced with code that only
- // lets you edit objects if you have permission to do so (edit perms,
- // group edit, god). See also lltoolbar.cpp. JC
- bool enable = false;
- if (gAgent.inPrelude())
- {
- enable = LLViewerParcelMgr::getInstance()->allowAgentBuild()
- || LLSelectMgr::getInstance()->getSelection()->isAttachment();
- }
- else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound())
- {
- enable = true;
- }
-
- return enable;
-}
-
-// mutually exclusive - show either edit option or build in menu
-bool enable_object_build()
-{
- return !enable_object_edit();
-}
-
-class LLSelfRemoveAllAttachments : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLAgentWearables::userRemoveAllAttachments();
- return true;
- }
-};
-
-class LLSelfEnableRemoveAllAttachments : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = false;
- if (isAgentAvatarValid())
- {
- for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
- iter != gAgentAvatarp->mAttachmentPoints.end(); )
- {
- LLVOAvatar::attachment_map_t::iterator curiter = iter++;
- LLViewerJointAttachment* attachment = curiter->second;
- if (attachment->getNumObjects() > 0)
- {
- new_value = true;
- break;
- }
- }
- }
- return new_value;
- }
-};
-
-BOOL enable_has_attachments(void*)
-{
-
- return FALSE;
-}
-
-//---------------------------------------------------------------------------
-// Avatar pie menu
-//---------------------------------------------------------------------------
-//void handle_follow(void *userdata)
-//{
-// // follow a given avatar by ID
-// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-// if (objectp)
-// {
-// gAgent.startFollowPilot(objectp->getID());
-// }
-//}
-
-bool enable_object_mute()
-{
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if (!object) return false;
-
- LLVOAvatar* avatar = find_avatar_from_object(object);
- if (avatar)
- {
- // It's an avatar
- LLNameValue *lastname = avatar->getNVPair("LastName");
- bool is_linden =
- lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden");
- bool is_self = avatar->isSelf();
- return !is_linden && !is_self;
- }
- else
- {
- // Just a regular object
- return LLSelectMgr::getInstance()->getSelection()->
- contains( object, SELECT_ALL_TES );
- }
-}
-
-class LLObjectMute : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if (!object) return true;
-
- LLUUID id;
- std::string name;
- LLMute::EType type;
- LLVOAvatar* avatar = find_avatar_from_object(object);
- if (avatar)
- {
- id = avatar->getID();
-
- LLNameValue *firstname = avatar->getNVPair("FirstName");
- LLNameValue *lastname = avatar->getNVPair("LastName");
- if (firstname && lastname)
- {
- name = LLCacheName::buildFullName(
- firstname->getString(), lastname->getString());
- }
-
- type = LLMute::AGENT;
- }
- else
- {
- // it's an object
- id = object->getID();
-
- LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
- if (node)
- {
- name = node->mName;
- }
-
- type = LLMute::OBJECT;
- }
-
- LLMute mute(id, name, type);
- if (LLMuteList::getInstance()->isMuted(mute.mID))
- {
- LLMuteList::getInstance()->remove(mute);
- }
- else
- {
- LLMuteList::getInstance()->add(mute);
- LLPanelBlockedList::showPanelAndSelect(mute.mID);
- }
-
- return true;
- }
-};
-
-bool handle_go_to()
-{
- // try simulator autopilot
- std::vector<std::string> strings;
- std::string val;
- LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
- val = llformat("%g", pos.mdV[VX]);
- strings.push_back(val);
- val = llformat("%g", pos.mdV[VY]);
- strings.push_back(val);
- val = llformat("%g", pos.mdV[VZ]);
- strings.push_back(val);
- send_generic_message("autopilot", strings);
-
- LLViewerParcelMgr::getInstance()->deselectLand();
-
- if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera"))
- {
- gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID());
- }
- else
- {
- // Snap camera back to behind avatar
- gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE);
- }
-
- // Could be first use
- //LLFirstUse::useGoTo();
- return true;
-}
-
-class LLGoToObject : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- return handle_go_to();
- }
-};
-
-class LLAvatarReportAbuse : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
- if(avatar)
- {
- LLFloaterReporter::showFromObject(avatar->getID());
- }
- return true;
- }
-};
-
-
-//---------------------------------------------------------------------------
-// Parcel freeze, eject, etc.
-//---------------------------------------------------------------------------
-bool callback_freeze(const LLSD& notification, const LLSD& response)
-{
- LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID();
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
-
- if (0 == option || 1 == option)
- {
- U32 flags = 0x0;
- if (1 == option)
- {
- // unfreeze
- flags |= 0x1;
- }
-
- LLMessageSystem* msg = gMessageSystem;
- LLViewerObject* avatar = gObjectList.findObject(avatar_id);
-
- if (avatar)
- {
- msg->newMessage("FreezeUser");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID());
- msg->addUUID("SessionID", gAgent.getSessionID());
- msg->nextBlock("Data");
- msg->addUUID("TargetID", avatar_id );
- msg->addU32("Flags", flags );
- msg->sendReliable( avatar->getRegion()->getHost() );
- }
- }
- return false;
-}
-
-
-void handle_avatar_freeze(const LLSD& avatar_id)
-{
- // Use avatar_id if available, otherwise default to right-click avatar
- LLVOAvatar* avatar = NULL;
- if (avatar_id.asUUID().notNull())
- {
- avatar = find_avatar_from_object(avatar_id.asUUID());
- }
- else
- {
- avatar = find_avatar_from_object(
- LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
- }
-
- if( avatar )
- {
- std::string fullname = avatar->getFullname();
- LLSD payload;
- payload["avatar_id"] = avatar->getID();
-
- if (!fullname.empty())
- {
- LLSD args;
- args["AVATAR_NAME"] = fullname;
- LLNotificationsUtil::add("FreezeAvatarFullname",
- args,
- payload,
- callback_freeze);
- }
- else
- {
- LLNotificationsUtil::add("FreezeAvatar",
- LLSD(),
- payload,
- callback_freeze);
- }
- }
-}
-
-class LLAvatarVisibleDebug : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- return gAgent.isGodlike();
- }
-};
-
-class LLAvatarDebug : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
- if( avatar )
- {
- if (avatar->isSelf())
- {
- ((LLVOAvatarSelf *)avatar)->dumpLocalTextures();
- }
- llinfos << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << llendl;
- std::vector<std::string> strings;
- strings.push_back(avatar->getID().asString());
- LLUUID invoice;
- send_generic_message("dumptempassetdata", strings, invoice);
- LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) );
- }
- return true;
- }
-};
-
-bool callback_eject(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (2 == option)
- {
- // Cancel button.
- return false;
- }
- LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID();
- bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean();
-
- if (0 == option)
- {
- // Eject button
- LLMessageSystem* msg = gMessageSystem;
- LLViewerObject* avatar = gObjectList.findObject(avatar_id);
-
- if (avatar)
- {
- U32 flags = 0x0;
- msg->newMessage("EjectUser");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID() );
- msg->addUUID("SessionID", gAgent.getSessionID() );
- msg->nextBlock("Data");
- msg->addUUID("TargetID", avatar_id );
- msg->addU32("Flags", flags );
- msg->sendReliable( avatar->getRegion()->getHost() );
- }
- }
- else if (ban_enabled)
- {
- // This is tricky. It is similar to say if it is not an 'Eject' button,
- // and it is also not an 'Cancle' button, and ban_enabled==ture,
- // it should be the 'Eject and Ban' button.
- LLMessageSystem* msg = gMessageSystem;
- LLViewerObject* avatar = gObjectList.findObject(avatar_id);
-
- if (avatar)
- {
- U32 flags = 0x1;
- msg->newMessage("EjectUser");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID() );
- msg->addUUID("SessionID", gAgent.getSessionID() );
- msg->nextBlock("Data");
- msg->addUUID("TargetID", avatar_id );
- msg->addU32("Flags", flags );
- msg->sendReliable( avatar->getRegion()->getHost() );
- }
- }
- return false;
-}
-
-void handle_avatar_eject(const LLSD& avatar_id)
-{
- // Use avatar_id if available, otherwise default to right-click avatar
- LLVOAvatar* avatar = NULL;
- if (avatar_id.asUUID().notNull())
- {
- avatar = find_avatar_from_object(avatar_id.asUUID());
- }
- else
- {
- avatar = find_avatar_from_object(
- LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
- }
-
- if( avatar )
- {
- LLSD payload;
- payload["avatar_id"] = avatar->getID();
- std::string fullname = avatar->getFullname();
-
- const LLVector3d& pos = avatar->getPositionGlobal();
- LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel();
-
- if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED))
- {
- payload["ban_enabled"] = true;
- if (!fullname.empty())
- {
- LLSD args;
- args["AVATAR_NAME"] = fullname;
- LLNotificationsUtil::add("EjectAvatarFullname",
- args,
- payload,
- callback_eject);
- }
- else
- {
- LLNotificationsUtil::add("EjectAvatarFullname",
- LLSD(),
- payload,
- callback_eject);
- }
- }
- else
- {
- payload["ban_enabled"] = false;
- if (!fullname.empty())
- {
- LLSD args;
- args["AVATAR_NAME"] = fullname;
- LLNotificationsUtil::add("EjectAvatarFullnameNoBan",
- args,
- payload,
- callback_eject);
- }
- else
- {
- LLNotificationsUtil::add("EjectAvatarNoBan",
- LLSD(),
- payload,
- callback_eject);
- }
- }
- }
-}
-
-bool enable_freeze_eject(const LLSD& avatar_id)
-{
- // Use avatar_id if available, otherwise default to right-click avatar
- LLVOAvatar* avatar = NULL;
- if (avatar_id.asUUID().notNull())
- {
- avatar = find_avatar_from_object(avatar_id.asUUID());
- }
- else
- {
- avatar = find_avatar_from_object(
- LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
- }
- if (!avatar) return false;
-
- // Gods can always freeze
- if (gAgent.isGodlike()) return true;
-
- // Estate owners / managers can freeze
- // Parcel owners can also freeze
- const LLVector3& pos = avatar->getPositionRegion();
- const LLVector3d& pos_global = avatar->getPositionGlobal();
- LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos_global)->getParcel();
- LLViewerRegion* region = avatar->getRegion();
- if (!region) return false;
-
- bool new_value = region->isOwnedSelf(pos);
- if (!new_value || region->isOwnedGroup(pos))
- {
- new_value = LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_ADMIN);
- }
- return new_value;
-}
-
-
-void login_done(S32 which, void *user)
-{
- llinfos << "Login done " << which << llendl;
-
- LLPanelLogin::closePanel();
-}
-
-
-bool callback_leave_group(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option == 0)
- {
- LLMessageSystem *msg = gMessageSystem;
-
- msg->newMessageFast(_PREHASH_LeaveGroupRequest);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_GroupData);
- msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() );
- gAgent.sendReliableMessage();
- }
- return false;
-}
-
-void append_aggregate(std::string& string, const LLAggregatePermissions& ag_perm, PermissionBit bit, const char* txt)
-{
- LLAggregatePermissions::EValue val = ag_perm.getValue(bit);
- std::string buffer;
- switch(val)
- {
- case LLAggregatePermissions::AP_NONE:
- buffer = llformat( "* %s None\n", txt);
- break;
- case LLAggregatePermissions::AP_SOME:
- buffer = llformat( "* %s Some\n", txt);
- break;
- case LLAggregatePermissions::AP_ALL:
- buffer = llformat( "* %s All\n", txt);
- break;
- case LLAggregatePermissions::AP_EMPTY:
- default:
- break;
- }
- string.append(buffer);
-}
-
-bool enable_buy_object()
-{
- // In order to buy, there must only be 1 purchaseable object in
- // the selection manger.
- if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false;
- LLViewerObject* obj = NULL;
- LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
- if(node)
- {
- obj = node->getObject();
- if(!obj) return false;
-
- if( for_sale_selection(node) )
- {
- // *NOTE: Is this needed? This checks to see if anyone owns the
- // object, dating back to when we had "public" objects owned by
- // no one. JC
- if(obj->permAnyOwner()) return true;
- }
- }
- return false;
-}
-
-// Note: This will only work if the selected object's data has been
-// received by the viewer and cached in the selection manager.
-void handle_buy_object(LLSaleInfo sale_info)
-{
- if(!LLSelectMgr::getInstance()->selectGetAllRootsValid())
- {
- LLNotificationsUtil::add("UnableToBuyWhileDownloading");
- return;
- }
-
- LLUUID owner_id;
- std::string owner_name;
- BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name);
- if (!owners_identical)
- {
- LLNotificationsUtil::add("CannotBuyObjectsFromDifferentOwners");
- return;
- }
-
- LLPermissions perm;
- BOOL valid = LLSelectMgr::getInstance()->selectGetPermissions(perm);
- LLAggregatePermissions ag_perm;
- valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm);
- if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID()))
- {
- LLNotificationsUtil::add("ObjectNotForSale");
- return;
- }
-
- LLFloaterBuy::show(sale_info);
-}
-
-
-void handle_buy_contents(LLSaleInfo sale_info)
-{
- LLFloaterBuyContents::show(sale_info);
-}
-
-void handle_region_dump_temp_asset_data(void*)
-{
- llinfos << "Dumping temporary asset data to simulator logs" << llendl;
- std::vector<std::string> strings;
- LLUUID invoice;
- send_generic_message("dumptempassetdata", strings, invoice);
-}
-
-void handle_region_clear_temp_asset_data(void*)
-{
- llinfos << "Clearing temporary asset data" << llendl;
- std::vector<std::string> strings;
- LLUUID invoice;
- send_generic_message("cleartempassetdata", strings, invoice);
-}
-
-void handle_region_dump_settings(void*)
-{
- LLViewerRegion* regionp = gAgent.getRegion();
- if (regionp)
- {
- llinfos << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << llendl;
- llinfos << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << llendl;
- llinfos << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << llendl;
- llinfos << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << llendl;
- llinfos << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << llendl;
- llinfos << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << llendl;
- llinfos << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << llendl;
- llinfos << "Water: " << (regionp->getWaterHeight()) << llendl;
- }
-}
-
-void handle_dump_group_info(void *)
-{
- gAgent.dumpGroupInfo();
-}
-
-void handle_dump_capabilities_info(void *)
-{
- LLViewerRegion* regionp = gAgent.getRegion();
- if (regionp)
- {
- regionp->logActiveCapabilities();
- }
-}
-
-void handle_dump_region_object_cache(void*)
-{
- LLViewerRegion* regionp = gAgent.getRegion();
- if (regionp)
- {
- regionp->dumpCache();
- }
-}
-
-void handle_dump_focus()
-{
- LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
-
- llinfos << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << llendl;
-}
-
-class LLSelfStandUp : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gAgent.standUp();
- return true;
- }
-};
-
-bool enable_standup_self()
-{
- return isAgentAvatarValid() && gAgentAvatarp->isSitting();
-}
-
-class LLSelfSitDown : public view_listener_t
- {
- bool handleEvent(const LLSD& userdata)
- {
- gAgent.sitDown();
- return true;
- }
- };
-
-bool enable_sitdown_self()
-{
- return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying();
-}
-
-// Used from the login screen to aid in UI work on side tray
-void handle_show_side_tray()
-{
- LLSideTray* side_tray = LLSideTray::getInstance();
- LLView* root = gViewerWindow->getRootView();
- // automatically removes and re-adds if there already
- root->addChild(side_tray);
-}
-
-// Toggle one of "People" panel tabs in side tray.
-class LLTogglePanelPeopleTab : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string panel_name = userdata.asString();
-
- LLSD param;
- param["people_panel_tab_name"] = panel_name;
-
- static LLPanel* friends_panel = NULL;
- static LLPanel* groups_panel = NULL;
- static LLPanel* nearby_panel = NULL;
-
- if (panel_name == "friends_panel")
- {
- return togglePeoplePanel(friends_panel, panel_name, param);
- }
- else if (panel_name == "groups_panel")
- {
- return togglePeoplePanel(groups_panel, panel_name, param);
- }
- else if (panel_name == "nearby_panel")
- {
- return togglePeoplePanel(nearby_panel, panel_name, param);
- }
- else
- {
- return false;
- }
- }
-
- static bool togglePeoplePanel(LLPanel* &panel, const std::string& panel_name, const LLSD& param)
- {
- if(!panel)
- {
- panel = LLSideTray::getInstance()->getPanel(panel_name);
- if(!panel)
- return false;
- }
-
- LLSideTray::getInstance()->togglePanel(panel, "panel_people", param);
-
- return true;
- }
-};
-
-BOOL check_admin_override(void*)
-{
- return gAgent.getAdminOverride();
-}
-
-void handle_admin_override_toggle(void*)
-{
- gAgent.setAdminOverride(!gAgent.getAdminOverride());
-
- // The above may have affected which debug menus are visible
- show_debug_menus();
-}
-
-void handle_god_mode(void*)
-{
- gAgent.requestEnterGodMode();
-}
-
-void handle_leave_god_mode(void*)
-{
- gAgent.requestLeaveGodMode();
-}
-
-void set_god_level(U8 god_level)
-{
- U8 old_god_level = gAgent.getGodLevel();
- gAgent.setGodLevel( god_level );
- LLViewerParcelMgr::getInstance()->notifyObservers();
-
- // God mode changes region visibility
- LLWorldMap::getInstance()->reloadItems(true);
-
- // inventory in items may change in god mode
- gObjectList.dirtyAllObjectInventory();
-
- if(gViewerWindow)
- {
- gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT,
- LLGridManager::getInstance()->isInProductionGrid());
- }
-
- LLSD args;
- if(god_level > GOD_NOT)
- {
- args["LEVEL"] = llformat("%d",(S32)god_level);
- LLNotificationsUtil::add("EnteringGodMode", args);
- }
- else
- {
- args["LEVEL"] = llformat("%d",(S32)old_god_level);
- LLNotificationsUtil::add("LeavingGodMode", args);
- }
-
- // changing god-level can affect which menus we see
- show_debug_menus();
-
- // changing god-level can invalidate search results
- LLFloaterSearch *search = dynamic_cast<LLFloaterSearch*>(LLFloaterReg::getInstance("search"));
- if (search)
- {
- search->godLevelChanged(god_level);
- }
-}
-
-#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
-void handle_toggle_hacked_godmode(void*)
-{
- gHackGodmode = !gHackGodmode;
- set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT);
-}
-
-BOOL check_toggle_hacked_godmode(void*)
-{
- return gHackGodmode;
-}
-
-bool enable_toggle_hacked_godmode(void*)
-{
- return !LLGridManager::getInstance()->isInProductionGrid();
-}
-#endif
-
-void process_grant_godlike_powers(LLMessageSystem* msg, void**)
-{
- LLUUID agent_id;
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
- LLUUID session_id;
- msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
- if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID()))
- {
- U8 god_level;
- msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level);
- set_god_level(god_level);
- }
- else
- {
- llwarns << "Grant godlike for wrong agent " << agent_id << llendl;
- }
-}
-
-/*
-class LLHaveCallingcard : public LLInventoryCollectFunctor
-{
-public:
- LLHaveCallingcard(const LLUUID& agent_id);
- virtual ~LLHaveCallingcard() {}
- virtual bool operator()(LLInventoryCategory* cat,
- LLInventoryItem* item);
- BOOL isThere() const { return mIsThere;}
-protected:
- LLUUID mID;
- BOOL mIsThere;
-};
-
-LLHaveCallingcard::LLHaveCallingcard(const LLUUID& agent_id) :
- mID(agent_id),
- mIsThere(FALSE)
-{
-}
-
-bool LLHaveCallingcard::operator()(LLInventoryCategory* cat,
- LLInventoryItem* item)
-{
- if(item)
- {
- if((item->getType() == LLAssetType::AT_CALLINGCARD)
- && (item->getCreatorUUID() == mID))
- {
- mIsThere = TRUE;
- }
- }
- return FALSE;
-}
-*/
-
-BOOL is_agent_mappable(const LLUUID& agent_id)
-{
- const LLRelationship* buddy_info = NULL;
- bool is_friend = LLAvatarActions::isFriend(agent_id);
-
- if (is_friend)
- buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id);
-
- return (buddy_info &&
- buddy_info->isOnline() &&
- buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)
- );
-}
-
-
-// Enable a menu item when you don't have someone's card.
-class LLAvatarEnableAddFriend : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
- bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID());
- return new_value;
- }
-};
-
-void request_friendship(const LLUUID& dest_id)
-{
- LLViewerObject* dest = gObjectList.findObject(dest_id);
- if(dest && dest->isAvatar())
- {
- std::string full_name;
- LLNameValue* nvfirst = dest->getNVPair("FirstName");
- LLNameValue* nvlast = dest->getNVPair("LastName");
- if(nvfirst && nvlast)
- {
- full_name = LLCacheName::buildFullName(
- nvfirst->getString(), nvlast->getString());
- }
- if (!full_name.empty())
- {
- LLAvatarActions::requestFriendshipDialog(dest_id, full_name);
- }
- else
- {
- LLNotificationsUtil::add("CantOfferFriendship");
- }
- }
-}
-
-
-class LLEditEnableCustomizeAvatar : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gAgentWearables.areWearablesLoaded();
- return new_value;
- }
-};
-
-class LLEnableEditShape : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0);
- }
-};
-
-bool is_object_sittable()
-{
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-
- if (object && object->getPCode() == LL_PCODE_VOLUME)
- {
- return true;
- }
- else
- {
- return false;
- }
-}
-
-
-// only works on pie menu
-void handle_object_sit_or_stand()
-{
- LLPickInfo pick = LLToolPie::getInstance()->getPick();
- LLViewerObject *object = pick.getObject();;
- if (!object || pick.mPickType == LLPickInfo::PICK_FLORA)
- {
- return;
- }
-
- if (sitting_on_selection())
- {
- gAgent.standUp();
- return;
- }
-
- // get object selection offset
-
- if (object && object->getPCode() == LL_PCODE_VOLUME)
- {
-
- gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- gMessageSystem->nextBlockFast(_PREHASH_TargetObject);
- gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID);
- gMessageSystem->addVector3Fast(_PREHASH_Offset, pick.mObjectOffset);
-
- object->getRegion()->sendReliableMessage();
- }
-}
-
-void near_sit_down_point(BOOL success, void *)
-{
- if (success)
- {
- gAgent.setFlying(FALSE);
- gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
-
- // Might be first sit
- //LLFirstUse::useSit();
- }
-}
-
-class LLLandSit : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gAgent.standUp();
- LLViewerParcelMgr::getInstance()->deselectLand();
-
- LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal;
-
- LLQuaternion target_rot;
- if (isAgentAvatarValid())
- {
- target_rot = gAgentAvatarp->getRotation();
- }
- else
- {
- target_rot = gAgent.getFrameAgent().getQuaternion();
- }
- gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f);
- return true;
- }
-};
-
-//-------------------------------------------------------------------
-// Help menu functions
-//-------------------------------------------------------------------
-
-//
-// Major mode switching
-//
-void reset_view_final( BOOL proceed );
-
-void handle_reset_view()
-{
- if (gAgentCamera.cameraCustomizeAvatar())
- {
- // switching to outfit selector should automagically save any currently edited wearable
- LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "my_outfits"));
- }
-
- gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW);
- reset_view_final( TRUE );
- LLFloaterCamera::resetCameraMode();
-}
-
-class LLViewResetView : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- handle_reset_view();
- return true;
- }
-};
-
-// Note: extra parameters allow this function to be called from dialog.
-void reset_view_final( BOOL proceed )
-{
- if( !proceed )
- {
- return;
- }
-
- gAgentCamera.resetView(TRUE, TRUE);
- gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR);
-}
-
-class LLViewLookAtLastChatter : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gAgentCamera.lookAtLastChat();
- return true;
- }
-};
-
-class LLViewMouselook : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (!gAgentCamera.cameraMouselook())
- {
- gAgentCamera.changeCameraToMouselook();
- }
- else
- {
- gAgentCamera.changeCameraToDefault();
- }
- return true;
- }
-};
-
-class LLViewDefaultUISize : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gSavedSettings.setF32("UIScaleFactor", 1.0f);
- gSavedSettings.setBOOL("UIAutoScale", FALSE);
- gViewerWindow->reshape(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
- return true;
- }
-};
-
-class LLEditDuplicate : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if(LLEditMenuHandler::gEditMenuHandler)
- {
- LLEditMenuHandler::gEditMenuHandler->duplicate();
- }
- return true;
- }
-};
-
-class LLEditEnableDuplicate : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDuplicate();
- return new_value;
- }
-};
-
-void handle_duplicate_in_place(void*)
-{
- llinfos << "handle_duplicate_in_place" << llendl;
-
- LLVector3 offset(0.f, 0.f, 0.f);
- LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE);
-}
-
-/* dead code 30-apr-2008
-void handle_deed_object_to_group(void*)
-{
- LLUUID group_id;
-
- LLSelectMgr::getInstance()->selectGetGroup(group_id);
- LLSelectMgr::getInstance()->sendOwner(LLUUID::null, group_id, FALSE);
- LLViewerStats::getInstance()->incStat(LLViewerStats::ST_RELEASE_COUNT);
-}
-
-BOOL enable_deed_object_to_group(void*)
-{
- if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) return FALSE;
- LLPermissions perm;
- LLUUID group_id;
-
- if (LLSelectMgr::getInstance()->selectGetGroup(group_id) &&
- gAgent.hasPowerInGroup(group_id, GP_OBJECT_DEED) &&
- LLSelectMgr::getInstance()->selectGetPermissions(perm) &&
- perm.deedToGroup(gAgent.getID(), group_id))
- {
- return TRUE;
- }
- return FALSE;
-}
-
-*/
-
-
-/*
- * No longer able to support viewer side manipulations in this way
- *
-void god_force_inv_owner_permissive(LLViewerObject* object,
- LLInventoryObject::object_list_t* inventory,
- S32 serial_num,
- void*)
-{
- typedef std::vector<LLPointer<LLViewerInventoryItem> > item_array_t;
- item_array_t items;
-
- LLInventoryObject::object_list_t::const_iterator inv_it = inventory->begin();
- LLInventoryObject::object_list_t::const_iterator inv_end = inventory->end();
- for ( ; inv_it != inv_end; ++inv_it)
- {
- if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY))
- {
- LLInventoryObject* obj = *inv_it;
- LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj);
- LLPermissions perm(new_item->getPermissions());
- perm.setMaskBase(PERM_ALL);
- perm.setMaskOwner(PERM_ALL);
- new_item->setPermissions(perm);
- items.push_back(new_item);
- }
- }
- item_array_t::iterator end = items.end();
- item_array_t::iterator it;
- for(it = items.begin(); it != end; ++it)
- {
- // since we have the inventory item in the callback, it should not
- // invalidate iteration through the selection manager.
- object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false);
- }
-}
-*/
-
-void handle_object_owner_permissive(void*)
-{
- // only send this if they're a god.
- if(gAgent.isGodlike())
- {
- // do the objects.
- LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE);
- LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE);
- }
-}
-
-void handle_object_owner_self(void*)
-{
- // only send this if they're a god.
- if(gAgent.isGodlike())
- {
- LLSelectMgr::getInstance()->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE);
- }
-}
-
-// Shortcut to set owner permissions to not editable.
-void handle_object_lock(void*)
-{
- LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY);
-}
-
-void handle_object_asset_ids(void*)
-{
- // only send this if they're a god.
- if (gAgent.isGodlike())
- {
- LLSelectMgr::getInstance()->sendGodlikeRequest("objectinfo", "assetids");
- }
-}
-
-void handle_force_parcel_owner_to_me(void*)
-{
- LLViewerParcelMgr::getInstance()->sendParcelGodForceOwner( gAgent.getID() );
-}
-
-void handle_force_parcel_to_content(void*)
-{
- LLViewerParcelMgr::getInstance()->sendParcelGodForceToContent();
-}
-
-void handle_claim_public_land(void*)
-{
- if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion())
- {
- LLNotificationsUtil::add("ClaimPublicLand");
- return;
- }
-
- LLVector3d west_south_global;
- LLVector3d east_north_global;
- LLViewerParcelMgr::getInstance()->getSelection(west_south_global, east_north_global);
- LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global);
- LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global);
-
- LLMessageSystem* msg = gMessageSystem;
- msg->newMessage("GodlikeMessage");
- msg->nextBlock("AgentData");
- msg->addUUID("AgentID", gAgent.getID());
- msg->addUUID("SessionID", gAgent.getSessionID());
- msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used
- msg->nextBlock("MethodData");
- msg->addString("Method", "claimpublicland");
- msg->addUUID("Invoice", LLUUID::null);
- std::string buffer;
- buffer = llformat( "%f", west_south.mV[VX]);
- msg->nextBlock("ParamList");
- msg->addString("Parameter", buffer);
- buffer = llformat( "%f", west_south.mV[VY]);
- msg->nextBlock("ParamList");
- msg->addString("Parameter", buffer);
- buffer = llformat( "%f", east_north.mV[VX]);
- msg->nextBlock("ParamList");
- msg->addString("Parameter", buffer);
- buffer = llformat( "%f", east_north.mV[VY]);
- msg->nextBlock("ParamList");
- msg->addString("Parameter", buffer);
- gAgent.sendReliableMessage();
-}
-
-
-
-// HACK for easily testing new avatar geometry
-void handle_god_request_avatar_geometry(void *)
-{
- if (gAgent.isGodlike())
- {
- LLSelectMgr::getInstance()->sendGodlikeRequest("avatar toggle", "");
- }
-}
-
-
-void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
-{
- if(gAgentCamera.cameraMouselook())
- {
- gAgentCamera.changeCameraToDefault();
- }
- //gInventoryView->setPanelOpen(TRUE);
-
- std::string error;
- LLDynamicArray<LLViewerObject*> derez_objects;
-
- // Check conditions that we can't deal with, building a list of
- // everything that we'll actually be derezzing.
- LLViewerRegion* first_region = NULL;
- for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
- iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- LLViewerRegion* region = object->getRegion();
- if (!first_region)
- {
- first_region = region;
- }
- else
- {
- if(region != first_region)
- {
- // Derez doesn't work at all if the some of the objects
- // are in regions besides the first object selected.
-
- // ...crosses region boundaries
- error = "AcquireErrorObjectSpan";
- break;
- }
- }
- if (object->isAvatar())
- {
- // ...don't acquire avatars
- continue;
- }
-
- // If AssetContainers are being sent back, they will appear as
- // boxes in the owner's inventory.
- if (object->getNVPair("AssetContainer")
- && dest != DRD_RETURN_TO_OWNER)
- {
- // this object is an asset container, derez its contents, not it
- llwarns << "Attempt to derez deprecated AssetContainer object type not supported." << llendl;
- /*
- object->requestInventory(container_inventory_arrived,
- (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest));
- */
- continue;
- }
- BOOL can_derez_current = FALSE;
- switch(dest)
- {
- case DRD_TAKE_INTO_AGENT_INVENTORY:
- case DRD_TRASH:
- if( (node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify())
- || (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)) )
- {
- can_derez_current = TRUE;
- }
- break;
-
- case DRD_RETURN_TO_OWNER:
- can_derez_current = TRUE;
- break;
-
- default:
- if((node->mPermissions->allowTransferTo(gAgent.getID())
- && object->permCopy())
- || gAgent.isGodlike())
- {
- can_derez_current = TRUE;
- }
- break;
- }
- if(can_derez_current)
- {
- derez_objects.put(object);
- }
- }
-
- // This constant is based on (1200 - HEADER_SIZE) / 4 bytes per
- // root. I lopped off a few (33) to provide a bit
- // pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs.
- // This gives us a maximum of 63500 root objects - which should
- // satisfy anybody.
- const S32 MAX_ROOTS_PER_PACKET = 250;
- const S32 MAX_PACKET_COUNT = 254;
- F32 packets = ceil((F32)derez_objects.count() / (F32)MAX_ROOTS_PER_PACKET);
- if(packets > (F32)MAX_PACKET_COUNT)
- {
- error = "AcquireErrorTooManyObjects";
- }
-
- if(error.empty() && derez_objects.count() > 0)
- {
- U8 d = (U8)dest;
- LLUUID tid;
- tid.generate();
- U8 packet_count = (U8)packets;
- S32 object_index = 0;
- S32 objects_in_packet = 0;
- LLMessageSystem* msg = gMessageSystem;
- for(U8 packet_number = 0;
- packet_number < packet_count;
- ++packet_number)
- {
- msg->newMessageFast(_PREHASH_DeRezObject);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->nextBlockFast(_PREHASH_AgentBlock);
- msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
- msg->addU8Fast(_PREHASH_Destination, d);
- msg->addUUIDFast(_PREHASH_DestinationID, dest_id);
- msg->addUUIDFast(_PREHASH_TransactionID, tid);
- msg->addU8Fast(_PREHASH_PacketCount, packet_count);
- msg->addU8Fast(_PREHASH_PacketNumber, packet_number);
- objects_in_packet = 0;
- while((object_index < derez_objects.count())
- && (objects_in_packet++ < MAX_ROOTS_PER_PACKET))
-
- {
- LLViewerObject* object = derez_objects.get(object_index++);
- msg->nextBlockFast(_PREHASH_ObjectData);
- msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
- // VEFFECT: DerezObject
- LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
- effectp->setPositionGlobal(object->getPositionGlobal());
- effectp->setColor(LLColor4U(gAgent.getEffectColor()));
- }
- msg->sendReliable(first_region->getHost());
- }
- make_ui_sound("UISndObjectRezOut");
-
- // Busy count decremented by inventory update, so only increment
- // if will be causing an update.
- if (dest != DRD_RETURN_TO_OWNER)
- {
- gViewerWindow->getWindow()->incBusyCount();
- }
- }
- else if(!error.empty())
- {
- LLNotificationsUtil::add(error);
- }
-}
-
-void handle_take_copy()
-{
- if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
-
- const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
- derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id);
-}
-
-// You can return an object to its owner if it is on your land.
-class LLObjectReturn : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true;
-
- mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
-
- LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2));
- return true;
- }
-
- bool onReturnToOwner(const LLSD& notification, const LLSD& response)
- {
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- // Ignore category ID for this derez destination.
- derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null);
- }
-
- // drop reference to current selection
- mObjectSelection = NULL;
- return false;
- }
-
-protected:
- LLObjectSelectionHandle mObjectSelection;
-};
-
-
-// Allow return to owner if one or more of the selected items is
-// over land you own.
-class LLObjectEnableReturn : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
- {
- // Do not enable if nothing selected
- return false;
- }
-#ifdef HACKED_GODLIKE_VIEWER
- bool new_value = true;
-#else
- bool new_value = false;
- if (gAgent.isGodlike())
- {
- new_value = true;
- }
- else
- {
- LLViewerRegion* region = gAgent.getRegion();
- if (region)
- {
- // Estate owners and managers can always return objects.
- if (region->canManageEstate())
- {
- new_value = true;
- }
- else
- {
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* obj)
- {
- return
- obj->permModify() ||
- obj->isReturnable();
- }
- } func;
- const bool firstonly = true;
- new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
- }
- }
- }
-#endif
- return new_value;
- }
-};
-
-void force_take_copy(void*)
-{
- if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
- const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
- derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id);
-}
-
-void handle_take()
-{
- // we want to use the folder this was derezzed from if it's
- // available. Otherwise, derez to the normal place.
- if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
- {
- return;
- }
-
- BOOL you_own_everything = TRUE;
- BOOL locked_but_takeable_object = FALSE;
- LLUUID category_id;
-
- for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
- iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if(object)
- {
- if(!object->permYouOwner())
- {
- you_own_everything = FALSE;
- }
-
- if(!object->permMove())
- {
- locked_but_takeable_object = TRUE;
- }
- }
- if(node->mFolderID.notNull())
- {
- if(category_id.isNull())
- {
- category_id = node->mFolderID;
- }
- else if(category_id != node->mFolderID)
- {
- // we have found two potential destinations. break out
- // now and send to the default location.
- category_id.setNull();
- break;
- }
- }
- }
- if(category_id.notNull())
- {
- // there is an unambiguous destination. See if this agent has
- // such a location and it is not in the trash or library
- if(!gInventory.getCategory(category_id))
- {
- // nope, set to NULL.
- category_id.setNull();
- }
- if(category_id.notNull())
- {
- // check trash
- const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
- if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash))
- {
- category_id.setNull();
- }
-
- // check library
- if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID()))
- {
- category_id.setNull();
- }
-
- }
- }
- if(category_id.isNull())
- {
- category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
- }
- LLSD payload;
- payload["folder_id"] = category_id;
-
- LLNotification::Params params("ConfirmObjectTakeLock");
- params.payload(payload);
- params.functor.function(confirm_take);
-
- if(locked_but_takeable_object ||
- !you_own_everything)
- {
- if(locked_but_takeable_object && you_own_everything)
- {
- params.name("ConfirmObjectTakeLock");
- }
- else if(!locked_but_takeable_object && !you_own_everything)
- {
- params.name("ConfirmObjectTakeNoOwn");
- }
- else
- {
- params.name("ConfirmObjectTakeLockNoOwn");
- }
-
- LLNotifications::instance().add(params);
- }
- else
- {
- LLNotifications::instance().forceResponse(params, 0);
- }
-}
-
-void handle_object_show_inspector()
-{
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- LLViewerObject* objectp = selection->getFirstRootObject(TRUE);
- if (!objectp)
- {
- return;
- }
-
- LLSD params;
- params["object_id"] = objectp->getID();
- LLFloaterReg::showInstance("inspect_object", params);
-}
-
-void handle_avatar_show_inspector()
-{
- LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
- if(avatar)
- {
- LLSD params;
- params["avatar_id"] = avatar->getID();
- LLFloaterReg::showInstance("inspect_avatar", params);
- }
-}
-
-
-
-bool confirm_take(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if(enable_take() && (option == 0))
- {
- derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID());
- }
- return false;
-}
-
-// You can take an item when it is public and transferrable, or when
-// you own it. We err on the side of enabling the item when at least
-// one item selected can be copied to inventory.
-BOOL enable_take()
-{
- if (sitting_on_selection())
- {
- return FALSE;
- }
-
- for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
- iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- if (object->isAvatar())
- {
- // ...don't acquire avatars
- continue;
- }
-
-#ifdef HACKED_GODLIKE_VIEWER
- return TRUE;
-#else
-# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLGridManager::getInstance()->isInProductionGrid()
- && gAgent.isGodlike())
- {
- return TRUE;
- }
-# endif
- if((node->mPermissions->allowTransferTo(gAgent.getID())
- && object->permModify())
- || (node->mPermissions->getOwner() == gAgent.getID()))
- {
- return TRUE;
- }
-#endif
- }
- return FALSE;
-}
-
-
-void handle_buy_or_take()
-{
- if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
- {
- return;
- }
-
- if (is_selection_buy_not_take())
- {
- S32 total_price = selection_price();
-
- if (total_price <= gStatusBar->getBalance() || total_price == 0)
- {
- handle_buy();
- }
- else
- {
- LLStringUtil::format_map_t args;
- args["AMOUNT"] = llformat("%d", total_price);
- LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "BuyingCosts", args ), total_price );
- }
- }
- else
- {
- handle_take();
- }
-}
-
-bool visible_buy_object()
-{
- return is_selection_buy_not_take() && enable_buy_object();
-}
-
-bool visible_take_object()
-{
- return !is_selection_buy_not_take() && enable_take();
-}
-
-bool tools_visible_buy_object()
-{
- return is_selection_buy_not_take();
-}
-
-bool tools_visible_take_object()
-{
- return !is_selection_buy_not_take();
-}
-
-class LLToolsEnableBuyOrTake : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool is_buy = is_selection_buy_not_take();
- bool new_value = is_buy ? enable_buy_object() : enable_take();
- return new_value;
- }
-};
-
-// This is a small helper function to determine if we have a buy or a
-// take in the selection. This method is to help with the aliasing
-// problems of putting buy and take in the same pie menu space. After
-// a fair amont of discussion, it was determined to prefer buy over
-// take. The reasoning follows from the fact that when users walk up
-// to buy something, they will click on one or more items. Thus, if
-// anything is for sale, it becomes a buy operation, and the server
-// will group all of the buy items, and copyable/modifiable items into
-// one package and give the end user as much as the permissions will
-// allow. If the user wanted to take something, they will select fewer
-// and fewer items until only 'takeable' items are left. The one
-// exception is if you own everything in the selection that is for
-// sale, in this case, you can't buy stuff from yourself, so you can
-// take it.
-// return value = TRUE if selection is a 'buy'.
-// FALSE if selection is a 'take'
-BOOL is_selection_buy_not_take()
-{
- for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
- iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* obj = node->getObject();
- if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale()))
- {
- // you do not own the object and it is for sale, thus,
- // it's a buy
- return TRUE;
- }
- }
- return FALSE;
-}
-
-S32 selection_price()
-{
- S32 total_price = 0;
- for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
- iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* obj = node->getObject();
- if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale()))
- {
- // you do not own the object and it is for sale.
- // Add its price.
- total_price += node->mSaleInfo.getSalePrice();
- }
- }
-
- return total_price;
-}
-/*
-bool callback_show_buy_currency(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- llinfos << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << llendl;
- LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL"));
- }
- return false;
-}
-*/
-
-void show_buy_currency(const char* extra)
-{
- // Don't show currency web page for branded clients.
-/*
- std::ostringstream mesg;
- if (extra != NULL)
- {
- mesg << extra << "\n \n";
- }
- mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?";
-*/
- LLSD args;
- if (extra != NULL)
- {
- args["EXTRA"] = extra;
- }
- LLNotificationsUtil::add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency);
-}
-
-void handle_buy()
-{
- if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
-
- LLSaleInfo sale_info;
- BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info);
- if (!valid) return;
-
- S32 price = sale_info.getSalePrice();
-
- if (price > 0 && price > gStatusBar->getBalance())
- {
- LLStringUtil::format_map_t args;
- args["AMOUNT"] = llformat("%d", price);
- LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price );
- return;
- }
-
- if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS)
- {
- handle_buy_contents(sale_info);
- }
- else
- {
- handle_buy_object(sale_info);
- }
-}
-
-bool anyone_copy_selection(LLSelectNode* nodep)
-{
- bool perm_copy = (bool)(nodep->getObject()->permCopy());
- bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY);
- return perm_copy && all_copy;
-}
-
-bool for_sale_selection(LLSelectNode* nodep)
-{
- return nodep->mSaleInfo.isForSale()
- && nodep->mPermissions->getMaskOwner() & PERM_TRANSFER
- && (nodep->mPermissions->getMaskOwner() & PERM_COPY
- || nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY);
-}
-
-BOOL sitting_on_selection()
-{
- LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
- if (!node)
- {
- return FALSE;
- }
-
- if (!node->mValid)
- {
- return FALSE;
- }
-
- LLViewerObject* root_object = node->getObject();
- if (!root_object)
- {
- return FALSE;
- }
-
- // Need to determine if avatar is sitting on this object
- if (!isAgentAvatarValid()) return FALSE;
-
- return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object);
-}
-
-class LLToolsSaveToInventory : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if(enable_save_into_inventory(NULL))
- {
- derez_objects(DRD_SAVE_INTO_AGENT_INVENTORY, LLUUID::null);
- }
- return true;
- }
-};
-
-class LLToolsSaveToObjectInventory : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
- if(node && (node->mValid) && (!node->mFromTaskID.isNull()))
- {
- // *TODO: check to see if the fromtaskid object exists.
- derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID);
- }
- return true;
- }
-};
-
-// Round the position of all root objects to the grid
-class LLToolsSnapObjectXY : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- F64 snap_size = (F64)gSavedSettings.getF32("GridResolution");
-
- for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
- iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* obj = node->getObject();
- if (obj->permModify())
- {
- LLVector3d pos_global = obj->getPositionGlobal();
- F64 round_x = fmod(pos_global.mdV[VX], snap_size);
- if (round_x < snap_size * 0.5)
- {
- // closer to round down
- pos_global.mdV[VX] -= round_x;
- }
- else
- {
- // closer to round up
- pos_global.mdV[VX] -= round_x;
- pos_global.mdV[VX] += snap_size;
- }
-
- F64 round_y = fmod(pos_global.mdV[VY], snap_size);
- if (round_y < snap_size * 0.5)
- {
- pos_global.mdV[VY] -= round_y;
- }
- else
- {
- pos_global.mdV[VY] -= round_y;
- pos_global.mdV[VY] += snap_size;
- }
-
- obj->setPositionGlobal(pos_global, FALSE);
- }
- }
- LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION);
- return true;
- }
-};
-
-// Determine if the option to cycle between linked prims is shown
-class LLToolsEnableSelectNextPart : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = (gSavedSettings.getBOOL("EditLinkedParts") &&
- !LLSelectMgr::getInstance()->getSelection()->isEmpty());
- return new_value;
- }
-};
-
-// Cycle selection through linked children in selected object.
-// FIXME: Order of children list is not always the same as sim's idea of link order. This may confuse
-// resis. Need link position added to sim messages to address this.
-class LLToolsSelectNextPart : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
- if (gSavedSettings.getBOOL("EditLinkedParts") && object_count)
- {
- LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
- if (selected && selected->getRootEdit())
- {
- bool fwd = (userdata.asString() == "next");
- bool prev = (userdata.asString() == "previous");
- bool ifwd = (userdata.asString() == "includenext");
- bool iprev = (userdata.asString() == "includeprevious");
- LLViewerObject* to_select = NULL;
- LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren();
- children.push_front(selected->getRootEdit()); // need root in the list too
-
- for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter)
- {
- if ((*iter)->isSelected())
- {
- if (object_count > 1 && (fwd || prev)) // multiple selection, find first or last selected if not include
- {
- to_select = *iter;
- if (fwd)
- {
- // stop searching if going forward; repeat to get last hit if backward
- break;
- }
- }
- else if ((object_count == 1) || (ifwd || iprev)) // single selection or include
- {
- if (fwd || ifwd)
- {
- ++iter;
- while (iter != children.end() && ((*iter)->isAvatar() || (ifwd && (*iter)->isSelected())))
- {
- ++iter; // skip sitting avatars and selected if include
- }
- }
- else // backward
- {
- iter = (iter == children.begin() ? children.end() : iter);
- --iter;
- while (iter != children.begin() && ((*iter)->isAvatar() || (iprev && (*iter)->isSelected())))
- {
- --iter; // skip sitting avatars and selected if include
- }
- }
- iter = (iter == children.end() ? children.begin() : iter);
- to_select = *iter;
- break;
- }
- }
- }
-
- if (to_select)
- {
- if (gFocusMgr.childHasKeyboardFocus(gFloaterTools))
- {
- gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes
- }
- if (fwd || prev)
- {
- LLSelectMgr::getInstance()->deselectAll();
- }
- LLSelectMgr::getInstance()->selectObjectOnly(to_select);
- return true;
- }
- }
- }
- return true;
- }
-};
-
-class LLToolsStopAllAnimations : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gAgent.stopCurrentAnimations();
- return true;
- }
-};
-
-class LLToolsReleaseKeys : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gAgent.forceReleaseControls();
-
- return true;
- }
-};
-
-class LLToolsEnableReleaseKeys : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- return gAgent.anyControlGrabbed();
- }
-};
-
-
-class LLEditEnableCut : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut();
- return new_value;
- }
-};
-
-class LLEditCut : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if( LLEditMenuHandler::gEditMenuHandler )
- {
- LLEditMenuHandler::gEditMenuHandler->cut();
- }
- return true;
- }
-};
-
-class LLEditEnableCopy : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy();
- return new_value;
- }
-};
-
-class LLEditCopy : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if( LLEditMenuHandler::gEditMenuHandler )
- {
- LLEditMenuHandler::gEditMenuHandler->copy();
- }
- return true;
- }
-};
-
-class LLEditEnablePaste : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste();
- return new_value;
- }
-};
-
-class LLEditPaste : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if( LLEditMenuHandler::gEditMenuHandler )
- {
- LLEditMenuHandler::gEditMenuHandler->paste();
- }
- return true;
- }
-};
-
-class LLEditEnableDelete : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete();
- return new_value;
- }
-};
-
-class LLEditDelete : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- // If a text field can do a deletion, it gets precedence over deleting
- // an object in the world.
- if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete())
- {
- LLEditMenuHandler::gEditMenuHandler->doDelete();
- }
-
- // and close any pie/context menus when done
- gMenuHolder->hideMenus();
-
- // When deleting an object we may not actually be done
- // Keep selection so we know what to delete when confirmation is needed about the delete
- gMenuObject->hide();
- return true;
- }
-};
-
-bool enable_object_delete()
-{
- bool new_value =
-#ifdef HACKED_GODLIKE_VIEWER
- TRUE;
-#else
-# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- (!LLGridManager::getInstance()->isInProductionGrid()
- && gAgent.isGodlike()) ||
-# endif
- LLSelectMgr::getInstance()->canDoDelete();
-#endif
- return new_value;
-}
-
-void handle_object_delete()
-{
-
- if (LLSelectMgr::getInstance())
- {
- LLSelectMgr::getInstance()->doDelete();
- }
-
- // and close any pie/context menus when done
- gMenuHolder->hideMenus();
-
- // When deleting an object we may not actually be done
- // Keep selection so we know what to delete when confirmation is needed about the delete
- gMenuObject->hide();
- return;
-}
-
-void handle_force_delete(void*)
-{
- LLSelectMgr::getInstance()->selectForceDelete();
-}
-
-class LLViewEnableJoystickFlycam : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled"));
- return new_value;
- }
-};
-
-class LLViewEnableLastChatter : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- // *TODO: add check that last chatter is in range
- bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull());
- return new_value;
- }
-};
-
-class LLEditEnableDeselect : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect();
- return new_value;
- }
-};
-
-class LLEditDeselect : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if( LLEditMenuHandler::gEditMenuHandler )
- {
- LLEditMenuHandler::gEditMenuHandler->deselect();
- }
- return true;
- }
-};
-
-class LLEditEnableSelectAll : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll();
- return new_value;
- }
-};
-
-
-class LLEditSelectAll : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if( LLEditMenuHandler::gEditMenuHandler )
- {
- LLEditMenuHandler::gEditMenuHandler->selectAll();
- }
- return true;
- }
-};
-
-
-class LLEditEnableUndo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo();
- return new_value;
- }
-};
-
-class LLEditUndo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() )
- {
- LLEditMenuHandler::gEditMenuHandler->undo();
- }
- return true;
- }
-};
-
-class LLEditEnableRedo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo();
- return new_value;
- }
-};
-
-class LLEditRedo : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() )
- {
- LLEditMenuHandler::gEditMenuHandler->redo();
- }
- return true;
- }
-};
-
-
-
-void print_object_info(void*)
-{
- LLSelectMgr::getInstance()->selectionDump();
-}
-
-void print_agent_nvpairs(void*)
-{
- LLViewerObject *objectp;
-
- llinfos << "Agent Name Value Pairs" << llendl;
-
- objectp = gObjectList.findObject(gAgentID);
- if (objectp)
- {
- objectp->printNameValuePairs();
- }
- else
- {
- llinfos << "Can't find agent object" << llendl;
- }
-
- llinfos << "Camera at " << gAgentCamera.getCameraPositionGlobal() << llendl;
-}
-
-void show_debug_menus()
-{
- // this might get called at login screen where there is no menu so only toggle it if one exists
- if ( gMenuBarView )
- {
- BOOL debug = gSavedSettings.getBOOL("UseDebugMenus");
- BOOL qamode = gSavedSettings.getBOOL("QAMode");
-
- gMenuBarView->setItemVisible("Advanced", debug);
-// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden
-
- gMenuBarView->setItemVisible("Debug", qamode);
- gMenuBarView->setItemEnabled("Debug", qamode);
-
- gMenuBarView->setItemVisible("Develop", qamode);
- gMenuBarView->setItemEnabled("Develop", qamode);
-
- // Server ('Admin') menu hidden when not in godmode.
- const bool show_server_menu = (gAgent.getGodLevel() > GOD_NOT || (debug && gAgent.getAdminOverride()));
- gMenuBarView->setItemVisible("Admin", show_server_menu);
- gMenuBarView->setItemEnabled("Admin", show_server_menu);
- }
- if (gLoginMenuBarView)
- {
- BOOL debug = gSavedSettings.getBOOL("UseDebugMenus");
- gLoginMenuBarView->setItemVisible("Debug", debug);
- gLoginMenuBarView->setItemEnabled("Debug", debug);
- }
-}
-
-void toggle_debug_menus(void*)
-{
- BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus");
- gSavedSettings.setBOOL("UseDebugMenus", visible);
- show_debug_menus();
-}
-
-
-// LLUUID gExporterRequestID;
-// std::string gExportDirectory;
-
-// LLUploadDialog *gExportDialog = NULL;
-
-// void handle_export_selected( void * )
-// {
-// LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
-// if (selection->isEmpty())
-// {
-// return;
-// }
-// llinfos << "Exporting selected objects:" << llendl;
-
-// gExporterRequestID.generate();
-// gExportDirectory = "";
-
-// LLMessageSystem* msg = gMessageSystem;
-// msg->newMessageFast(_PREHASH_ObjectExportSelected);
-// msg->nextBlockFast(_PREHASH_AgentData);
-// msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
-// msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID);
-// msg->addS16Fast(_PREHASH_VolumeDetail, 4);
-
-// for (LLObjectSelection::root_iterator iter = selection->root_begin();
-// iter != selection->root_end(); iter++)
-// {
-// LLSelectNode* node = *iter;
-// LLViewerObject* object = node->getObject();
-// msg->nextBlockFast(_PREHASH_ObjectData);
-// msg->addUUIDFast(_PREHASH_ObjectID, object->getID());
-// llinfos << "Object: " << object->getID() << llendl;
-// }
-// msg->sendReliable(gAgent.getRegion()->getHost());
-
-// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects...");
-// }
-//
-
-
-class LLWorldSetHomeLocation : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- // we just send the message and let the server check for failure cases
- // server will echo back a "Home position set." alert if it succeeds
- // and the home location screencapture happens when that alert is recieved
- gAgent.setStartPosition(START_LOCATION_ID_HOME);
- return true;
- }
-};
-
-class LLWorldTeleportHome : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gAgent.teleportHome();
- return true;
- }
-};
-
-class LLWorldAlwaysRun : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- // as well as altering the default walk-vs-run state,
- // we also change the *current* walk-vs-run state.
- if (gAgent.getAlwaysRun())
- {
- gAgent.clearAlwaysRun();
- gAgent.clearRunning();
- }
- else
- {
- gAgent.setAlwaysRun();
- gAgent.setRunning();
- }
-
- // tell the simulator.
- gAgent.sendWalkRun(gAgent.getAlwaysRun());
-
- // Update Movement Controls according to AlwaysRun mode
- LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun());
-
- return true;
- }
-};
-
-class LLWorldCheckAlwaysRun : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gAgent.getAlwaysRun();
- return new_value;
- }
-};
-
-class LLWorldSetAway : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (gAgent.getAFK())
- {
- gAgent.clearAFK();
- }
- else
- {
- gAgent.setAFK();
- }
- return true;
- }
-};
-
-class LLWorldSetBusy : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (gAgent.getBusy())
- {
- gAgent.clearBusy();
- }
- else
- {
- gAgent.setBusy();
- LLNotificationsUtil::add("BusyModeSet");
- }
- return true;
- }
-};
-
-class LLWorldCreateLandmark : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark"));
-
- return true;
- }
-};
-
-class LLWorldPlaceProfile : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "agent"));
-
- return true;
- }
-};
-
-void handle_look_at_selection(const LLSD& param)
-{
- const F32 PADDING_FACTOR = 1.75f;
- BOOL zoom = (param.asString() == "zoom");
- if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
- {
- gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
-
- LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
- F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView());
- F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view);
-
- LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - selection_bbox.getCenterAgent();
- obj_to_cam.normVec();
-
- LLUUID object_id;
- if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject())
- {
- object_id = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->mID;
- }
- if (zoom)
- {
- // Make sure we are not increasing the distance between the camera and object
- LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal();
- distance = llmin(distance, (F32) orig_distance.length());
-
- gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance),
- LLSelectMgr::getInstance()->getSelectionCenterGlobal(),
- object_id );
-
- }
- else
- {
- gAgentCamera.setFocusGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal(), object_id );
- }
- }
-}
-
-void handle_zoom_to_object(LLUUID object_id)
-{
- const F32 PADDING_FACTOR = 2.f;
-
- LLViewerObject* object = gObjectList.findObject(object_id);
-
- 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,
- object_id );
- }
-}
-
-class LLAvatarInviteToGroup : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
- if(avatar)
- {
- LLAvatarActions::inviteToGroup(avatar->getID());
- }
- return true;
- }
-};
-
-class LLAvatarAddFriend : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
- if(avatar && !LLAvatarActions::isFriend(avatar->getID()))
- {
- request_friendship(avatar->getID());
- }
- return true;
- }
-};
-
-class LLAvatarAddContact : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
- if(avatar)
- {
- create_inventory_callingcard(avatar->getID());
- }
- return true;
- }
-};
-
-bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option == 0)
- {
- gAgent.clearBusy();
- }
-
- LLViewerObject* objectp = selection->getPrimaryObject();
-
- // Show avatar's name if paying attachment
- if (objectp && objectp->isAttachment())
- {
- while (objectp && !objectp->isAvatar())
- {
- objectp = (LLViewerObject*)objectp->getParent();
- }
- }
-
- if (objectp)
- {
- if (objectp->isAvatar())
- {
- const bool is_group = false;
- LLFloaterPayUtil::payDirectly(&give_money,
- objectp->getID(),
- is_group);
- }
- else
- {
- LLFloaterPayUtil::payViaObject(&give_money, selection);
- }
- }
- return false;
-}
-
-void handle_give_money_dialog()
-{
- LLNotification::Params params("BusyModePay");
- params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection()));
-
- if (gAgent.getBusy())
- {
- // warn users of being in busy mode during a transaction
- LLNotifications::instance().add(params);
- }
- else
- {
- LLNotifications::instance().forceResponse(params, 1);
- }
-}
-
-bool enable_pay_avatar()
-{
- LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- LLVOAvatar* avatar = find_avatar_from_object(obj);
- return (avatar != NULL);
-}
-
-bool enable_pay_object()
-{
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if( object )
- {
- LLViewerObject *parent = (LLViewerObject *)object->getParent();
- if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney()))
- {
- return true;
- }
- }
- return false;
-}
-
-bool enable_object_stand_up()
-{
- // 'Object Stand Up' menu item is enabled when agent is sitting on selection
- return sitting_on_selection();
-}
-
-bool enable_object_sit(LLUICtrl* ctrl)
-{
- // 'Object Sit' menu item is enabled when agent is not sitting on selection
- bool sitting_on_sel = sitting_on_selection();
- if (!sitting_on_sel)
- {
- std::string item_name = ctrl->getName();
-
- // init default labels
- init_default_item_label(item_name);
-
- // Update label
- LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
- if (node && node->mValid && !node->mSitName.empty())
- {
- gMenuHolder->childSetText(item_name, node->mSitName);
- }
- else
- {
- gMenuHolder->childSetText(item_name, get_default_item_label(item_name));
- }
- }
- return !sitting_on_sel && is_object_sittable();
-}
-
-void dump_select_mgr(void*)
-{
- LLSelectMgr::getInstance()->dump();
-}
-
-void dump_inventory(void*)
-{
- gInventory.dumpInventory();
-}
-
-
-void handle_dump_followcam(void*)
-{
- LLFollowCamMgr::dump();
-}
-
-void handle_viewer_enable_message_log(void*)
-{
- gMessageSystem->startLogging();
-}
-
-void handle_viewer_disable_message_log(void*)
-{
- gMessageSystem->stopLogging();
-}
-
-void handle_customize_avatar()
-{
- LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "my_outfits"));
-}
-
-void handle_edit_outfit()
-{
- LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
-}
-
-void handle_edit_shape()
-{
- LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_shape"));
-}
-
-void handle_report_abuse()
-{
- // Prevent menu from appearing in screen shot.
- gMenuHolder->hideMenus();
- LLFloaterReporter::showFromMenu(COMPLAINT_REPORT);
-}
-
-void handle_buy_currency()
-{
- LLBuyCurrencyHTML::openCurrencyFloater();
-}
-
-class LLFloaterVisible : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string floater_name = userdata.asString();
- bool new_value = false;
- {
- new_value = LLFloaterReg::instanceVisible(floater_name);
- }
- return new_value;
- }
-};
-
-class LLShowHelp : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string help_topic = userdata.asString();
- LLViewerHelp* vhelp = LLViewerHelp::getInstance();
- vhelp->showTopic(help_topic);
- return true;
- }
-};
-
-class LLShowSidetrayPanel : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string panel_name = userdata.asString();
- // Toggle the panel
- if (!LLSideTray::getInstance()->isPanelActive(panel_name))
- {
- // LLFloaterInventory::showAgentInventory();
- LLSideTray::getInstance()->showPanel(panel_name, LLSD());
- }
- else
- {
- LLSideTray::getInstance()->collapseSideBar();
- }
- return true;
- }
-};
-
-class LLSidetrayPanelVisible : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string panel_name = userdata.asString();
- // Toggle the panel
- if (LLSideTray::getInstance()->isPanelActive(panel_name))
- {
- return true;
- }
- else
- {
- return false;
- }
-
- }
-};
-
-
-bool callback_show_url(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- LLWeb::loadURL(notification["payload"]["url"].asString());
- }
- return false;
-}
-
-class LLPromptShowURL : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string param = userdata.asString();
- std::string::size_type offset = param.find(",");
- if (offset != param.npos)
- {
- std::string alert = param.substr(0, offset);
- std::string url = param.substr(offset+1);
-
- if(gSavedSettings.getBOOL("UseExternalBrowser"))
- {
- LLSD payload;
- payload["url"] = url;
- LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_url);
- }
- else
- {
- LLWeb::loadURL(url);
- }
- }
- else
- {
- llinfos << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << llendl;
- }
- return true;
- }
-};
-
-bool callback_show_file(const LLSD& notification, const LLSD& response)
-{
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (0 == option)
- {
- LLWeb::loadURL(notification["payload"]["url"]);
- }
- return false;
-}
-
-class LLPromptShowFile : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string param = userdata.asString();
- std::string::size_type offset = param.find(",");
- if (offset != param.npos)
- {
- std::string alert = param.substr(0, offset);
- std::string file = param.substr(offset+1);
-
- LLSD payload;
- payload["url"] = file;
- LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_file);
- }
- else
- {
- llinfos << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << llendl;
- }
- return true;
- }
-};
-
-class LLShowAgentProfile : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLUUID agent_id;
- if (userdata.asString() == "agent")
- {
- agent_id = gAgent.getID();
- }
- else if (userdata.asString() == "hit object")
- {
- LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if (objectp)
- {
- agent_id = objectp->getID();
- }
- }
- else
- {
- agent_id = userdata.asUUID();
- }
-
- LLVOAvatar* avatar = find_avatar_from_object(agent_id);
- if (avatar)
- {
- LLAvatarActions::showProfile(avatar->getID());
- }
- return true;
- }
-};
-
-class LLLandEdit : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- if (gAgentCamera.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") )
- {
- // zoom in if we're looking at the avatar
- gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
- gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
-
- gAgentCamera.cameraOrbitOver( F_PI * 0.25f );
- gViewerWindow->moveCursorToCenter();
- }
- else if ( gSavedSettings.getBOOL("EditCameraMovement") )
- {
- gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
- gViewerWindow->moveCursorToCenter();
- }
-
-
- LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal );
-
- LLFloaterReg::showInstance("build");
-
- // Switch to land edit toolset
- LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() );
- return true;
- }
-};
-
-class LLWorldEnableBuyLand : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel(
- LLViewerParcelMgr::getInstance()->selectionEmpty()
- ? LLViewerParcelMgr::getInstance()->getAgentParcel()
- : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(),
- false);
- return new_value;
- }
-};
-
-BOOL enable_buy_land(void*)
-{
- return LLViewerParcelMgr::getInstance()->canAgentBuyParcel(
- LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false);
-}
-
-void handle_buy_land()
-{
- LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance();
- if (vpm->selectionEmpty())
- {
- vpm->selectParcelAt(gAgent.getPositionGlobal());
- }
- vpm->startBuyLand();
-}
-
-class LLObjectAttachToAvatar : public view_listener_t
-{
-public:
- LLObjectAttachToAvatar(bool replace) : mReplace(replace) {}
- static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; }
-
-private:
- bool handleEvent(const LLSD& userdata)
- {
- setObjectSelection(LLSelectMgr::getInstance()->getSelection());
- LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject();
- if (selectedObject)
- {
- S32 index = userdata.asInteger();
- LLViewerJointAttachment* attachment_point = NULL;
- if (index > 0)
- attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL);
- confirmReplaceAttachment(0, attachment_point);
- }
- return true;
- }
-
- static void onNearAttachObject(BOOL success, void *user_data);
- void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point);
-
- struct CallbackData
- {
- CallbackData(LLViewerJointAttachment* point, bool replace) : mAttachmentPoint(point), mReplace(replace) {}
-
- LLViewerJointAttachment* mAttachmentPoint;
- bool mReplace;
- };
-
-protected:
- static LLObjectSelectionHandle sObjectSelection;
- bool mReplace;
-};
-
-LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection;
-
-// static
-void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data)
-{
- if (!user_data) return;
- CallbackData* cb_data = static_cast<CallbackData*>(user_data);
-
- if (success)
- {
- const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint;
-
- U8 attachment_id = 0;
- if (attachment)
- {
- for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
- iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter)
- {
- if (iter->second == attachment)
- {
- attachment_id = iter->first;
- break;
- }
- }
- }
- else
- {
- // interpret 0 as "default location"
- attachment_id = 0;
- }
- LLSelectMgr::getInstance()->sendAttach(attachment_id, cb_data->mReplace);
- }
- LLObjectAttachToAvatar::setObjectSelection(NULL);
-
- delete cb_data;
-}
-
-// static
-void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point)
-{
- if (option == 0/*YES*/)
- {
- LLViewerObject* selectedObject = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject();
- if (selectedObject)
- {
- const F32 MIN_STOP_DISTANCE = 1.f; // meters
- const F32 ARM_LENGTH = 0.5f; // meters
- const F32 SCALE_FUDGE = 1.5f;
-
- F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH;
- if (stop_distance < MIN_STOP_DISTANCE)
- {
- stop_distance = MIN_STOP_DISTANCE;
- }
-
- LLVector3 walkToSpot = selectedObject->getPositionAgent();
-
- // make sure we stop in front of the object
- LLVector3 delta = walkToSpot - gAgent.getPositionAgent();
- delta.normVec();
- delta = delta * 0.5f;
- walkToSpot -= delta;
-
- // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak.
- CallbackData* user_data = new CallbackData(attachment_point, mReplace);
- gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance);
- gAgentCamera.clearFocusObject();
- }
- }
-}
-
-void callback_attachment_drop(const LLSD& notification, const LLSD& response)
-{
- // Ensure user confirmed the drop
- S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
- if (option != 0) return;
-
- // Called when the user clicked on an object attached to them
- // and selected "Drop".
- LLUUID object_id = notification["payload"]["object_id"].asUUID();
- LLViewerObject *object = gObjectList.findObject(object_id);
-
- if (!object)
- {
- llwarns << "handle_drop_attachment() - no object to drop" << llendl;
- return;
- }
-
- LLViewerObject *parent = (LLViewerObject*)object->getParent();
- while (parent)
- {
- if(parent->isAvatar())
- {
- break;
- }
- object = parent;
- parent = (LLViewerObject*)parent->getParent();
- }
-
- if (!object)
- {
- llwarns << "handle_detach() - no object to detach" << llendl;
- return;
- }
-
- if (object->isAvatar())
- {
- llwarns << "Trying to detach avatar from avatar." << llendl;
- return;
- }
-
- // reselect the object
- LLSelectMgr::getInstance()->selectObjectAndFamily(object);
-
- LLSelectMgr::getInstance()->sendDropAttachment();
-
- return;
-}
-
-class LLAttachmentDrop : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLSD payload;
- LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-
- if (object)
- {
- payload["object_id"] = object->getID();
- }
- else
- {
- llwarns << "Drop object not found" << llendl;
- return true;
- }
-
- LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop);
- return true;
- }
-};
-
-// called from avatar pie menu
-class LLAttachmentDetachFromPoint : public view_listener_t
-{
- bool handleEvent(const LLSD& user_data)
- {
- const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL);
- if (attachment->getNumObjects() > 0)
- {
- gMessageSystem->newMessage("ObjectDetach");
- gMessageSystem->nextBlockFast(_PREHASH_AgentData);
- gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
- gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
-
- for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin();
- iter != attachment->mAttachedObjects.end();
- iter++)
- {
- LLViewerObject *attached_object = (*iter);
- gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
- gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID());
- }
- gMessageSystem->sendReliable( gAgent.getRegionHost() );
- }
- return true;
- }
-};
-
-static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data)
-{
- std::string label;
- LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl);
- if (menu)
- {
- const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL);
- if (attachment)
- {
- label = data["label"].asString();
- for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- const LLViewerObject* attached_object = (*attachment_iter);
- if (attached_object)
- {
- LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID());
- if (itemp)
- {
- label += std::string(" (") + itemp->getName() + std::string(")");
- break;
- }
- }
- }
- }
- menu->setLabel(label);
- }
- return true;
-}
-
-class LLAttachmentDetach : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- // Called when the user clicked on an object attached to them
- // and selected "Detach".
- LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if (!object)
- {
- llwarns << "handle_detach() - no object to detach" << llendl;
- return true;
- }
-
- LLViewerObject *parent = (LLViewerObject*)object->getParent();
- while (parent)
- {
- if(parent->isAvatar())
- {
- break;
- }
- object = parent;
- parent = (LLViewerObject*)parent->getParent();
- }
-
- if (!object)
- {
- llwarns << "handle_detach() - no object to detach" << llendl;
- return true;
- }
-
- if (object->isAvatar())
- {
- llwarns << "Trying to detach avatar from avatar." << llendl;
- return true;
- }
-
- // The sendDetach() method works on the list of selected
- // objects. Thus we need to clear the list, make sure it only
- // contains the object the user clicked, send the message,
- // then clear the list.
- // We use deselectAll to update the simulator's notion of what's
- // selected, and removeAll just to change things locally.
- //RN: I thought it was more useful to detach everything that was selected
- if (LLSelectMgr::getInstance()->getSelection()->isAttachment())
- {
- LLSelectMgr::getInstance()->sendDetach();
- }
- return true;
- }
-};
-
-//Adding an observer for a Jira 2422 and needs to be a fetch observer
-//for Jira 3119
-class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver
-{
-public:
- LLWornItemFetchedObserver(const LLUUID& worn_item_id) :
- LLInventoryFetchItemsObserver(worn_item_id)
- {}
- virtual ~LLWornItemFetchedObserver() {}
-
-protected:
- virtual void done()
- {
- gMenuAttachmentSelf->buildDrawLabels();
- gInventory.removeObserver(this);
- delete this;
- }
-};
-
-// You can only drop items on parcels where you can build.
-class LLAttachmentEnableDrop : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild());
-
- //Add an inventory observer to only allow dropping the newly attached item
- //once it exists in your inventory. Look at Jira 2422.
- //-jwolk
-
- // A bug occurs when you wear/drop an item before it actively is added to your inventory
- // if this is the case (you're on a slow sim, etc.) a copy of the object,
- // well, a newly created object with the same properties, is placed
- // in your inventory. Therefore, we disable the drop option until the
- // item is in your inventory
-
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- LLViewerJointAttachment* attachment = NULL;
- LLInventoryItem* item = NULL;
-
- // Do not enable drop if all faces of object are not enabled
- if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES ))
- {
- S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getState());
- attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
-
- if (attachment)
- {
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- // make sure item is in your inventory (it could be a delayed attach message being sent from the sim)
- // so check to see if the item is in the inventory already
- item = gInventory.getItem((*attachment_iter)->getAttachmentItemID());
- if (!item)
- {
- // Item does not exist, make an observer to enable the pie menu
- // when the item finishes fetching worst case scenario
- // if a fetch is already out there (being sent from a slow sim)
- // we refetch and there are 2 fetches
- LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID());
- worn_item_fetched->startFetch();
- gInventory.addObserver(worn_item_fetched);
- }
- }
- }
- }
-
- //now check to make sure that the item is actually in the inventory before we enable dropping it
- bool new_value = enable_detach() && can_build && item;
-
- return new_value;
- }
-};
-
-BOOL enable_detach(const LLSD&)
-{
- LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
-
- // Only enable detach if all faces of object are selected
- if (!object ||
- !object->isAttachment() ||
- !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES ))
- {
- return FALSE;
- }
-
- // Find the avatar who owns this attachment
- LLViewerObject* avatar = object;
- while (avatar)
- {
- // ...if it's you, good to detach
- if (avatar->getID() == gAgent.getID())
- {
- return TRUE;
- }
-
- avatar = (LLViewerObject*)avatar->getParent();
- }
-
- return FALSE;
-}
-
-class LLAttachmentEnableDetach : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = enable_detach();
- return new_value;
- }
-};
-
-// Used to tell if the selected object can be attached to your avatar.
-BOOL object_selected_and_point_valid()
-{
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- for (LLObjectSelection::root_iterator iter = selection->root_begin();
- iter != selection->root_end(); iter++)
- {
- LLSelectNode* node = *iter;
- LLViewerObject* object = node->getObject();
- LLViewerObject::const_child_list_t& child_list = object->getChildren();
- for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
- iter != child_list.end(); iter++)
- {
- LLViewerObject* child = *iter;
- if (child->isAvatar())
- {
- return FALSE;
- }
- }
- }
-
- return (selection->getRootObjectCount() == 1) &&
- (selection->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) &&
- selection->getFirstRootObject()->permYouOwner() &&
- selection->getFirstRootObject()->flagObjectMove() &&
- !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() &&
- (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL);
-}
-
-
-BOOL object_is_wearable()
-{
- if (!object_selected_and_point_valid())
- {
- return FALSE;
- }
- if (sitting_on_selection())
- {
- return FALSE;
- }
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
- iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
- {
- LLSelectNode* node = *iter;
- if (node->mPermissions->getOwner() == gAgent.getID())
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-
-class LLAttachmentPointFilled : public view_listener_t
-{
- bool handleEvent(const LLSD& user_data)
- {
- bool enable = false;
- LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger());
- if (found_it != gAgentAvatarp->mAttachmentPoints.end())
- {
- enable = found_it->second->getNumObjects() > 0;
- }
- return enable;
- }
-};
-
-class LLAvatarSendIM : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
- if(avatar)
- {
- LLAvatarActions::startIM(avatar->getID());
- }
- return true;
- }
-};
-
-class LLAvatarCall : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
- if(avatar)
- {
- LLAvatarActions::startCall(avatar->getID());
- }
- return true;
- }
-};
-
-namespace
-{
- struct QueueObjects : public LLSelectedObjectFunctor
- {
- BOOL scripted;
- BOOL modifiable;
- LLFloaterScriptQueue* mQueue;
- QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {}
- virtual bool apply(LLViewerObject* obj)
- {
- scripted = obj->flagScripted();
- modifiable = obj->permModify();
-
- if( scripted && modifiable )
- {
- mQueue->addObject(obj->getID());
- return false;
- }
- else
- {
- return true; // fail: stop applying
- }
- }
- };
-}
-
-void queue_actions(LLFloaterScriptQueue* q, const std::string& msg)
-{
- QueueObjects func(q);
- LLSelectMgr *mgr = LLSelectMgr::getInstance();
- LLObjectSelectionHandle selectHandle = mgr->getSelection();
- bool fail = selectHandle->applyToObjects(&func);
- if(fail)
- {
- if ( !func.scripted )
- {
- std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts";
- LLNotificationsUtil::add(noscriptmsg);
- }
- else if ( !func.modifiable )
- {
- std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission";
- LLNotificationsUtil::add(nomodmsg);
- }
- else
- {
- llerrs << "Bad logic." << llendl;
- }
- }
- else
- {
- if (!q->start())
- {
- llwarns << "Unexpected script compile failure." << llendl;
- }
- }
-}
-
-class LLToolsSelectedScriptAction : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string action = userdata.asString();
- bool mono = false;
- std::string msg, name;
- if (action == "compile mono")
- {
- name = "compile_queue";
- mono = true;
- msg = "Recompile";
- }
- if (action == "compile lsl")
- {
- name = "compile_queue";
- msg = "Recompile";
- }
- else if (action == "reset")
- {
- name = "reset_queue";
- msg = "Reset";
- }
- else if (action == "start")
- {
- name = "start_queue";
- msg = "Running";
- }
- else if (action == "stop")
- {
- name = "stop_queue";
- msg = "RunningNot";
- }
- LLUUID id; id.generate();
-
- LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance<LLFloaterScriptQueue>(name, LLSD(id));
- if (queue)
- {
- queue->setMono(mono);
- queue_actions(queue, msg);
- }
- else
- {
- llwarns << "Failed to generate LLFloaterScriptQueue with action: " << action << llendl;
- }
- return true;
- }
-};
-
-void handle_selected_texture_info(void*)
-{
- for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin();
- iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++)
- {
- LLSelectNode* node = *iter;
-
- std::string msg;
- msg.assign("Texture info for: ");
- msg.append(node->mName);
-
- LLSD args;
- args["MESSAGE"] = msg;
- LLNotificationsUtil::add("SystemMessage", args);
-
- U8 te_count = node->getObject()->getNumTEs();
- // map from texture ID to list of faces using it
- typedef std::map< LLUUID, std::vector<U8> > map_t;
- map_t faces_per_texture;
- for (U8 i = 0; i < te_count; i++)
- {
- if (!node->isTESelected(i)) continue;
-
- LLViewerTexture* img = node->getObject()->getTEImage(i);
- LLUUID image_id = img->getID();
- faces_per_texture[image_id].push_back(i);
- }
- // Per-texture, dump which faces are using it.
- map_t::iterator it;
- for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it)
- {
- LLUUID image_id = it->first;
- U8 te = it->second[0];
- LLViewerTexture* img = node->getObject()->getTEImage(te);
- S32 height = img->getHeight();
- S32 width = img->getWidth();
- S32 components = img->getComponents();
- msg = llformat("%dx%d %s on face ",
- width,
- height,
- (components == 4 ? "alpha" : "opaque"));
- for (U8 i = 0; i < it->second.size(); ++i)
- {
- msg.append( llformat("%d ", (S32)(it->second[i])));
- }
-
- LLSD args;
- args["MESSAGE"] = msg;
- LLNotificationsUtil::add("SystemMessage", args);
- }
- }
-}
-
-void handle_test_male(void*)
-{
- LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit");
- //gGestureList.requestResetFromServer( TRUE );
-}
-
-void handle_test_female(void*)
-{
- LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit");
- //gGestureList.requestResetFromServer( FALSE );
-}
-
-void handle_toggle_pg(void*)
-{
- gAgent.setTeen( !gAgent.isTeen() );
-
- LLFloaterWorldMap::reloadIcons(NULL);
-
- llinfos << "PG status set to " << (S32)gAgent.isTeen() << llendl;
-}
-
-void handle_dump_attachments(void*)
-{
- if(!isAgentAvatarValid()) return;
-
- for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
- iter != gAgentAvatarp->mAttachmentPoints.end(); )
- {
- LLVOAvatar::attachment_map_t::iterator curiter = iter++;
- LLViewerJointAttachment* attachment = curiter->second;
- S32 key = curiter->first;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- LLViewerObject *attached_object = (*attachment_iter);
- BOOL visible = (attached_object != NULL &&
- attached_object->mDrawable.notNull() &&
- !attached_object->mDrawable->isRenderType(0));
- LLVector3 pos;
- if (visible) pos = attached_object->mDrawable->getPosition();
- llinfos << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID()
- << (attached_object ? " present " : " absent ")
- << (visible ? "visible " : "invisible ")
- << " at " << pos
- << " and " << (visible ? attached_object->getPosition() : LLVector3::zero)
- << llendl;
- }
- }
-}
-
-
-// these are used in the gl menus to set control values, generically.
-class LLToggleControl : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string control_name = userdata.asString();
- BOOL checked = gSavedSettings.getBOOL( control_name );
- gSavedSettings.setBOOL( control_name, !checked );
- return true;
- }
-};
-
-class LLCheckControl : public view_listener_t
-{
- bool handleEvent( const LLSD& userdata)
- {
- std::string callback_data = userdata.asString();
- bool new_value = gSavedSettings.getBOOL(callback_data);
- return new_value;
- }
-};
-
-// not so generic
-
-class LLAdvancedCheckRenderShadowOption: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string control_name = userdata.asString();
- S32 current_shadow_level = gSavedSettings.getS32(control_name);
- if (current_shadow_level == 0) // is off
- {
- return false;
- }
- else // is on
- {
- return true;
- }
- }
-};
-
-class LLAdvancedClickRenderShadowOption: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string control_name = userdata.asString();
- S32 current_shadow_level = gSavedSettings.getS32(control_name);
- if (current_shadow_level == 0) // upgrade to level 2
- {
- gSavedSettings.setS32(control_name, 2);
- }
- else // downgrade to level 0
- {
- gSavedSettings.setS32(control_name, 0);
- }
- return true;
- }
-};
-
-void menu_toggle_attached_lights(void* user_data)
-{
- LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
-}
-
-void menu_toggle_attached_particles(void* user_data)
-{
- LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
-}
-
-class LLAdvancedHandleAttachedLightParticles: public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string control_name = userdata.asString();
-
- // toggle the control
- gSavedSettings.setBOOL(control_name,
- !gSavedSettings.getBOOL(control_name));
-
- // update internal flags
- if (control_name == "RenderAttachedLights")
- {
- menu_toggle_attached_lights(NULL);
- }
- else if (control_name == "RenderAttachedParticles")
- {
- menu_toggle_attached_particles(NULL);
- }
- return true;
- }
-};
-
-class LLSomethingSelected : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty());
- return new_value;
- }
-};
-
-class LLSomethingSelectedNoHUD : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
- bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD);
- return new_value;
- }
-};
-
-static bool is_editable_selected()
-{
- return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL);
-}
-
-class LLEditableSelected : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- return is_editable_selected();
- }
-};
-
-class LLEditableSelectedMono : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = false;
- LLViewerRegion* region = gAgent.getRegion();
- if(region && gMenuHolder)
- {
- bool have_cap = (! region->getCapability("UpdateScriptTask").empty());
- new_value = is_editable_selected() && have_cap;
- }
- return new_value;
- }
-};
-
-bool enable_object_take_copy()
-{
- bool all_valid = false;
- if (LLSelectMgr::getInstance())
- {
- if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
- {
- all_valid = true;
-#ifndef HACKED_GODLIKE_VIEWER
-# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (LLGridManager::getInstance()->isInProductionGrid()
- || !gAgent.isGodlike())
-# endif
- {
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* obj)
- {
- return (!obj->permCopy() || obj->isAttachment());
- }
- } func;
- const bool firstonly = true;
- bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
- all_valid = !any_invalid;
- }
-#endif // HACKED_GODLIKE_VIEWER
- }
- }
-
- return all_valid;
-}
-
-
-class LLHasAsset : public LLInventoryCollectFunctor
-{
-public:
- LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {}
- virtual ~LLHasAsset() {}
- virtual bool operator()(LLInventoryCategory* cat,
- LLInventoryItem* item);
- BOOL hasAsset() const { return mHasAsset; }
-
-protected:
- LLUUID mAssetID;
- BOOL mHasAsset;
-};
-
-bool LLHasAsset::operator()(LLInventoryCategory* cat,
- LLInventoryItem* item)
-{
- if(item && item->getAssetUUID() == mAssetID)
- {
- mHasAsset = TRUE;
- }
- return FALSE;
-}
-
-BOOL enable_save_into_inventory(void*)
-{
- // *TODO: clean this up
- // find the last root
- LLSelectNode* last_node = NULL;
- for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
- iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
- {
- last_node = *iter;
- }
-
-#ifdef HACKED_GODLIKE_VIEWER
- return TRUE;
-#else
-# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- if (!LLGridManager::getInstance()->isInProductionGrid()
- && gAgent.isGodlike())
- {
- return TRUE;
- }
-# endif
- // check all pre-req's for save into inventory.
- if(last_node && last_node->mValid && !last_node->mItemID.isNull()
- && (last_node->mPermissions->getOwner() == gAgent.getID())
- && (gInventory.getItem(last_node->mItemID) != NULL))
- {
- LLViewerObject* obj = last_node->getObject();
- if( obj && !obj->isAttachment() )
- {
- return TRUE;
- }
- }
-#endif
- return FALSE;
-}
-
-class LLToolsEnableSaveToInventory : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = enable_save_into_inventory(NULL);
- return new_value;
- }
-};
-
-BOOL enable_save_into_task_inventory(void*)
-{
- LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
- if(node && (node->mValid) && (!node->mFromTaskID.isNull()))
- {
- // *TODO: check to see if the fromtaskid object exists.
- LLViewerObject* obj = node->getObject();
- if( obj && !obj->isAttachment() )
- {
- return TRUE;
- }
- }
- return FALSE;
-}
-
-class LLToolsEnableSaveToObjectInventory : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = enable_save_into_task_inventory(NULL);
- return new_value;
- }
-};
-
-
-class LLViewEnableMouselook : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- // You can't go directly from customize avatar to mouselook.
- // TODO: write code with appropriate dialogs to handle this transition.
- bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime"));
- return new_value;
- }
-};
-
-class LLToolsEnableToolNotPie : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() );
- return new_value;
- }
-};
-
-class LLWorldEnableCreateLandmark : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- return !LLLandmarkActions::landmarkAlreadyExists();
- }
-};
-
-class LLWorldEnableSetHomeLocation : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gAgent.isGodlike() ||
- (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome());
- return new_value;
- }
-};
-
-class LLWorldEnableTeleportHome : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLViewerRegion* regionp = gAgent.getRegion();
- bool agent_on_prelude = (regionp && regionp->isPrelude());
- bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude;
- return enable_teleport_home;
- }
-};
-
-BOOL enable_god_full(void*)
-{
- return gAgent.getGodLevel() >= GOD_FULL;
-}
-
-BOOL enable_god_liaison(void*)
-{
- return gAgent.getGodLevel() >= GOD_LIAISON;
-}
-
-bool is_god_customer_service()
-{
- return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE;
-}
-
-BOOL enable_god_basic(void*)
-{
- return gAgent.getGodLevel() > GOD_NOT;
-}
-
-
-void toggle_show_xui_names(void *)
-{
- gSavedSettings.setBOOL("DebugShowXUINames", !gSavedSettings.getBOOL("DebugShowXUINames"));
-}
-
-BOOL check_show_xui_names(void *)
-{
- return gSavedSettings.getBOOL("DebugShowXUINames");
-}
-
-class LLToolsSelectOnlyMyObjects : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly");
-
- gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val );
-
- return true;
- }
-};
-
-class LLToolsSelectOnlyMovableObjects : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly");
-
- gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val );
-
- return true;
- }
-};
-
-class LLToolsSelectBySurrounding : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive;
-
- gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive);
- return true;
- }
-};
-
-class LLToolsShowHiddenSelection : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- // TomY TODO Merge these
- LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections;
-
- gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections);
- return true;
- }
-};
-
-class LLToolsShowSelectionLightRadius : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- // TomY TODO merge these
- LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius;
-
- gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius);
- return true;
- }
-};
-
-class LLToolsEditLinkedParts : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts");
- gSavedSettings.setBOOL( "EditLinkedParts", select_individuals );
- if (select_individuals)
- {
- LLSelectMgr::getInstance()->demoteSelectionToIndividuals();
- }
- else
- {
- LLSelectMgr::getInstance()->promoteSelectionToRoot();
- }
- return true;
- }
-};
-
-void reload_vertex_shader(void *)
-{
- //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP
-}
-
-void handle_dump_avatar_local_textures(void*)
-{
- gAgentAvatarp->dumpLocalTextures();
-}
-
-void handle_dump_timers()
-{
- LLFastTimer::dumpCurTimes();
-}
-
-void handle_debug_avatar_textures(void*)
-{
- LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
- if (objectp)
- {
- LLFloaterReg::showInstance( "avatar_textures", LLSD(objectp->getID()) );
- }
-}
-
-void handle_grab_baked_texture(void* data)
-{
- EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data);
- if (!isAgentAvatarValid()) return;
-
- const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index);
- LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << llendl;
- LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE;
- LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE;
- const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type));
- if(folder_id.notNull())
- {
- std::string name;
- name = "Baked " + LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture";
-
- LLUUID item_id;
- item_id.generate();
- LLPermissions perm;
- perm.init(gAgentID,
- gAgentID,
- LLUUID::null,
- LLUUID::null);
- U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER;
- perm.initMasks(PERM_ALL,
- PERM_ALL,
- PERM_NONE,
- PERM_NONE,
- next_owner_perm);
- time_t creation_date_now = time_corrected();
- LLPointer<LLViewerInventoryItem> item
- = new LLViewerInventoryItem(item_id,
- folder_id,
- perm,
- asset_id,
- asset_type,
- inv_type,
- name,
- LLStringUtil::null,
- LLSaleInfo::DEFAULT,
- LLInventoryItemFlags::II_FLAGS_NONE,
- creation_date_now);
-
- item->updateServer(TRUE);
- gInventory.updateItem(item);
- gInventory.notifyObservers();
-
- // Show the preview panel for textures to let
- // user know that the image is now in inventory.
- LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
- if(active_panel)
- {
- LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
-
- active_panel->setSelection(item_id, TAKE_FOCUS_NO);
- active_panel->openSelected();
- //LLFloaterInventory::dumpSelectionInformation((void*)view);
- // restore keyboard focus
- gFocusMgr.setKeyboardFocus(focus_ctrl);
- }
- }
- else
- {
- llwarns << "Can't find a folder to put it in" << llendl;
- }
-}
-
-BOOL enable_grab_baked_texture(void* data)
-{
- EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data);
- if (isAgentAvatarValid())
- {
- return gAgentAvatarp->canGrabBakedTexture(index);
- }
- return FALSE;
-}
-
-// Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing.
-// Returns NULL on failure.
-LLVOAvatar* find_avatar_from_object( LLViewerObject* object )
-{
- if (object)
- {
- if( object->isAttachment() )
- {
- do
- {
- object = (LLViewerObject*) object->getParent();
- }
- while( object && !object->isAvatar() );
- }
- else if( !object->isAvatar() )
- {
- object = NULL;
- }
- }
-
- return (LLVOAvatar*) object;
-}
-
-
-// Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing.
-// Returns NULL on failure.
-LLVOAvatar* find_avatar_from_object( const LLUUID& object_id )
-{
- return find_avatar_from_object( gObjectList.findObject(object_id) );
-}
-
-
-void handle_disconnect_viewer(void *)
-{
- LLAppViewer::instance()->forceDisconnect(LLTrans::getString("TestingDisconnect"));
-}
-
-void force_error_breakpoint(void *)
-{
- LLAppViewer::instance()->forceErrorBreakpoint();
-}
-
-void force_error_llerror(void *)
-{
- LLAppViewer::instance()->forceErrorLLError();
-}
-
-void force_error_bad_memory_access(void *)
-{
- LLAppViewer::instance()->forceErrorBadMemoryAccess();
-}
-
-void force_error_infinite_loop(void *)
-{
- LLAppViewer::instance()->forceErrorInfiniteLoop();
-}
-
-void force_error_software_exception(void *)
-{
- LLAppViewer::instance()->forceErrorSoftwareException();
-}
-
-void force_error_driver_crash(void *)
-{
- LLAppViewer::instance()->forceErrorDriverCrash();
-}
-
-class LLToolsUseSelectionForGrid : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLSelectMgr::getInstance()->clearGridObjects();
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* objectp)
- {
- LLSelectMgr::getInstance()->addGridObject(objectp);
- return true;
- }
- } func;
- LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func);
- LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT);
- if (gFloaterTools)
- {
- gFloaterTools->mComboGridMode->setCurrentByIndex((S32)GRID_MODE_REF_OBJECT);
- }
- return true;
- }
-};
-
-void handle_test_load_url(void*)
-{
- LLWeb::loadURL("");
- LLWeb::loadURL("hacker://www.google.com/");
- LLWeb::loadURL("http");
- LLWeb::loadURL("http://www.google.com/");
-}
-
-//
-// LLViewerMenuHolderGL
-//
-static LLDefaultChildRegistry::Register<LLViewerMenuHolderGL> r("menu_holder");
-
-LLViewerMenuHolderGL::LLViewerMenuHolderGL(const LLViewerMenuHolderGL::Params& p)
-: LLMenuHolderGL(p)
-{}
-
-BOOL LLViewerMenuHolderGL::hideMenus()
-{
- BOOL handled = LLMenuHolderGL::hideMenus();
-
- // drop pie menu selection
- mParcelSelection = NULL;
- mObjectSelection = NULL;
-
- if (gMenuBarView)
- {
- gMenuBarView->clearHoverItem();
- gMenuBarView->resetMenuTrigger();
- }
-
- return handled;
-}
-
-void LLViewerMenuHolderGL::setParcelSelection(LLSafeHandle<LLParcelSelection> selection)
-{
- mParcelSelection = selection;
-}
-
-void LLViewerMenuHolderGL::setObjectSelection(LLSafeHandle<LLObjectSelection> selection)
-{
- mObjectSelection = selection;
-}
-
-
-const LLRect LLViewerMenuHolderGL::getMenuRect() const
-{
- return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT);
-}
-
-void handle_web_browser_test(const LLSD& param)
-{
- std::string url = param.asString();
- if (url.empty())
- {
- url = "about:blank";
- }
- LLWeb::loadURLInternal(url);
-}
-
-void handle_web_content_test(const LLSD& param)
-{
- std::string url = param.asString();
- LLWeb::loadWebURLInternal(url);
-}
-
-void handle_buy_currency_test(void*)
-{
- std::string url =
- "http://sarahd-sl-13041.webdev.lindenlab.com/app/lindex/index.php?agent_id=[AGENT_ID]&secure_session_id=[SESSION_ID]&lang=[LANGUAGE]";
-
- LLStringUtil::format_map_t replace;
- replace["[AGENT_ID]"] = gAgent.getID().asString();
- replace["[SESSION_ID]"] = gAgent.getSecureSessionID().asString();
- replace["[LANGUAGE]"] = LLUI::getLanguage();
- LLStringUtil::format(url, replace);
-
- llinfos << "buy currency url " << url << llendl;
-
- LLFloaterReg::showInstance("buy_currency_html", LLSD(url));
-}
-
-void handle_rebake_textures(void*)
-{
- if (!isAgentAvatarValid()) return;
-
- // Slam pending upload count to "unstick" things
- bool slam_for_debug = true;
- gAgentAvatarp->forceBakeAllTextures(slam_for_debug);
-}
-
-void toggle_visibility(void* user_data)
-{
- LLView* viewp = (LLView*)user_data;
- viewp->setVisible(!viewp->getVisible());
-}
-
-BOOL get_visibility(void* user_data)
-{
- LLView* viewp = (LLView*)user_data;
- return viewp->getVisible();
-}
-
-// TomY TODO: Get rid of these?
-class LLViewShowHoverTips : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- gSavedSettings.setBOOL("ShowHoverTips", !gSavedSettings.getBOOL("ShowHoverTips"));
- return true;
- }
-};
-
-class LLViewCheckShowHoverTips : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = gSavedSettings.getBOOL("ShowHoverTips");
- return new_value;
- }
-};
-
-// TomY TODO: Get rid of these?
-class LLViewHighlightTransparent : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha;
- return true;
- }
-};
-
-class LLViewCheckHighlightTransparent : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLDrawPoolAlpha::sShowDebugAlpha;
- return new_value;
- }
-};
-
-class LLViewBeaconWidth : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string width = userdata.asString();
- if(width == "1")
- {
- gSavedSettings.setS32("DebugBeaconLineWidth", 1);
- }
- else if(width == "4")
- {
- gSavedSettings.setS32("DebugBeaconLineWidth", 4);
- }
- else if(width == "16")
- {
- gSavedSettings.setS32("DebugBeaconLineWidth", 16);
- }
- else if(width == "32")
- {
- gSavedSettings.setS32("DebugBeaconLineWidth", 32);
- }
-
- return true;
- }
-};
-
-
-class LLViewToggleBeacon : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string beacon = userdata.asString();
- if (beacon == "scriptsbeacon")
- {
- LLPipeline::toggleRenderScriptedBeacons(NULL);
- gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons(NULL) );
- // toggle the other one off if it's on
- if (LLPipeline::getRenderScriptedBeacons(NULL) && LLPipeline::getRenderScriptedTouchBeacons(NULL))
- {
- LLPipeline::toggleRenderScriptedTouchBeacons(NULL);
- gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons(NULL) );
- }
- }
- else if (beacon == "physicalbeacon")
- {
- LLPipeline::toggleRenderPhysicalBeacons(NULL);
- gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons(NULL) );
- }
- else if (beacon == "soundsbeacon")
- {
- LLPipeline::toggleRenderSoundBeacons(NULL);
- gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons(NULL) );
- }
- else if (beacon == "particlesbeacon")
- {
- LLPipeline::toggleRenderParticleBeacons(NULL);
- gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons(NULL) );
- }
- else if (beacon == "scripttouchbeacon")
- {
- LLPipeline::toggleRenderScriptedTouchBeacons(NULL);
- gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons(NULL) );
- // toggle the other one off if it's on
- if (LLPipeline::getRenderScriptedBeacons(NULL) && LLPipeline::getRenderScriptedTouchBeacons(NULL))
- {
- LLPipeline::toggleRenderScriptedBeacons(NULL);
- gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons(NULL) );
- }
- }
- else if (beacon == "renderbeacons")
- {
- LLPipeline::toggleRenderBeacons(NULL);
- gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons(NULL) );
- // toggle the other one on if it's not
- if (!LLPipeline::getRenderBeacons(NULL) && !LLPipeline::getRenderHighlights(NULL))
- {
- LLPipeline::toggleRenderHighlights(NULL);
- gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights(NULL) );
- }
- }
- else if (beacon == "renderhighlights")
- {
- LLPipeline::toggleRenderHighlights(NULL);
- gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights(NULL) );
- // toggle the other one on if it's not
- if (!LLPipeline::getRenderBeacons(NULL) && !LLPipeline::getRenderHighlights(NULL))
- {
- LLPipeline::toggleRenderBeacons(NULL);
- gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons(NULL) );
- }
- }
-
- return true;
- }
-};
-
-class LLViewCheckBeaconEnabled : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string beacon = userdata.asString();
- bool new_value = false;
- if (beacon == "scriptsbeacon")
- {
- new_value = gSavedSettings.getBOOL( "scriptsbeacon");
- LLPipeline::setRenderScriptedBeacons(new_value);
- }
- else if (beacon == "physicalbeacon")
- {
- new_value = gSavedSettings.getBOOL( "physicalbeacon");
- LLPipeline::setRenderPhysicalBeacons(new_value);
- }
- else if (beacon == "soundsbeacon")
- {
- new_value = gSavedSettings.getBOOL( "soundsbeacon");
- LLPipeline::setRenderSoundBeacons(new_value);
- }
- else if (beacon == "particlesbeacon")
- {
- new_value = gSavedSettings.getBOOL( "particlesbeacon");
- LLPipeline::setRenderParticleBeacons(new_value);
- }
- else if (beacon == "scripttouchbeacon")
- {
- new_value = gSavedSettings.getBOOL( "scripttouchbeacon");
- LLPipeline::setRenderScriptedTouchBeacons(new_value);
- }
- else if (beacon == "renderbeacons")
- {
- new_value = gSavedSettings.getBOOL( "renderbeacons");
- LLPipeline::setRenderBeacons(new_value);
- }
- else if (beacon == "renderhighlights")
- {
- new_value = gSavedSettings.getBOOL( "renderhighlights");
- LLPipeline::setRenderHighlights(new_value);
- }
- return new_value;
- }
-};
-
-class LLViewToggleRenderType : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string type = userdata.asString();
- if (type == "hideparticles")
- {
- LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES);
- }
- return true;
- }
-};
-
-class LLViewCheckRenderType : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string type = userdata.asString();
- bool new_value = false;
- if (type == "hideparticles")
- {
- new_value = LLPipeline::toggleRenderTypeControlNegated((void *)LLPipeline::RENDER_TYPE_PARTICLES);
- }
- return new_value;
- }
-};
-
-class LLViewShowHUDAttachments : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments;
- return true;
- }
-};
-
-class LLViewCheckHUDAttachments : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool new_value = LLPipeline::sShowHUDAttachments;
- return new_value;
- }
-};
-
-class LLEditEnableTakeOff : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string clothing = userdata.asString();
- LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
- if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT)
- return LLAgentWearables::selfHasWearable(type);
- return false;
- }
-};
-
-class LLEditTakeOff : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string clothing = userdata.asString();
- if (clothing == "all")
- LLWearableBridge::removeAllClothesFromAvatar();
- else
- {
- LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
- if (type >= LLWearableType::WT_SHAPE
- && type < LLWearableType::WT_COUNT
- && (gAgentWearables.getWearableCount(type) > 0))
- {
- // MULTI-WEARABLES: assuming user wanted to remove top shirt.
- U32 wearable_index = gAgentWearables.getWearableCount(type) - 1;
- LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(gAgentWearables.getWearableInventoryItem(type,wearable_index));
- LLWearableBridge::removeItemFromAvatar(item);
- }
-
- }
- return true;
- }
-};
-
-class LLToolsSelectTool : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string tool_name = userdata.asString();
- if (tool_name == "focus")
- {
- LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(1);
- }
- else if (tool_name == "move")
- {
- LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(2);
- }
- else if (tool_name == "edit")
- {
- LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(3);
- }
- else if (tool_name == "create")
- {
- LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(4);
- }
- else if (tool_name == "land")
- {
- LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(5);
- }
- return true;
- }
-};
-
-/// WINDLIGHT callbacks
-class LLWorldEnvSettings : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- std::string tod = userdata.asString();
- LLVector3 sun_direction;
-
- if (tod == "editor")
- {
- // if not there or is hidden, show it
- LLFloaterReg::toggleInstance("env_settings");
- return true;
- }
-
- if (tod == "sunrise")
- {
- // set the value, turn off animation
- LLWLParamManager::instance()->mAnimator.setDayTime(0.25);
- LLWLParamManager::instance()->mAnimator.mIsRunning = false;
- LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
-
- // then call update once
- LLWLParamManager::instance()->mAnimator.update(
- LLWLParamManager::instance()->mCurParams);
- }
- else if (tod == "noon")
- {
- // set the value, turn off animation
- LLWLParamManager::instance()->mAnimator.setDayTime(0.567);
- LLWLParamManager::instance()->mAnimator.mIsRunning = false;
- LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
-
- // then call update once
- LLWLParamManager::instance()->mAnimator.update(
- LLWLParamManager::instance()->mCurParams);
- }
- else if (tod == "sunset")
- {
- // set the value, turn off animation
- LLWLParamManager::instance()->mAnimator.setDayTime(0.75);
- LLWLParamManager::instance()->mAnimator.mIsRunning = false;
- LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
-
- // then call update once
- LLWLParamManager::instance()->mAnimator.update(
- LLWLParamManager::instance()->mCurParams);
- }
- else if (tod == "midnight")
- {
- // set the value, turn off animation
- LLWLParamManager::instance()->mAnimator.setDayTime(0.0);
- LLWLParamManager::instance()->mAnimator.mIsRunning = false;
- LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
-
- // then call update once
- LLWLParamManager::instance()->mAnimator.update(
- LLWLParamManager::instance()->mCurParams);
- }
- else
- {
- LLWLParamManager::instance()->mAnimator.mIsRunning = true;
- LLWLParamManager::instance()->mAnimator.mUseLindenTime = true;
- }
- return true;
- }
-};
-
-/// Water Menu callbacks
-class LLWorldWaterSettings : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLFloaterReg::toggleInstance("env_water");
- return true;
- }
-};
-
-/// Post-Process callbacks
-class LLWorldPostProcess : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLFloaterReg::showInstance("env_post_process");
- return true;
- }
-};
-
-/// Day Cycle callbacks
-class LLWorldDayCycle : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLFloaterReg::showInstance("env_day_cycle");
- return true;
- }
-};
-
-class LLWorldToggleMovementControls : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLBottomTray::getInstance()->toggleMovementControls();
- return true;
- }
-};
-
-class LLWorldToggleCameraControls : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- LLBottomTray::getInstance()->toggleCameraControls();
- return true;
- }
-};
-
-void handle_flush_name_caches()
-{
- // Toggle display names on and off to flush
- bool use_display_names = LLAvatarNameCache::useDisplayNames();
- LLAvatarNameCache::setUseDisplayNames(!use_display_names);
- LLAvatarNameCache::setUseDisplayNames(use_display_names);
-
- if (gCacheName) gCacheName->clear();
-}
-
-class LLUploadCostCalculator : public view_listener_t
-{
- std::string mCostStr;
-
- bool handleEvent(const LLSD& userdata)
- {
- std::string menu_name = userdata.asString();
- gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr);
-
- return true;
- }
-
- void calculateCost();
-
-public:
- LLUploadCostCalculator()
- {
- calculateCost();
- }
-};
-
-class LLToggleUIHints : public view_listener_t
-{
- bool handleEvent(const LLSD& userdata)
- {
- bool ui_hints_enabled = gSavedSettings.getBOOL("EnableUIHints");
- // toggle
- ui_hints_enabled = !ui_hints_enabled;
- gSavedSettings.setBOOL("EnableUIHints", ui_hints_enabled);
- return true;
- }
-};
-
-void LLUploadCostCalculator::calculateCost()
-{
- S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
-
- // getPriceUpload() returns -1 if no data available yet.
- if(upload_cost >= 0)
- {
- mCostStr = llformat("%d", upload_cost);
- }
- else
- {
- mCostStr = llformat("%d", gSavedSettings.getU32("DefaultUploadCost"));
- }
-}
-
-void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y)
-{
- static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml",
- gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
- if(gMenuHolder->hasVisibleMenu())
- {
- gMenuHolder->hideMenus();
- }
- show_navbar_context_menu->buildDrawLabels();
- show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer);
- LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y);
-}
-
-void show_topinfobar_context_menu(LLView* ctrl, S32 x, S32 y)
-{
- static LLMenuGL* show_topbarinfo_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_topinfobar.xml",
- gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
-
- LLMenuItemGL* landmark_item = show_topbarinfo_context_menu->getChild<LLMenuItemGL>("Landmark");
- if (!LLLandmarkActions::landmarkAlreadyExists())
- {
- landmark_item->setLabel(LLTrans::getString("AddLandmarkNavBarMenu"));
- }
- else
- {
- landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu"));
- }
-
- if(gMenuHolder->hasVisibleMenu())
- {
- gMenuHolder->hideMenus();
- }
-
- show_topbarinfo_context_menu->buildDrawLabels();
- show_topbarinfo_context_menu->updateParent(LLMenuGL::sMenuContainer);
- LLMenuGL::showPopup(ctrl, show_topbarinfo_context_menu, x, y);
-}
-
-void initialize_edit_menu()
-{
- view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo");
- view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo");
- view_listener_t::addMenu(new LLEditCut(), "Edit.Cut");
- view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy");
- view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste");
- view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete");
- view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll");
- view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect");
- view_listener_t::addMenu(new LLEditDuplicate(), "Edit.Duplicate");
- view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff");
- view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo");
- view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo");
- view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut");
- view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy");
- view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste");
- view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete");
- view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll");
- view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect");
- view_listener_t::addMenu(new LLEditEnableDuplicate(), "Edit.EnableDuplicate");
-
-}
-
-void initialize_menus()
-{
- // A parameterized event handler used as ctrl-8/9/0 zoom controls below.
- class LLZoomer : public view_listener_t
- {
- public:
- // The "mult" parameter says whether "val" is a multiplier or used to set the value.
- LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {}
- bool handleEvent(const LLSD& userdata)
- {
- F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal;
- LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad);
- gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it.
- return true;
- }
- private:
- F32 mVal;
- bool mMult;
- };
-
- LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar();
- LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar();
-
- // Generic enable and visible
- // Don't prepend MenuName.Foo because these can be used in any menu.
- enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service));
-
- view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts");
-
- // Agent
- commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying));
- enable.add("Agent.enableFlying", boost::bind(&LLAgent::enableFlying));
-
- // File menu
- init_menu_file();
-
- view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff");
- view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar");
- view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape");
- commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar));
- commit.add("EditOutfit", boost::bind(&handle_edit_outfit));
- commit.add("EditShape", boost::bind(&handle_edit_shape));
-
- // View menu
- view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook");
- view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam");
- view_listener_t::addMenu(new LLViewResetView(), "View.ResetView");
- view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter");
- view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips");
- view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent");
- view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType");
- view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments");
- view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut");
- view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn");
- view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault");
- view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize");
-
- view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook");
- view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam");
- view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter");
-
- view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam");
- view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips");
- view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent");
- view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType");
- view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments");
-
- // Me > Movement
- view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying");
-
- // World menu
- commit.add("World.Chat", boost::bind(&handle_chat, (void*)NULL));
- view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun");
- view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark");
- view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile");
- view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation");
- view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome");
- view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway");
- view_listener_t::addMenu(new LLWorldSetBusy(), "World.SetBusy");
-
- view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark");
- view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation");
- view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome");
- view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand");
-
- view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun");
-
- view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings");
- view_listener_t::addMenu(new LLWorldWaterSettings(), "World.WaterSettings");
- view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess");
- view_listener_t::addMenu(new LLWorldDayCycle(), "World.DayCycle");
-
- view_listener_t::addMenu(new LLWorldToggleMovementControls(), "World.Toggle.MovementControls");
- view_listener_t::addMenu(new LLWorldToggleCameraControls(), "World.Toggle.CameraControls");
-
- // Tools menu
- view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool");
- view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects");
- view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects");
- view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding");
- view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection");
- view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius");
- view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts");
- view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY");
- view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid");
- view_listener_t::addMenu(new LLToolsSelectNextPart(), "Tools.SelectNextPart");
- commit.add("Tools.Link", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()));
- commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
- view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations");
- view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys");
- view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys");
- commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2));
- commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take));
- commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy));
- view_listener_t::addMenu(new LLToolsSaveToInventory(), "Tools.SaveToInventory");
- view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory");
- view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction");
-
- view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie");
- view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart");
- enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance()));
- enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance()));
- view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake");
- enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy));
- enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object));
- enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object));
- view_listener_t::addMenu(new LLToolsEnableSaveToInventory(), "Tools.EnableSaveToInventory");
- view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory");
-
- // Help menu
- // most items use the ShowFloater method
-
- // Advanced menu
- view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole");
- view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole");
- view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole");
-
- // Advanced > HUD Info
- view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo");
- view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo");
-
- // Advanced Other Settings
- view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache");
-
- // Advanced > Render > Types
- view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType");
- view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType");
-
- //// Advanced > Render > Features
- view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature");
- view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature");
- // Advanced > Render > Info Displays
- view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay");
- view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay");
- view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo");
- view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe");
- view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe");
- // Develop > Render
- view_listener_t::addMenu(new LLAdvancedToggleTextureAtlas(), "Advanced.ToggleTextureAtlas");
- view_listener_t::addMenu(new LLAdvancedCheckTextureAtlas(), "Advanced.CheckTextureAtlas");
- view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion");
- view_listener_t::addMenu(new LLAdvancedEnableRenderFBO(), "Advanced.EnableRenderFBO");
- view_listener_t::addMenu(new LLAdvancedEnableRenderDeferred(), "Advanced.EnableRenderDeferred");
- view_listener_t::addMenu(new LLAdvancedEnableRenderDeferredOptions(), "Advanced.EnableRenderDeferredOptions");
- view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate");
- view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate");
- view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame");
- view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame");
- view_listener_t::addMenu(new LLAdvancedVectorizePerfTest(), "Advanced.VectorizePerfTest");
- view_listener_t::addMenu(new LLAdvancedToggleFrameTest(), "Advanced.ToggleFrameTest");
- view_listener_t::addMenu(new LLAdvancedCheckFrameTest(), "Advanced.CheckFrameTest");
- view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles");
- view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption");
- view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption");
-
-
- #ifdef TOGGLE_HACKED_GODLIKE_VIEWER
- view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode");
- view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode");
- view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode");
- #endif
-
- // Advanced > World
- view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera");
- view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache");
-
- // Advanced > UI
- commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser
- commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater
- view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");
- view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");
- view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory");
- commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) );
- commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) );
- view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo");
- view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo");
- view_listener_t::addMenu(new LLAdvancedPrintTextureMemoryStats(), "Advanced.PrintTextureMemoryStats");
- view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks");
- view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks");
- view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews");
- view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews");
- view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips");
- view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips");
- view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents");
- view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents");
- view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys");
- view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys");
- view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc");
- view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc");
- commit.add("Advanced.ShowSideTray", boost::bind(&handle_show_side_tray));
-
- // Advanced > XUI
- commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance()));
- view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames");
- view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames");
- view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs");
- commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches));
-
- // Advanced > Character > Grab Baked Texture
- view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture");
- view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture");
-
- // Advanced > Character > Character Tests
- view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML");
- view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry");
-
- view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale");
- view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale");
- view_listener_t::addMenu(new LLAdvancedTogglePG(), "Advanced.TogglePG");
-
- // Advanced > Character (toplevel)
- view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault");
- view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader");
- view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo");
- view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo");
- view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt");
- view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt");
- view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt");
- view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt");
- view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates");
- view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates");
- view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD");
- view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD");
- view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis");
- view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis");
- view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments");
- view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures");
- view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures");
- view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures");
- // Advanced > Network
- view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog");
- view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog");
- view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket");
-
- // Advanced > Recorder
- view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot");
- view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop");
- view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop");
-
- // Advanced > Debugging
- view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint");
- view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror");
- view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess");
- view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop");
- view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException");
- view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash");
- view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer");
-
- // Advanced (toplevel)
- view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates");
- view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates");
- view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage");
- view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings");
- view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions");
- view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions");
- view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions");
- view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus");
- view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus");
-
-
- // Admin >Object
- view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy");
- view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf");
- view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive");
- view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete");
- view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock");
- view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs");
-
- // Admin >Parcel
- view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe");
- view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent");
- view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand");
-
- // Admin >Region
- view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData");
- // Admin top level
- view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState");
-
- // Self context menu
- view_listener_t::addMenu(new LLSelfStandUp(), "Self.StandUp");
- enable.add("Self.EnableStandUp", boost::bind(&enable_standup_self));
- view_listener_t::addMenu(new LLSelfSitDown(), "Self.SitDown");
- enable.add("Self.EnableSitDown", boost::bind(&enable_sitdown_self));
- view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments");
-
- view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments");
-
- // we don't use boost::bind directly to delay side tray construction
- view_listener_t::addMenu( new LLTogglePanelPeopleTab(), "SideTray.PanelPeopleTab");
-
- // Avatar pie menu
- view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute");
- view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend");
- view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact");
- commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD()));
- view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug");
- view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug");
- view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup");
- commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD()));
- commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector));
- view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM");
- view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call");
- enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
- view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
-
- view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend");
- enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2));
-
- // Object pie menu
- view_listener_t::addMenu(new LLObjectBuild(), "Object.Build");
- commit.add("Object.Touch", boost::bind(&handle_object_touch));
- commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand));
- commit.add("Object.Delete", boost::bind(&handle_object_delete));
- view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar");
- view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar");
- view_listener_t::addMenu(new LLObjectReturn(), "Object.Return");
- view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse");
- view_listener_t::addMenu(new LLObjectMute(), "Object.Mute");
-
- enable.add("Object.VisibleTake", boost::bind(&visible_take_object));
- enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object));
-
- commit.add("Object.Buy", boost::bind(&handle_buy));
- commit.add("Object.Edit", boost::bind(&handle_object_edit));
- commit.add("Object.Inspect", boost::bind(&handle_object_inspect));
- commit.add("Object.Open", boost::bind(&handle_object_open));
- commit.add("Object.Take", boost::bind(&handle_take));
- commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector));
- enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
- enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1));
- enable.add("Object.EnableDelete", boost::bind(&enable_object_delete));
- enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid));
-
- enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up));
- enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1));
-
- view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn");
- view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse");
-
- enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute));
- enable.add("Object.EnableMute", boost::bind(&enable_object_mute));
- enable.add("Object.EnableBuy", boost::bind(&enable_buy_object));
- commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom"));
-
- // Attachment pie menu
- enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2));
- view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop");
- view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint");
- view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach");
- view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled");
- view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop");
- view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach");
-
- // Land pie menu
- view_listener_t::addMenu(new LLLandBuild(), "Land.Build");
- view_listener_t::addMenu(new LLLandSit(), "Land.Sit");
- view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass");
- view_listener_t::addMenu(new LLLandEdit(), "Land.Edit");
-
- view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass");
- commit.add("Land.Buy", boost::bind(&handle_buy_land));
-
- // Generic actions
- commit.add("ReportAbuse", boost::bind(&handle_report_abuse));
- commit.add("BuyCurrency", boost::bind(&handle_buy_currency));
- view_listener_t::addMenu(new LLShowHelp(), "ShowHelp");
- view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL");
- view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile");
- view_listener_t::addMenu(new LLToggleControl(), "ToggleControl");
- view_listener_t::addMenu(new LLCheckControl(), "CheckControl");
- view_listener_t::addMenu(new LLGoToObject(), "GoToObject");
- commit.add("PayObject", boost::bind(&handle_give_money_dialog));
-
- enable.add("EnablePayObject", boost::bind(&enable_pay_object));
- enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar));
- enable.add("EnableEdit", boost::bind(&enable_object_edit));
- enable.add("VisibleBuild", boost::bind(&enable_object_build));
-
- view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible");
- view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel");
- view_listener_t::addMenu(new LLSidetrayPanelVisible(), "SidetrayPanelVisible");
- view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected");
- view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD");
- view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected");
- view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
-
- view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
-
- commit.add("DestinationAndAvatar.show", boost::bind(&LLDestinationAndAvatarShow, _2));
-}
+/**
+ * @file llviewermenu.cpp
+ * @brief Builds menus out of items.
+ *
+ * $LicenseInfo:firstyear=2002&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+#include "llviewermenu.h"
+
+// linden library includes
+#include "llavatarnamecache.h" // IDEVO
+#include "llfloaterreg.h"
+#include "llcombobox.h"
+#include "llinventorypanel.h"
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+
+// newview includes
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llagentwearables.h"
+#include "llagentpilot.h"
+#include "llbottomtray.h"
+#include "llcompilequeue.h"
+#include "llconsole.h"
+#include "lldebugview.h"
+#include "llfilepicker.h"
+#include "llfirstuse.h"
+#include "llfloaterbuy.h"
+#include "llfloaterbuycontents.h"
+#include "llbuycurrencyhtml.h"
+#include "llfloatergodtools.h"
+#include "llfloaterinventory.h"
+#include "llfloaterland.h"
+#include "llfloaterpay.h"
+#include "llfloaterreporter.h"
+#include "llfloatersearch.h"
+#include "llfloaterscriptdebug.h"
+#include "llfloatersnapshot.h"
+#include "llfloatertools.h"
+#include "llfloaterworldmap.h"
+#include "llavataractions.h"
+#include "lllandmarkactions.h"
+#include "llgroupmgr.h"
+#include "lltooltip.h"
+#include "llhints.h"
+#include "llhudeffecttrail.h"
+#include "llhudmanager.h"
+#include "llimview.h"
+#include "llinventorybridge.h"
+#include "llinventorydefines.h"
+#include "llinventoryfunctions.h"
+#include "llpanellogin.h"
+#include "llpanelblockedlist.h"
+#include "llmenucommands.h"
+#include "llmoveview.h"
+#include "llparcel.h"
+#include "llrootview.h"
+#include "llselectmgr.h"
+#include "llsidetray.h"
+#include "llstatusbar.h"
+#include "lltextureview.h"
+#include "lltoolcomp.h"
+#include "lltoolmgr.h"
+#include "lltoolpie.h"
+#include "lltoolselectland.h"
+#include "lltrans.h"
+#include "llviewergenericmessage.h"
+#include "llviewerhelp.h"
+#include "llviewermenufile.h" // init_menu_file()
+#include "llviewermessage.h"
+#include "llviewernetwork.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerstats.h"
+#include "llvoavatarself.h"
+#include "llworldmap.h"
+#include "pipeline.h"
+#include "llviewerjoystick.h"
+#include "llwlanimator.h"
+#include "llwlparammanager.h"
+#include "llfloatercamera.h"
+#include "lluilistener.h"
+#include "llappearancemgr.h"
+#include "lltrans.h"
+#include "lleconomy.h"
+#include "boost/unordered_map.hpp"
+
+using namespace LLVOAvatarDefines;
+
+static boost::unordered_map<std::string, LLStringExplicit> sDefaultItemLabels;
+
+BOOL enable_land_build(void*);
+BOOL enable_object_build(void*);
+
+LLVOAvatar* find_avatar_from_object( LLViewerObject* object );
+LLVOAvatar* find_avatar_from_object( const LLUUID& object_id );
+
+void handle_test_load_url(void*);
+
+//
+// Evil hackish imported globals
+
+//extern BOOL gHideSelectedObjects;
+//extern BOOL gAllowSelectAvatar;
+//extern BOOL gDebugAvatarRotation;
+extern BOOL gDebugClicks;
+extern BOOL gDebugWindowProc;
+//extern BOOL gDebugTextEditorTips;
+//extern BOOL gDebugSelectMgr;
+
+//
+// Globals
+//
+
+LLMenuBarGL *gMenuBarView = NULL;
+LLViewerMenuHolderGL *gMenuHolder = NULL;
+LLMenuGL *gPopupMenuView = NULL;
+LLMenuGL *gEditMenu = NULL;
+LLMenuBarGL *gLoginMenuBarView = NULL;
+
+// Pie menus
+LLContextMenu *gMenuAvatarSelf = NULL;
+LLContextMenu *gMenuAvatarOther = NULL;
+LLContextMenu *gMenuObject = NULL;
+LLContextMenu *gMenuAttachmentSelf = NULL;
+LLContextMenu *gMenuAttachmentOther = NULL;
+LLContextMenu *gMenuLand = NULL;
+
+const std::string SAVE_INTO_INVENTORY("Save Object Back to My Inventory");
+const std::string SAVE_INTO_TASK_INVENTORY("Save Object Back to Object Contents");
+
+LLMenuGL* gAttachSubMenu = NULL;
+LLMenuGL* gDetachSubMenu = NULL;
+LLMenuGL* gTakeOffClothes = NULL;
+LLContextMenu* gAttachScreenPieMenu = NULL;
+LLContextMenu* gAttachPieMenu = NULL;
+LLContextMenu* gAttachBodyPartPieMenus[8];
+LLContextMenu* gDetachPieMenu = NULL;
+LLContextMenu* gDetachScreenPieMenu = NULL;
+LLContextMenu* gDetachBodyPartPieMenus[8];
+
+LLMenuItemCallGL* gAFKMenu = NULL;
+LLMenuItemCallGL* gBusyMenu = NULL;
+
+//
+// Local prototypes
+
+// File Menu
+const char* upload_pick(void* data);
+void handle_compress_image(void*);
+
+
+// Edit menu
+void handle_dump_group_info(void *);
+void handle_dump_capabilities_info(void *);
+
+// Advanced->Consoles menu
+void handle_region_dump_settings(void*);
+void handle_region_dump_temp_asset_data(void*);
+void handle_region_clear_temp_asset_data(void*);
+
+// Object pie menu
+BOOL sitting_on_selection();
+
+void near_sit_object();
+//void label_sit_or_stand(std::string& label, void*);
+// buy and take alias into the same UI positions, so these
+// declarations handle this mess.
+BOOL is_selection_buy_not_take();
+S32 selection_price();
+BOOL enable_take();
+void handle_take();
+void handle_object_show_inspector();
+void handle_avatar_show_inspector();
+bool confirm_take(const LLSD& notification, const LLSD& response);
+
+void handle_buy_object(LLSaleInfo sale_info);
+void handle_buy_contents(LLSaleInfo sale_info);
+
+// Land pie menu
+void near_sit_down_point(BOOL success, void *);
+
+// Avatar pie menu
+
+// Debug menu
+
+
+void velocity_interpolate( void* );
+
+void handle_rebake_textures(void*);
+BOOL check_admin_override(void*);
+void handle_admin_override_toggle(void*);
+#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+void handle_toggle_hacked_godmode(void*);
+BOOL check_toggle_hacked_godmode(void*);
+bool enable_toggle_hacked_godmode(void*);
+#endif
+
+void toggle_show_xui_names(void *);
+BOOL check_show_xui_names(void *);
+
+// Debug UI
+
+void handle_buy_currency_test(void*);
+
+void handle_god_mode(void*);
+
+// God menu
+void handle_leave_god_mode(void*);
+
+
+void handle_reset_view();
+
+void handle_duplicate_in_place(void*);
+
+
+void handle_object_owner_self(void*);
+void handle_object_owner_permissive(void*);
+void handle_object_lock(void*);
+void handle_object_asset_ids(void*);
+void force_take_copy(void*);
+#ifdef _CORY_TESTING
+void force_export_copy(void*);
+void force_import_geometry(void*);
+#endif
+
+void handle_force_parcel_owner_to_me(void*);
+void handle_force_parcel_to_content(void*);
+void handle_claim_public_land(void*);
+
+void handle_god_request_avatar_geometry(void *); // Hack for easy testing of new avatar geometry
+void reload_vertex_shader(void *);
+void handle_disconnect_viewer(void *);
+
+void force_error_breakpoint(void *);
+void force_error_llerror(void *);
+void force_error_bad_memory_access(void *);
+void force_error_infinite_loop(void *);
+void force_error_software_exception(void *);
+void force_error_driver_crash(void *);
+
+void handle_force_delete(void*);
+void print_object_info(void*);
+void print_agent_nvpairs(void*);
+void toggle_debug_menus(void*);
+void upload_done_callback(const LLUUID& uuid, void* user_data, S32 result, LLExtStat ext_status);
+void dump_select_mgr(void*);
+
+void dump_inventory(void*);
+void toggle_visibility(void*);
+BOOL get_visibility(void*);
+
+// Avatar Pie menu
+void request_friendship(const LLUUID& agent_id);
+
+// Tools menu
+void handle_selected_texture_info(void*);
+
+void handle_dump_followcam(void*);
+void handle_viewer_enable_message_log(void*);
+void handle_viewer_disable_message_log(void*);
+
+BOOL enable_buy_land(void*);
+
+// Help menu
+
+void handle_test_male(void *);
+void handle_test_female(void *);
+void handle_toggle_pg(void*);
+void handle_dump_attachments(void *);
+void handle_dump_avatar_local_textures(void*);
+void handle_debug_avatar_textures(void*);
+void handle_grab_baked_texture(void*);
+BOOL enable_grab_baked_texture(void*);
+void handle_dump_region_object_cache(void*);
+
+BOOL enable_save_into_inventory(void*);
+BOOL enable_save_into_task_inventory(void*);
+
+BOOL enable_detach(const LLSD& = LLSD());
+void menu_toggle_attached_lights(void* user_data);
+void menu_toggle_attached_particles(void* user_data);
+
+class LLMenuParcelObserver : public LLParcelObserver
+{
+public:
+ LLMenuParcelObserver();
+ ~LLMenuParcelObserver();
+ virtual void changed();
+};
+
+static LLMenuParcelObserver* gMenuParcelObserver = NULL;
+
+static LLUIListener sUIListener;
+
+LLMenuParcelObserver::LLMenuParcelObserver()
+{
+ LLViewerParcelMgr::getInstance()->addObserver(this);
+}
+
+LLMenuParcelObserver::~LLMenuParcelObserver()
+{
+ LLViewerParcelMgr::getInstance()->removeObserver(this);
+}
+
+void LLMenuParcelObserver::changed()
+{
+ gMenuHolder->childSetEnabled("Land Buy Pass", LLPanelLandGeneral::enableBuyPass(NULL));
+
+ BOOL buyable = enable_buy_land(NULL);
+ gMenuHolder->childSetEnabled("Land Buy", buyable);
+ gMenuHolder->childSetEnabled("Buy Land...", buyable);
+}
+
+
+void initialize_menus();
+
+//-----------------------------------------------------------------------------
+// Initialize main menus
+//
+// HOW TO NAME MENUS:
+//
+// First Letter Of Each Word Is Capitalized, Even At Or And
+//
+// Items that lead to dialog boxes end in "..."
+//
+// Break up groups of more than 6 items with separators
+//-----------------------------------------------------------------------------
+
+void set_underclothes_menu_options()
+{
+ if (gMenuHolder && gAgent.isTeen())
+ {
+ gMenuHolder->getChild<LLView>("Self Underpants")->setVisible(FALSE);
+ gMenuHolder->getChild<LLView>("Self Undershirt")->setVisible(FALSE);
+ }
+ if (gMenuBarView && gAgent.isTeen())
+ {
+ gMenuBarView->getChild<LLView>("Menu Underpants")->setVisible(FALSE);
+ gMenuBarView->getChild<LLView>("Menu Undershirt")->setVisible(FALSE);
+ }
+}
+
+void init_menus()
+{
+ S32 top = gViewerWindow->getRootView()->getRect().getHeight();
+
+ // Initialize actions
+ initialize_menus();
+
+ ///
+ /// Popup menu
+ ///
+ /// The popup menu is now populated by the show_context_menu()
+ /// method.
+
+ LLMenuGL::Params menu_params;
+ menu_params.name = "Popup";
+ menu_params.visible = false;
+ gPopupMenuView = LLUICtrlFactory::create<LLMenuGL>(menu_params);
+ gMenuHolder->addChild( gPopupMenuView );
+
+ ///
+ /// Context menus
+ ///
+
+ const widget_registry_t& registry =
+ LLViewerMenuHolderGL::child_registry_t::instance();
+ gEditMenu = LLUICtrlFactory::createFromFile<LLMenuGL>("menu_edit.xml", gMenuHolder, registry);
+ gMenuAvatarSelf = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_avatar_self.xml", gMenuHolder, registry);
+ gMenuAvatarOther = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_avatar_other.xml", gMenuHolder, registry);
+
+ gDetachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach HUD", true);
+ gDetachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Detach", true);
+
+ gMenuObject = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_object.xml", gMenuHolder, registry);
+
+ gAttachScreenPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach HUD");
+ gAttachPieMenu = gMenuHolder->getChild<LLContextMenu>("Object Attach");
+
+ gMenuAttachmentSelf = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_attachment_self.xml", gMenuHolder, registry);
+ gMenuAttachmentOther = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_attachment_other.xml", gMenuHolder, registry);
+
+ gMenuLand = LLUICtrlFactory::createFromFile<LLContextMenu>(
+ "menu_land.xml", gMenuHolder, registry);
+
+ ///
+ /// set up the colors
+ ///
+ LLColor4 color;
+
+ LLColor4 context_menu_color = LLUIColorTable::instance().getColor("MenuPopupBgColor");
+
+ gMenuAvatarSelf->setBackgroundColor( context_menu_color );
+ gMenuAvatarOther->setBackgroundColor( context_menu_color );
+ gMenuObject->setBackgroundColor( context_menu_color );
+ gMenuAttachmentSelf->setBackgroundColor( context_menu_color );
+ gMenuAttachmentOther->setBackgroundColor( context_menu_color );
+
+ gMenuLand->setBackgroundColor( context_menu_color );
+
+ color = LLUIColorTable::instance().getColor( "MenuPopupBgColor" );
+ gPopupMenuView->setBackgroundColor( color );
+
+ // If we are not in production, use a different color to make it apparent.
+ if (LLGridManager::getInstance()->isInProductionGrid())
+ {
+ color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
+ }
+ else
+ {
+ color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
+ }
+ gMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_viewer.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ gMenuBarView->setRect(LLRect(0, top, 0, top - MENU_BAR_HEIGHT));
+ gMenuBarView->setBackgroundColor( color );
+
+ LLView* menu_bar_holder = gViewerWindow->getRootView()->getChildView("menu_bar_holder");
+ menu_bar_holder->addChild(gMenuBarView);
+
+ gViewerWindow->setMenuBackgroundColor(false,
+ LLGridManager::getInstance()->isInProductionGrid());
+
+ // Assume L$10 for now, the server will tell us the real cost at login
+ // *TODO:Also fix cost in llfolderview.cpp for Inventory menus
+ const std::string upload_cost("10");
+ gMenuHolder->childSetLabelArg("Upload Image", "[COST]", upload_cost);
+ gMenuHolder->childSetLabelArg("Upload Sound", "[COST]", upload_cost);
+ gMenuHolder->childSetLabelArg("Upload Animation", "[COST]", upload_cost);
+ gMenuHolder->childSetLabelArg("Bulk Upload", "[COST]", upload_cost);
+
+ gAFKMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Away", TRUE);
+ gBusyMenu = gMenuBarView->getChild<LLMenuItemCallGL>("Set Busy", TRUE);
+ gAttachSubMenu = gMenuBarView->findChildMenuByName("Attach Object", TRUE);
+ gDetachSubMenu = gMenuBarView->findChildMenuByName("Detach Object", TRUE);
+
+#if !MEM_TRACK_MEM
+ // Don't display the Memory console menu if the feature is turned off
+ LLMenuItemCheckGL *memoryMenu = gMenuBarView->getChild<LLMenuItemCheckGL>("Memory", TRUE);
+ if (memoryMenu)
+ {
+ memoryMenu->setVisible(FALSE);
+ }
+#endif
+
+ gMenuBarView->createJumpKeys();
+
+ // Let land based option enable when parcel changes
+ gMenuParcelObserver = new LLMenuParcelObserver();
+
+ gLoginMenuBarView = LLUICtrlFactory::getInstance()->createFromFile<LLMenuBarGL>("menu_login.xml", gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ gLoginMenuBarView->arrangeAndClear();
+ LLRect menuBarRect = gLoginMenuBarView->getRect();
+ menuBarRect.setLeftTopAndSize(0, menu_bar_holder->getRect().getHeight(), menuBarRect.getWidth(), menuBarRect.getHeight());
+ gLoginMenuBarView->setRect(menuBarRect);
+ gLoginMenuBarView->setBackgroundColor( color );
+ menu_bar_holder->addChild(gLoginMenuBarView);
+
+ // tooltips are on top of EVERYTHING, including menus
+ gViewerWindow->getRootView()->sendChildToFront(gToolTipView);
+}
+
+///////////////////
+// SHOW CONSOLES //
+///////////////////
+
+
+class LLAdvancedToggleConsole : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string console_type = userdata.asString();
+ if ("texture" == console_type)
+ {
+ toggle_visibility( (void*)gTextureView );
+ }
+ else if ("debug" == console_type)
+ {
+ toggle_visibility( (void*)static_cast<LLUICtrl*>(gDebugView->mDebugConsolep));
+ }
+ else if (gTextureSizeView && "texture size" == console_type)
+ {
+ toggle_visibility( (void*)gTextureSizeView );
+ }
+ else if (gTextureCategoryView && "texture category" == console_type)
+ {
+ toggle_visibility( (void*)gTextureCategoryView );
+ }
+ else if ("fast timers" == console_type)
+ {
+ toggle_visibility( (void*)gDebugView->mFastTimerView );
+ }
+#if MEM_TRACK_MEM
+ else if ("memory view" == console_type)
+ {
+ toggle_visibility( (void*)gDebugView->mMemoryView );
+ }
+#endif
+ return true;
+ }
+};
+class LLAdvancedCheckConsole : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string console_type = userdata.asString();
+ bool new_value = false;
+ if ("texture" == console_type)
+ {
+ new_value = get_visibility( (void*)gTextureView );
+ }
+ else if ("debug" == console_type)
+ {
+ new_value = get_visibility( (void*)((LLView*)gDebugView->mDebugConsolep) );
+ }
+ else if (gTextureSizeView && "texture size" == console_type)
+ {
+ new_value = get_visibility( (void*)gTextureSizeView );
+ }
+ else if (gTextureCategoryView && "texture category" == console_type)
+ {
+ new_value = get_visibility( (void*)gTextureCategoryView );
+ }
+ else if ("fast timers" == console_type)
+ {
+ new_value = get_visibility( (void*)gDebugView->mFastTimerView );
+ }
+#if MEM_TRACK_MEM
+ else if ("memory view" == console_type)
+ {
+ new_value = get_visibility( (void*)gDebugView->mMemoryView );
+ }
+#endif
+
+ return new_value;
+ }
+};
+
+
+//////////////////////////
+// DUMP INFO TO CONSOLE //
+//////////////////////////
+
+
+class LLAdvancedDumpInfoToConsole : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string info_type = userdata.asString();
+ if ("region" == info_type)
+ {
+ handle_region_dump_settings(NULL);
+ }
+ else if ("group" == info_type)
+ {
+ handle_dump_group_info(NULL);
+ }
+ else if ("capabilities" == info_type)
+ {
+ handle_dump_capabilities_info(NULL);
+ }
+ return true;
+ }
+};
+
+
+//////////////
+// HUD INFO //
+//////////////
+
+
+class LLAdvancedToggleHUDInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string info_type = userdata.asString();
+
+ if ("camera" == info_type)
+ {
+ gDisplayCameraPos = !(gDisplayCameraPos);
+ }
+ else if ("wind" == info_type)
+ {
+ gDisplayWindInfo = !(gDisplayWindInfo);
+ }
+ else if ("fov" == info_type)
+ {
+ gDisplayFOV = !(gDisplayFOV);
+ }
+ else if ("badge" == info_type)
+ {
+ gDisplayBadge = !(gDisplayBadge);
+ }
+ return true;
+ }
+};
+
+class LLAdvancedCheckHUDInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string info_type = userdata.asString();
+ bool new_value = false;
+ if ("camera" == info_type)
+ {
+ new_value = gDisplayCameraPos;
+ }
+ else if ("wind" == info_type)
+ {
+ new_value = gDisplayWindInfo;
+ }
+ else if ("fov" == info_type)
+ {
+ new_value = gDisplayFOV;
+ }
+ else if ("badge" == info_type)
+ {
+ new_value = gDisplayBadge;
+ }
+ return new_value;
+ }
+};
+
+
+//////////////
+// FLYING //
+//////////////
+
+class LLAdvancedAgentFlyingInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD&)
+ {
+ return gAgent.getFlying();
+ }
+};
+
+
+///////////////////////
+// CLEAR GROUP CACHE //
+///////////////////////
+
+class LLAdvancedClearGroupCache : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLGroupMgr::debugClearAllGroups(NULL);
+ return true;
+ }
+};
+
+
+
+
+/////////////////
+// RENDER TYPE //
+/////////////////
+U32 render_type_from_string(std::string render_type)
+{
+ if ("simple" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_SIMPLE;
+ }
+ else if ("alpha" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_ALPHA;
+ }
+ else if ("tree" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_TREE;
+ }
+ else if ("character" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_AVATAR;
+ }
+ else if ("surfacePath" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_TERRAIN;
+ }
+ else if ("sky" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_SKY;
+ }
+ else if ("water" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_WATER;
+ }
+ else if ("ground" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_GROUND;
+ }
+ else if ("volume" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_VOLUME;
+ }
+ else if ("grass" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_GRASS;
+ }
+ else if ("clouds" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_CLOUDS;
+ }
+ else if ("particles" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_PARTICLES;
+ }
+ else if ("bump" == render_type)
+ {
+ return LLPipeline::RENDER_TYPE_BUMP;
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+
+class LLAdvancedToggleRenderType : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ U32 render_type = render_type_from_string( userdata.asString() );
+ if ( render_type != 0 )
+ {
+ LLPipeline::toggleRenderTypeControl( (void*)render_type );
+ }
+ return true;
+ }
+};
+
+
+class LLAdvancedCheckRenderType : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ U32 render_type = render_type_from_string( userdata.asString() );
+ bool new_value = false;
+
+ if ( render_type != 0 )
+ {
+ new_value = LLPipeline::hasRenderTypeControl( (void*)render_type );
+ }
+
+ return new_value;
+ }
+};
+
+
+/////////////
+// FEATURE //
+/////////////
+U32 feature_from_string(std::string feature)
+{
+ if ("ui" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_UI;
+ }
+ else if ("selected" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_SELECTED;
+ }
+ else if ("highlighted" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_HIGHLIGHTED;
+ }
+ else if ("dynamic textures" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_DYNAMIC_TEXTURES;
+ }
+ else if ("foot shadows" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_FOOT_SHADOWS;
+ }
+ else if ("fog" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_FOG;
+ }
+ else if ("fr info" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_FR_INFO;
+ }
+ else if ("flexible" == feature)
+ {
+ return LLPipeline::RENDER_DEBUG_FEATURE_FLEXIBLE;
+ }
+ else
+ {
+ return 0;
+ }
+};
+
+
+class LLAdvancedToggleFeature : public view_listener_t{
+ bool handleEvent(const LLSD& userdata)
+ {
+ U32 feature = feature_from_string( userdata.asString() );
+ if ( feature != 0 )
+ {
+ LLPipeline::toggleRenderDebugFeature( (void*)feature );
+ }
+ return true;
+ }
+};
+
+class LLAdvancedCheckFeature : public view_listener_t
+{bool handleEvent(const LLSD& userdata)
+{
+ U32 feature = feature_from_string( userdata.asString() );
+ bool new_value = false;
+
+ if ( feature != 0 )
+ {
+ new_value = LLPipeline::toggleRenderDebugFeatureControl( (void*)feature );
+ }
+
+ return new_value;
+}
+};
+
+void toggle_destination_and_avatar_picker(const LLSD& show)
+{
+ S32 panel_idx = show.isDefined() ? show.asInteger() : -1;
+ LLView* container = gViewerWindow->getRootView()->getChildView("avatar_picker_and_destination_guide_container");
+ LLMediaCtrl* destinations = container->findChild<LLMediaCtrl>("destination_guide_contents");
+ LLMediaCtrl* avatar_picker = container->findChild<LLMediaCtrl>("avatar_picker_contents");
+ LLButton* avatar_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("avatar_btn");
+ LLButton* destination_btn = gViewerWindow->getRootView()->getChildView("bottom_tray")->getChild<LLButton>("destination_btn");
+
+ switch(panel_idx)
+ {
+ case 0:
+ container->setVisible(true);
+ destinations->setVisible(true);
+ avatar_picker->setVisible(false);
+ LLFirstUse::notUsingDestinationGuide(false);
+ avatar_btn->setToggleState(false);
+ destination_btn->setToggleState(true);
+ break;
+ case 1:
+ container->setVisible(true);
+ destinations->setVisible(false);
+ avatar_picker->setVisible(true);
+ avatar_btn->setToggleState(true);
+ destination_btn->setToggleState(false);
+ break;
+ default:
+ container->setVisible(false);
+ destinations->setVisible(false);
+ avatar_picker->setVisible(false);
+ avatar_btn->setToggleState(false);
+ destination_btn->setToggleState(false);
+ break;
+ }
+};
+
+
+//////////////////
+// INFO DISPLAY //
+//////////////////
+U32 info_display_from_string(std::string info_display)
+{
+ if ("verify" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_VERIFY;
+ }
+ else if ("bboxes" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_BBOXES;
+ }
+ else if ("points" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_POINTS;
+ }
+ else if ("octree" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_OCTREE;
+ }
+ else if ("shadow frusta" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA;
+ }
+ else if ("occlusion" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_OCCLUSION;
+ }
+ else if ("render batches" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_BATCH_SIZE;
+ }
+ else if ("update type" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_UPDATE_TYPE;
+ }
+ else if ("texture anim" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_TEXTURE_ANIM;
+ }
+ else if ("texture priority" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_TEXTURE_PRIORITY;
+ }
+ else if ("shame" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_SHAME;
+ }
+ else if ("texture area" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_TEXTURE_AREA;
+ }
+ else if ("face area" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_FACE_AREA;
+ }
+ else if ("lights" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_LIGHTS;
+ }
+ else if ("particles" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_PARTICLES;
+ }
+ else if ("composition" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_COMPOSITION;
+ }
+ else if ("glow" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_GLOW;
+ }
+ else if ("collision skeleton" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_AVATAR_VOLUME;
+ }
+ else if ("raycast" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_RAYCAST;
+ }
+ else if ("agent target" == info_display)
+ {
+ return LLPipeline::RENDER_DEBUG_AGENT_TARGET;
+ }
+ else
+ {
+ return 0;
+ }
+};
+
+class LLAdvancedToggleInfoDisplay : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ U32 info_display = info_display_from_string( userdata.asString() );
+
+ if ( info_display != 0 )
+ {
+ LLPipeline::toggleRenderDebug( (void*)info_display );
+ }
+
+ return true;
+ }
+};
+
+
+class LLAdvancedCheckInfoDisplay : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ U32 info_display = info_display_from_string( userdata.asString() );
+ bool new_value = false;
+
+ if ( info_display != 0 )
+ {
+ new_value = LLPipeline::toggleRenderDebugControl( (void*)info_display );
+ }
+
+ return new_value;
+ }
+};
+
+
+///////////////////////////
+//// RANDOMIZE FRAMERATE //
+///////////////////////////
+
+
+class LLAdvancedToggleRandomizeFramerate : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gRandomizeFramerate = !(gRandomizeFramerate);
+ return true;
+ }
+};
+
+class LLAdvancedCheckRandomizeFramerate : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gRandomizeFramerate;
+ return new_value;
+ }
+};
+
+void run_vectorize_perf_test(void *)
+{
+ gSavedSettings.setBOOL("VectorizePerfTest", TRUE);
+}
+
+
+////////////////////////////////
+// RUN Vectorized Perform Test//
+////////////////////////////////
+
+
+class LLAdvancedVectorizePerfTest : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ run_vectorize_perf_test(NULL);
+ return true;
+ }
+};
+
+///////////////////////////
+//// PERIODIC SLOW FRAME //
+///////////////////////////
+
+
+class LLAdvancedTogglePeriodicSlowFrame : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gPeriodicSlowFrame = !(gPeriodicSlowFrame);
+ return true;
+ }
+};
+
+class LLAdvancedCheckPeriodicSlowFrame : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gPeriodicSlowFrame;
+ return new_value;
+ }
+};
+
+
+
+////////////////
+// FRAME TEST //
+////////////////
+
+
+class LLAdvancedToggleFrameTest : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPipeline::sRenderFrameTest = !(LLPipeline::sRenderFrameTest);
+ return true;
+ }
+};
+
+class LLAdvancedCheckFrameTest : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLPipeline::sRenderFrameTest;
+ return new_value;
+ }
+};
+
+
+///////////////////////////
+// SELECTED TEXTURE INFO //
+///////////////////////////
+
+
+class LLAdvancedSelectedTextureInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_selected_texture_info(NULL);
+ return true;
+ }
+};
+
+//////////////////////
+// TOGGLE WIREFRAME //
+//////////////////////
+
+class LLAdvancedToggleWireframe : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gUseWireframe = !(gUseWireframe);
+ LLPipeline::updateRenderDeferred();
+ gPipeline.resetVertexBuffers();
+ return true;
+ }
+};
+
+class LLAdvancedCheckWireframe : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gUseWireframe;
+ return new_value;
+ }
+};
+
+//////////////////////
+// TEXTURE ATLAS //
+//////////////////////
+
+class LLAdvancedToggleTextureAtlas : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerTexture::sUseTextureAtlas = !LLViewerTexture::sUseTextureAtlas;
+ gSavedSettings.setBOOL("EnableTextureAtlas", LLViewerTexture::sUseTextureAtlas) ;
+ return true;
+ }
+};
+
+class LLAdvancedCheckTextureAtlas : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLViewerTexture::sUseTextureAtlas; // <-- make this using LLCacheControl
+ return new_value;
+ }
+};
+
+//////////////////////////
+// DUMP SCRIPTED CAMERA //
+//////////////////////////
+
+class LLAdvancedDumpScriptedCamera : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_dump_followcam(NULL);
+ return true;
+}
+};
+
+
+
+//////////////////////////////
+// DUMP REGION OBJECT CACHE //
+//////////////////////////////
+
+
+class LLAdvancedDumpRegionObjectCache : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+{
+ handle_dump_region_object_cache(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedBuyCurrencyTest : public view_listener_t
+ {
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_buy_currency_test(NULL);
+ return true;
+ }
+};
+
+
+/////////////////////
+// DUMP SELECT MGR //
+/////////////////////
+
+
+class LLAdvancedDumpSelectMgr : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ dump_select_mgr(NULL);
+ return true;
+ }
+};
+
+
+
+////////////////////
+// DUMP INVENTORY //
+////////////////////
+
+
+class LLAdvancedDumpInventory : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ dump_inventory(NULL);
+ return true;
+ }
+};
+
+
+
+////////////////////////////////
+// PRINT SELECTED OBJECT INFO //
+////////////////////////////////
+
+
+class LLAdvancedPrintSelectedObjectInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ print_object_info(NULL);
+ return true;
+ }
+};
+
+
+
+//////////////////////
+// PRINT AGENT INFO //
+//////////////////////
+
+
+class LLAdvancedPrintAgentInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ print_agent_nvpairs(NULL);
+ return true;
+ }
+};
+
+
+
+////////////////////////////////
+// PRINT TEXTURE MEMORY STATS //
+////////////////////////////////
+
+
+class LLAdvancedPrintTextureMemoryStats : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ output_statistics(NULL);
+ return true;
+ }
+};
+
+//////////////////
+// DEBUG CLICKS //
+//////////////////
+
+
+class LLAdvancedToggleDebugClicks : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gDebugClicks = !(gDebugClicks);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugClicks : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gDebugClicks;
+ return new_value;
+ }
+};
+
+
+
+/////////////////
+// DEBUG VIEWS //
+/////////////////
+
+
+class LLAdvancedToggleDebugViews : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLView::sDebugRects = !(LLView::sDebugRects);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugViews : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLView::sDebugRects;
+ return new_value;
+ }
+};
+
+
+
+///////////////////////
+// XUI NAME TOOLTIPS //
+///////////////////////
+
+
+class LLAdvancedToggleXUINameTooltips : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ toggle_show_xui_names(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedCheckXUINameTooltips : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = check_show_xui_names(NULL);
+ return new_value;
+ }
+};
+
+
+
+////////////////////////
+// DEBUG MOUSE EVENTS //
+////////////////////////
+
+
+class LLAdvancedToggleDebugMouseEvents : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLView::sDebugMouseHandling = !(LLView::sDebugMouseHandling);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugMouseEvents : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLView::sDebugMouseHandling;
+ return new_value;
+ }
+};
+
+
+
+////////////////
+// DEBUG KEYS //
+////////////////
+
+
+class LLAdvancedToggleDebugKeys : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLView::sDebugKeys = !(LLView::sDebugKeys);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugKeys : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLView::sDebugKeys;
+ return new_value;
+ }
+};
+
+
+
+///////////////////////
+// DEBUG WINDOW PROC //
+///////////////////////
+
+
+class LLAdvancedToggleDebugWindowProc : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gDebugWindowProc = !(gDebugWindowProc);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugWindowProc : public view_listener_t
+ {
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gDebugWindowProc;
+ return new_value;
+ }
+};
+
+// ------------------------------XUI MENU ---------------------------
+
+class LLAdvancedSendTestIms : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLIMModel::instance().testMessages();
+ return true;
+}
+};
+
+
+///////////////
+// XUI NAMES //
+///////////////
+
+
+class LLAdvancedToggleXUINames : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ toggle_show_xui_names(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedCheckXUINames : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = check_show_xui_names(NULL);
+ return new_value;
+ }
+};
+
+
+////////////////////////
+// GRAB BAKED TEXTURE //
+////////////////////////
+
+
+class LLAdvancedGrabBakedTexture : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string texture_type = userdata.asString();
+ if ("iris" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_EYES );
+ }
+ else if ("head" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_HEAD );
+ }
+ else if ("upper" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_UPPER );
+ }
+ else if ("lower" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_LOWER );
+ }
+ else if ("skirt" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_SKIRT );
+ }
+ else if ("hair" == texture_type)
+ {
+ handle_grab_baked_texture( (void*)BAKED_HAIR );
+ }
+
+ return true;
+ }
+};
+
+class LLAdvancedEnableGrabBakedTexture : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+{
+ std::string texture_type = userdata.asString();
+ bool new_value = false;
+
+ if ("iris" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_EYES );
+ }
+ else if ("head" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_HEAD );
+ }
+ else if ("upper" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_UPPER );
+ }
+ else if ("lower" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_LOWER );
+ }
+ else if ("skirt" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_SKIRT );
+ }
+ else if ("hair" == texture_type)
+ {
+ new_value = enable_grab_baked_texture( (void*)BAKED_HAIR );
+ }
+
+ return new_value;
+}
+};
+
+///////////////////////
+// APPEARANCE TO XML //
+///////////////////////
+
+
+class LLAdvancedAppearanceToXML : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar::dumpArchetypeXML(NULL);
+ return true;
+ }
+};
+
+
+
+///////////////////////////////
+// TOGGLE CHARACTER GEOMETRY //
+///////////////////////////////
+
+
+class LLAdvancedToggleCharacterGeometry : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_god_request_avatar_geometry(NULL);
+ return true;
+}
+};
+
+
+ /////////////////////////////
+// TEST MALE / TEST FEMALE //
+/////////////////////////////
+
+class LLAdvancedTestMale : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_test_male(NULL);
+ return true;
+ }
+};
+
+
+class LLAdvancedTestFemale : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_test_female(NULL);
+ return true;
+ }
+};
+
+
+
+///////////////
+// TOGGLE PG //
+///////////////
+
+
+class LLAdvancedTogglePG : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_toggle_pg(NULL);
+ return true;
+ }
+};
+
+
+class LLAdvancedForceParamsToDefault : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLAgent::clearVisualParams(NULL);
+ return true;
+ }
+};
+
+
+
+//////////////////////////
+// RELOAD VERTEX SHADER //
+//////////////////////////
+
+
+class LLAdvancedReloadVertexShader : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ reload_vertex_shader(NULL);
+ return true;
+ }
+};
+
+
+
+////////////////////
+// ANIMATION INFO //
+////////////////////
+
+
+class LLAdvancedToggleAnimationInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar::sShowAnimationDebug = !(LLVOAvatar::sShowAnimationDebug);
+ return true;
+ }
+};
+
+class LLAdvancedCheckAnimationInfo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLVOAvatar::sShowAnimationDebug;
+ return new_value;
+ }
+};
+
+
+//////////////////
+// SHOW LOOK AT //
+//////////////////
+
+
+class LLAdvancedToggleShowLookAt : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLHUDEffectLookAt::sDebugLookAt = !(LLHUDEffectLookAt::sDebugLookAt);
+ return true;
+ }
+};
+
+class LLAdvancedCheckShowLookAt : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLHUDEffectLookAt::sDebugLookAt;
+ return new_value;
+ }
+};
+
+
+
+///////////////////
+// SHOW POINT AT //
+///////////////////
+
+
+class LLAdvancedToggleShowPointAt : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLHUDEffectPointAt::sDebugPointAt = !(LLHUDEffectPointAt::sDebugPointAt);
+ return true;
+ }
+};
+
+class LLAdvancedCheckShowPointAt : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLHUDEffectPointAt::sDebugPointAt;
+ return new_value;
+ }
+};
+
+
+
+/////////////////////////
+// DEBUG JOINT UPDATES //
+/////////////////////////
+
+
+class LLAdvancedToggleDebugJointUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar::sJointDebug = !(LLVOAvatar::sJointDebug);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugJointUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLVOAvatar::sJointDebug;
+ return new_value;
+ }
+};
+
+
+
+/////////////////
+// DISABLE LOD //
+/////////////////
+
+
+class LLAdvancedToggleDisableLOD : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerJoint::sDisableLOD = !(LLViewerJoint::sDisableLOD);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDisableLOD : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLViewerJoint::sDisableLOD;
+ return new_value;
+ }
+};
+
+
+
+/////////////////////////
+// DEBUG CHARACTER VIS //
+/////////////////////////
+
+
+class LLAdvancedToggleDebugCharacterVis : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar::sDebugInvisible = !(LLVOAvatar::sDebugInvisible);
+ return true;
+ }
+};
+
+class LLAdvancedCheckDebugCharacterVis : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLVOAvatar::sDebugInvisible;
+ return new_value;
+ }
+};
+
+
+//////////////////////
+// DUMP ATTACHMENTS //
+//////////////////////
+
+
+class LLAdvancedDumpAttachments : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_dump_attachments(NULL);
+ return true;
+ }
+};
+
+
+
+/////////////////////
+// REBAKE TEXTURES //
+/////////////////////
+
+
+class LLAdvancedRebakeTextures : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_rebake_textures(NULL);
+ return true;
+ }
+};
+
+
+#if 1 //ndef LL_RELEASE_FOR_DOWNLOAD
+///////////////////////////
+// DEBUG AVATAR TEXTURES //
+///////////////////////////
+
+
+class LLAdvancedDebugAvatarTextures : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgent.isGodlike())
+ {
+ handle_debug_avatar_textures(NULL);
+ }
+ return true;
+ }
+};
+
+////////////////////////////////
+// DUMP AVATAR LOCAL TEXTURES //
+////////////////////////////////
+
+
+class LLAdvancedDumpAvatarLocalTextures : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+#ifndef LL_RELEASE_FOR_DOWNLOAD
+ handle_dump_avatar_local_textures(NULL);
+#endif
+ return true;
+ }
+};
+
+#endif
+
+/////////////////
+// MESSAGE LOG //
+/////////////////
+
+
+class LLAdvancedEnableMessageLog : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_viewer_enable_message_log(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedDisableMessageLog : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_viewer_disable_message_log(NULL);
+ return true;
+ }
+};
+
+/////////////////
+// DROP PACKET //
+/////////////////
+
+
+class LLAdvancedDropPacket : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gMessageSystem->mPacketRing.dropPackets(1);
+ return true;
+ }
+};
+
+
+
+/////////////////
+// AGENT PILOT //
+/////////////////
+
+
+class LLAdvancedAgentPilot : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string command = userdata.asString();
+ if ("start playback" == command)
+ {
+ LLAgentPilot::startPlayback(NULL);
+ }
+ else if ("stop playback" == command)
+ {
+ LLAgentPilot::stopPlayback(NULL);
+ }
+ else if ("start record" == command)
+ {
+ LLAgentPilot::startRecord(NULL);
+ }
+ else if ("stop record" == command)
+ {
+ LLAgentPilot::saveRecord(NULL);
+ }
+
+ return true;
+ }
+};
+
+
+
+//////////////////////
+// AGENT PILOT LOOP //
+//////////////////////
+
+
+class LLAdvancedToggleAgentPilotLoop : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLAgentPilot::sLoop = !(LLAgentPilot::sLoop);
+ return true;
+ }
+};
+
+class LLAdvancedCheckAgentPilotLoop : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLAgentPilot::sLoop;
+ return new_value;
+ }
+};
+
+
+/////////////////////////
+// SHOW OBJECT UPDATES //
+/////////////////////////
+
+
+class LLAdvancedToggleShowObjectUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gShowObjectUpdates = !(gShowObjectUpdates);
+ return true;
+ }
+};
+
+class LLAdvancedCheckShowObjectUpdates : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gShowObjectUpdates;
+ return new_value;
+ }
+};
+
+
+
+////////////////////
+// COMPRESS IMAGE //
+////////////////////
+
+
+class LLAdvancedCompressImage : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_compress_image(NULL);
+ return true;
+ }
+};
+
+
+
+/////////////////////////
+// SHOW DEBUG SETTINGS //
+/////////////////////////
+
+
+class LLAdvancedShowDebugSettings : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterReg::showInstance("settings_debug",userdata);
+ return true;
+ }
+};
+
+
+
+////////////////////////
+// VIEW ADMIN OPTIONS //
+////////////////////////
+
+class LLAdvancedEnableViewAdminOptions : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // Don't enable in god mode since the admin menu is shown anyway.
+ // Only enable if the user has set the appropriate debug setting.
+ bool new_value = !gAgent.getAgentAccess().isGodlikeWithoutAdminMenuFakery() && gSavedSettings.getBOOL("AdminMenu");
+ return new_value;
+ }
+};
+
+class LLAdvancedToggleViewAdminOptions : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_admin_override_toggle(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedCheckViewAdminOptions : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = check_admin_override(NULL) || gAgent.isGodlike();
+ return new_value;
+ }
+};
+
+/////////////////////////////////////
+// Enable Object Object Occlusion ///
+/////////////////////////////////////
+class LLAdvancedEnableObjectObjectOcclusion: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+
+ bool new_value = gGLManager.mHasOcclusionQuery; // && LLFeatureManager::getInstance()->isFeatureAvailable(userdata.asString());
+ return new_value;
+}
+};
+
+/////////////////////////////////////
+// Enable Framebuffer Objects ///
+/////////////////////////////////////
+class LLAdvancedEnableRenderFBO: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gGLManager.mHasFramebufferObject;
+ return new_value;
+ }
+};
+
+/////////////////////////////////////
+// Enable Deferred Rendering ///
+/////////////////////////////////////
+class LLAdvancedEnableRenderDeferred: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT > 0) &&
+ LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_AVATAR) > 0;
+ return new_value;
+ }
+};
+
+/////////////////////////////////////
+// Enable Deferred Rendering sub-options
+/////////////////////////////////////
+class LLAdvancedEnableRenderDeferredOptions: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gSavedSettings.getBOOL("RenderUseFBO") && gSavedSettings.getBOOL("RenderDeferred");
+ return new_value;
+ }
+};
+
+
+
+//////////////////
+// ADMIN STATUS //
+//////////////////
+
+
+class LLAdvancedRequestAdminStatus : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_god_mode(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedLeaveAdminStatus : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_leave_god_mode(NULL);
+ return true;
+ }
+};
+
+//////////////////////////
+// Advanced > Debugging //
+//////////////////////////
+
+
+class LLAdvancedForceErrorBreakpoint : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_breakpoint(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedForceErrorLlerror : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_llerror(NULL);
+ return true;
+ }
+};
+class LLAdvancedForceErrorBadMemoryAccess : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_bad_memory_access(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedForceErrorInfiniteLoop : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_infinite_loop(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedForceErrorSoftwareException : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_software_exception(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedForceErrorDriverCrash : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_error_driver_crash(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedForceErrorDisconnectViewer : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_disconnect_viewer(NULL);
+ return true;
+}
+};
+
+
+#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+
+class LLAdvancedHandleToggleHackedGodmode : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_toggle_hacked_godmode(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedCheckToggleHackedGodmode : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ check_toggle_hacked_godmode(NULL);
+ return true;
+ }
+};
+
+class LLAdvancedEnableToggleHackedGodmode : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = enable_toggle_hacked_godmode(NULL);
+ return new_value;
+ }
+};
+#endif
+
+
+//
+////-------------------------------------------------------------------
+//// Advanced menu
+////-------------------------------------------------------------------
+
+//////////////////
+// ADMIN MENU //
+//////////////////
+
+// Admin > Object
+class LLAdminForceTakeCopy : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ force_take_copy(NULL);
+ return true;
+ }
+};
+
+class LLAdminHandleObjectOwnerSelf : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_object_owner_self(NULL);
+ return true;
+ }
+};
+class LLAdminHandleObjectOwnerPermissive : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_object_owner_permissive(NULL);
+ return true;
+ }
+};
+
+class LLAdminHandleForceDelete : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_force_delete(NULL);
+ return true;
+ }
+};
+
+class LLAdminHandleObjectLock : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_object_lock(NULL);
+ return true;
+ }
+};
+
+class LLAdminHandleObjectAssetIDs: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_object_asset_ids(NULL);
+ return true;
+ }
+};
+
+//Admin >Parcel
+class LLAdminHandleForceParcelOwnerToMe: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_force_parcel_owner_to_me(NULL);
+ return true;
+ }
+};
+class LLAdminHandleForceParcelToContent: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_force_parcel_to_content(NULL);
+ return true;
+ }
+};
+class LLAdminHandleClaimPublicLand: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_claim_public_land(NULL);
+ return true;
+ }
+};
+
+// Admin > Region
+class LLAdminHandleRegionDumpTempAssetData: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_region_dump_temp_asset_data(NULL);
+ return true;
+ }
+};
+//Admin (Top Level)
+
+class LLAdminOnSaveState: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPanelRegionTools::onSaveState(NULL);
+ return true;
+}
+};
+
+
+//-----------------------------------------------------------------------------
+// cleanup_menus()
+//-----------------------------------------------------------------------------
+void cleanup_menus()
+{
+ delete gMenuParcelObserver;
+ gMenuParcelObserver = NULL;
+
+ delete gMenuAvatarSelf;
+ gMenuAvatarSelf = NULL;
+
+ delete gMenuAvatarOther;
+ gMenuAvatarOther = NULL;
+
+ delete gMenuObject;
+ gMenuObject = NULL;
+
+ delete gMenuAttachmentSelf;
+ gMenuAttachmentSelf = NULL;
+
+ delete gMenuAttachmentOther;
+ gMenuAttachmentSelf = NULL;
+
+ delete gMenuLand;
+ gMenuLand = NULL;
+
+ delete gMenuBarView;
+ gMenuBarView = NULL;
+
+ delete gPopupMenuView;
+ gPopupMenuView = NULL;
+
+ delete gMenuHolder;
+ gMenuHolder = NULL;
+}
+
+//-----------------------------------------------------------------------------
+// Object pie menu
+//-----------------------------------------------------------------------------
+
+class LLObjectReportAbuse : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (objectp)
+ {
+ LLFloaterReporter::showFromObject(objectp->getID());
+ }
+ return true;
+ }
+};
+
+// Enabled it you clicked an object
+class LLObjectEnableReportAbuse : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLSelectMgr::getInstance()->getSelection()->getObjectCount() != 0;
+ return new_value;
+ }
+};
+
+void handle_object_touch()
+{
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!object) return;
+
+ LLPickInfo pick = LLToolPie::getInstance()->getPick();
+
+ LLMessageSystem *msg = gMessageSystem;
+
+ msg->newMessageFast(_PREHASH_ObjectGrab);
+ msg->nextBlockFast( _PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast( _PREHASH_ObjectData);
+ msg->addU32Fast( _PREHASH_LocalID, object->mLocalID);
+ msg->addVector3Fast(_PREHASH_GrabOffset, LLVector3::zero );
+ msg->nextBlock("SurfaceInfo");
+ msg->addVector3("UVCoord", LLVector3(pick.mUVCoords));
+ msg->addVector3("STCoord", LLVector3(pick.mSTCoords));
+ msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace);
+ msg->addVector3("Position", pick.mIntersection);
+ msg->addVector3("Normal", pick.mNormal);
+ msg->addVector3("Binormal", pick.mBinormal);
+ msg->sendMessage( object->getRegion()->getHost());
+
+ // *NOTE: Hope the packets arrive safely and in order or else
+ // there will be some problems.
+ // *TODO: Just fix this bad assumption.
+ msg->newMessageFast(_PREHASH_ObjectDeGrab);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addU32Fast(_PREHASH_LocalID, object->mLocalID);
+ msg->nextBlock("SurfaceInfo");
+ msg->addVector3("UVCoord", LLVector3(pick.mUVCoords));
+ msg->addVector3("STCoord", LLVector3(pick.mSTCoords));
+ msg->addS32Fast(_PREHASH_FaceIndex, pick.mObjectFace);
+ msg->addVector3("Position", pick.mIntersection);
+ msg->addVector3("Normal", pick.mNormal);
+ msg->addVector3("Binormal", pick.mBinormal);
+ msg->sendMessage(object->getRegion()->getHost());
+}
+
+static void init_default_item_label(const std::string& item_name)
+{
+ boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
+ if (it == sDefaultItemLabels.end())
+ {
+ // *NOTE: This will not work for items of type LLMenuItemCheckGL because they return boolean value
+ // (doesn't seem to matter much ATM).
+ LLStringExplicit default_label = gMenuHolder->childGetValue(item_name).asString();
+ if (!default_label.empty())
+ {
+ sDefaultItemLabels.insert(std::pair<std::string, LLStringExplicit>(item_name, default_label));
+ }
+ }
+}
+
+static LLStringExplicit get_default_item_label(const std::string& item_name)
+{
+ LLStringExplicit res("");
+ boost::unordered_map<std::string, LLStringExplicit>::iterator it = sDefaultItemLabels.find(item_name);
+ if (it != sDefaultItemLabels.end())
+ {
+ res = it->second;
+ }
+
+ return res;
+}
+
+
+bool enable_object_touch(LLUICtrl* ctrl)
+{
+ LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+
+ bool new_value = obj && obj->flagHandleTouch();
+
+ std::string item_name = ctrl->getName();
+ init_default_item_label(item_name);
+
+ // Update label based on the node touch name if available.
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if (node && node->mValid && !node->mTouchName.empty())
+ {
+ gMenuHolder->childSetText(item_name, node->mTouchName);
+ }
+ else
+ {
+ gMenuHolder->childSetText(item_name, get_default_item_label(item_name));
+ }
+
+ return new_value;
+};
+
+//void label_touch(std::string& label, void*)
+//{
+// LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+// if (node && node->mValid && !node->mTouchName.empty())
+// {
+// label.assign(node->mTouchName);
+// }
+// else
+// {
+// label.assign("Touch");
+// }
+//}
+
+void handle_object_open()
+{
+ LLFloaterReg::showInstance("openobject");
+}
+
+bool enable_object_open()
+{
+ // Look for contents in root object, which is all the LLFloaterOpenObject
+ // understands.
+ LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!obj) return false;
+
+ LLViewerObject* root = obj->getRootEdit();
+ if (!root) return false;
+
+ return root->allowOpen();
+}
+
+
+class LLViewJoystickFlycam : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_toggle_flycam();
+ return true;
+ }
+};
+
+class LLViewCheckJoystickFlycam : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLViewerJoystick::getInstance()->getOverrideCamera();
+ return new_value;
+ }
+};
+
+void handle_toggle_flycam()
+{
+ LLViewerJoystick::getInstance()->toggleFlycam();
+}
+
+class LLObjectBuild : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ // zoom in if we're looking at the avatar
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+ gAgentCamera.cameraZoomIn(0.666f);
+ gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD );
+ gViewerWindow->moveCursorToCenter();
+ }
+ else if ( gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+ gViewerWindow->moveCursorToCenter();
+ }
+
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+ LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() );
+
+ // Could be first use
+ //LLFirstUse::useBuild();
+ return true;
+ }
+};
+
+
+void handle_object_edit()
+{
+ LLViewerParcelMgr::getInstance()->deselectLand();
+
+ if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit())
+ {
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+
+ if (selection->getSelectType() == SELECT_TYPE_HUD || !gSavedSettings.getBOOL("EditCameraMovement"))
+ {
+ // always freeze camera in space, even if camera doesn't move
+ // so, for example, follow cam scripts can't affect you when in build mode
+ gAgentCamera.setFocusGlobal(gAgentCamera.calcFocusPositionTargetGlobal(), LLUUID::null);
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+ }
+ else
+ {
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+ LLViewerObject* selected_objectp = selection->getFirstRootObject();
+ if (selected_objectp)
+ {
+ // zoom in on object center instead of where we clicked, as we need to see the manipulator handles
+ gAgentCamera.setFocusGlobal(selected_objectp->getPositionGlobal(), selected_objectp->getID());
+ gAgentCamera.cameraZoomIn(0.666f);
+ gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD );
+ gViewerWindow->moveCursorToCenter();
+ }
+ }
+ }
+
+ LLFloaterReg::showInstance("build");
+
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+ gFloaterTools->setEditTool( LLToolCompTranslate::getInstance() );
+
+ LLViewerJoystick::getInstance()->moveObjects(true);
+ LLViewerJoystick::getInstance()->setNeedsReset(true);
+
+ // Could be first use
+ //LLFirstUse::useBuild();
+ return;
+}
+
+void handle_object_inspect()
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ LLViewerObject* selected_objectp = selection->getFirstRootObject();
+ if (selected_objectp)
+ {
+ LLSD key;
+ key["task"] = "task";
+ LLSideTray::getInstance()->showPanel("sidepanel_inventory", key);
+ }
+
+ /*
+ // Old floater properties
+ LLFloaterReg::showInstance("inspect", LLSD());
+ */
+}
+
+//---------------------------------------------------------------------------
+// Land pie menu
+//---------------------------------------------------------------------------
+class LLLandBuild : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerParcelMgr::getInstance()->deselectLand();
+
+ if (gAgentCamera.getFocusOnAvatar() && !LLToolMgr::getInstance()->inEdit() && gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ // zoom in if we're looking at the avatar
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+ gAgentCamera.cameraZoomIn(0.666f);
+ gAgentCamera.cameraOrbitOver( 30.f * DEG_TO_RAD );
+ gViewerWindow->moveCursorToCenter();
+ }
+ else if ( gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ // otherwise just move focus
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+ gViewerWindow->moveCursorToCenter();
+ }
+
+
+ LLToolMgr::getInstance()->setCurrentToolset(gBasicToolset);
+ LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolCompCreate::getInstance() );
+
+ // Could be first use
+ //LLFirstUse::useBuild();
+ return true;
+ }
+};
+
+class LLLandBuyPass : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPanelLandGeneral::onClickBuyPass((void *)FALSE);
+ return true;
+ }
+};
+
+class LLLandEnableBuyPass : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLPanelLandGeneral::enableBuyPass(NULL);
+ return new_value;
+ }
+};
+
+// BUG: Should really check if CLICK POINT is in a parcel where you can build.
+BOOL enable_land_build(void*)
+{
+ if (gAgent.isGodlike()) return TRUE;
+ if (gAgent.inPrelude()) return FALSE;
+
+ BOOL can_build = FALSE;
+ LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (agent_parcel)
+ {
+ can_build = agent_parcel->getAllowModify();
+ }
+ return can_build;
+}
+
+// BUG: Should really check if OBJECT is in a parcel where you can build.
+BOOL enable_object_build(void*)
+{
+ if (gAgent.isGodlike()) return TRUE;
+ if (gAgent.inPrelude()) return FALSE;
+
+ BOOL can_build = FALSE;
+ LLParcel* agent_parcel = LLViewerParcelMgr::getInstance()->getAgentParcel();
+ if (agent_parcel)
+ {
+ can_build = agent_parcel->getAllowModify();
+ }
+ return can_build;
+}
+
+bool enable_object_edit()
+{
+ // *HACK: The new "prelude" Help Islands have a build sandbox area,
+ // so users need the Edit and Create pie menu options when they are
+ // there. Eventually this needs to be replaced with code that only
+ // lets you edit objects if you have permission to do so (edit perms,
+ // group edit, god). See also lltoolbar.cpp. JC
+ bool enable = false;
+ if (gAgent.inPrelude())
+ {
+ enable = LLViewerParcelMgr::getInstance()->allowAgentBuild()
+ || LLSelectMgr::getInstance()->getSelection()->isAttachment();
+ }
+ else if (LLSelectMgr::getInstance()->selectGetAllValidAndObjectsFound())
+ {
+ enable = true;
+ }
+
+ return enable;
+}
+
+// mutually exclusive - show either edit option or build in menu
+bool enable_object_build()
+{
+ return !enable_object_edit();
+}
+
+class LLSelfRemoveAllAttachments : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLAgentWearables::userRemoveAllAttachments();
+ return true;
+ }
+};
+
+class LLSelfEnableRemoveAllAttachments : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = false;
+ if (isAgentAvatarValid())
+ {
+ for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end(); )
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ if (attachment->getNumObjects() > 0)
+ {
+ new_value = true;
+ break;
+ }
+ }
+ }
+ return new_value;
+ }
+};
+
+BOOL enable_has_attachments(void*)
+{
+
+ return FALSE;
+}
+
+//---------------------------------------------------------------------------
+// Avatar pie menu
+//---------------------------------------------------------------------------
+//void handle_follow(void *userdata)
+//{
+// // follow a given avatar by ID
+// LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+// if (objectp)
+// {
+// gAgent.startFollowPilot(objectp->getID());
+// }
+//}
+
+bool enable_object_mute()
+{
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!object) return false;
+
+ LLVOAvatar* avatar = find_avatar_from_object(object);
+ if (avatar)
+ {
+ // It's an avatar
+ LLNameValue *lastname = avatar->getNVPair("LastName");
+ bool is_linden =
+ lastname && !LLStringUtil::compareStrings(lastname->getString(), "Linden");
+ bool is_self = avatar->isSelf();
+ return !is_linden && !is_self;
+ }
+ else
+ {
+ // Just a regular object
+ return LLSelectMgr::getInstance()->getSelection()->
+ contains( object, SELECT_ALL_TES );
+ }
+}
+
+class LLObjectMute : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!object) return true;
+
+ LLUUID id;
+ std::string name;
+ LLMute::EType type;
+ LLVOAvatar* avatar = find_avatar_from_object(object);
+ if (avatar)
+ {
+ id = avatar->getID();
+
+ LLNameValue *firstname = avatar->getNVPair("FirstName");
+ LLNameValue *lastname = avatar->getNVPair("LastName");
+ if (firstname && lastname)
+ {
+ name = LLCacheName::buildFullName(
+ firstname->getString(), lastname->getString());
+ }
+
+ type = LLMute::AGENT;
+ }
+ else
+ {
+ // it's an object
+ id = object->getID();
+
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if (node)
+ {
+ name = node->mName;
+ }
+
+ type = LLMute::OBJECT;
+ }
+
+ LLMute mute(id, name, type);
+ if (LLMuteList::getInstance()->isMuted(mute.mID))
+ {
+ LLMuteList::getInstance()->remove(mute);
+ }
+ else
+ {
+ LLMuteList::getInstance()->add(mute);
+ LLPanelBlockedList::showPanelAndSelect(mute.mID);
+ }
+
+ return true;
+ }
+};
+
+bool handle_go_to()
+{
+ // try simulator autopilot
+ std::vector<std::string> strings;
+ std::string val;
+ LLVector3d pos = LLToolPie::getInstance()->getPick().mPosGlobal;
+ val = llformat("%g", pos.mdV[VX]);
+ strings.push_back(val);
+ val = llformat("%g", pos.mdV[VY]);
+ strings.push_back(val);
+ val = llformat("%g", pos.mdV[VZ]);
+ strings.push_back(val);
+ send_generic_message("autopilot", strings);
+
+ LLViewerParcelMgr::getInstance()->deselectLand();
+
+ if (isAgentAvatarValid() && !gSavedSettings.getBOOL("AutoPilotLocksCamera"))
+ {
+ gAgentCamera.setFocusGlobal(gAgentCamera.getFocusTargetGlobal(), gAgentAvatarp->getID());
+ }
+ else
+ {
+ // Snap camera back to behind avatar
+ gAgentCamera.setFocusOnAvatar(TRUE, ANIMATE);
+ }
+
+ // Could be first use
+ //LLFirstUse::useGoTo();
+ return true;
+}
+
+class LLGoToObject : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return handle_go_to();
+ }
+};
+
+class LLAvatarReportAbuse : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLFloaterReporter::showFromObject(avatar->getID());
+ }
+ return true;
+ }
+};
+
+
+//---------------------------------------------------------------------------
+// Parcel freeze, eject, etc.
+//---------------------------------------------------------------------------
+bool callback_freeze(const LLSD& notification, const LLSD& response)
+{
+ LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID();
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+
+ if (0 == option || 1 == option)
+ {
+ U32 flags = 0x0;
+ if (1 == option)
+ {
+ // unfreeze
+ flags |= 0x1;
+ }
+
+ LLMessageSystem* msg = gMessageSystem;
+ LLViewerObject* avatar = gObjectList.findObject(avatar_id);
+
+ if (avatar)
+ {
+ msg->newMessage("FreezeUser");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID());
+ msg->addUUID("SessionID", gAgent.getSessionID());
+ msg->nextBlock("Data");
+ msg->addUUID("TargetID", avatar_id );
+ msg->addU32("Flags", flags );
+ msg->sendReliable( avatar->getRegion()->getHost() );
+ }
+ }
+ return false;
+}
+
+
+void handle_avatar_freeze(const LLSD& avatar_id)
+{
+ // Use avatar_id if available, otherwise default to right-click avatar
+ LLVOAvatar* avatar = NULL;
+ if (avatar_id.asUUID().notNull())
+ {
+ avatar = find_avatar_from_object(avatar_id.asUUID());
+ }
+ else
+ {
+ avatar = find_avatar_from_object(
+ LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+ }
+
+ if( avatar )
+ {
+ std::string fullname = avatar->getFullname();
+ LLSD payload;
+ payload["avatar_id"] = avatar->getID();
+
+ if (!fullname.empty())
+ {
+ LLSD args;
+ args["AVATAR_NAME"] = fullname;
+ LLNotificationsUtil::add("FreezeAvatarFullname",
+ args,
+ payload,
+ callback_freeze);
+ }
+ else
+ {
+ LLNotificationsUtil::add("FreezeAvatar",
+ LLSD(),
+ payload,
+ callback_freeze);
+ }
+ }
+}
+
+class LLAvatarVisibleDebug : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gAgent.isGodlike();
+ }
+};
+
+class LLAvatarDebug : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if( avatar )
+ {
+ if (avatar->isSelf())
+ {
+ ((LLVOAvatarSelf *)avatar)->dumpLocalTextures();
+ }
+ llinfos << "Dumping temporary asset data to simulator logs for avatar " << avatar->getID() << llendl;
+ std::vector<std::string> strings;
+ strings.push_back(avatar->getID().asString());
+ LLUUID invoice;
+ send_generic_message("dumptempassetdata", strings, invoice);
+ LLFloaterReg::showInstance( "avatar_textures", LLSD(avatar->getID()) );
+ }
+ return true;
+ }
+};
+
+bool callback_eject(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (2 == option)
+ {
+ // Cancel button.
+ return false;
+ }
+ LLUUID avatar_id = notification["payload"]["avatar_id"].asUUID();
+ bool ban_enabled = notification["payload"]["ban_enabled"].asBoolean();
+
+ if (0 == option)
+ {
+ // Eject button
+ LLMessageSystem* msg = gMessageSystem;
+ LLViewerObject* avatar = gObjectList.findObject(avatar_id);
+
+ if (avatar)
+ {
+ U32 flags = 0x0;
+ msg->newMessage("EjectUser");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID() );
+ msg->addUUID("SessionID", gAgent.getSessionID() );
+ msg->nextBlock("Data");
+ msg->addUUID("TargetID", avatar_id );
+ msg->addU32("Flags", flags );
+ msg->sendReliable( avatar->getRegion()->getHost() );
+ }
+ }
+ else if (ban_enabled)
+ {
+ // This is tricky. It is similar to say if it is not an 'Eject' button,
+ // and it is also not an 'Cancle' button, and ban_enabled==ture,
+ // it should be the 'Eject and Ban' button.
+ LLMessageSystem* msg = gMessageSystem;
+ LLViewerObject* avatar = gObjectList.findObject(avatar_id);
+
+ if (avatar)
+ {
+ U32 flags = 0x1;
+ msg->newMessage("EjectUser");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID() );
+ msg->addUUID("SessionID", gAgent.getSessionID() );
+ msg->nextBlock("Data");
+ msg->addUUID("TargetID", avatar_id );
+ msg->addU32("Flags", flags );
+ msg->sendReliable( avatar->getRegion()->getHost() );
+ }
+ }
+ return false;
+}
+
+void handle_avatar_eject(const LLSD& avatar_id)
+{
+ // Use avatar_id if available, otherwise default to right-click avatar
+ LLVOAvatar* avatar = NULL;
+ if (avatar_id.asUUID().notNull())
+ {
+ avatar = find_avatar_from_object(avatar_id.asUUID());
+ }
+ else
+ {
+ avatar = find_avatar_from_object(
+ LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+ }
+
+ if( avatar )
+ {
+ LLSD payload;
+ payload["avatar_id"] = avatar->getID();
+ std::string fullname = avatar->getFullname();
+
+ const LLVector3d& pos = avatar->getPositionGlobal();
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos)->getParcel();
+
+ if (LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_MANAGE_BANNED))
+ {
+ payload["ban_enabled"] = true;
+ if (!fullname.empty())
+ {
+ LLSD args;
+ args["AVATAR_NAME"] = fullname;
+ LLNotificationsUtil::add("EjectAvatarFullname",
+ args,
+ payload,
+ callback_eject);
+ }
+ else
+ {
+ LLNotificationsUtil::add("EjectAvatarFullname",
+ LLSD(),
+ payload,
+ callback_eject);
+ }
+ }
+ else
+ {
+ payload["ban_enabled"] = false;
+ if (!fullname.empty())
+ {
+ LLSD args;
+ args["AVATAR_NAME"] = fullname;
+ LLNotificationsUtil::add("EjectAvatarFullnameNoBan",
+ args,
+ payload,
+ callback_eject);
+ }
+ else
+ {
+ LLNotificationsUtil::add("EjectAvatarNoBan",
+ LLSD(),
+ payload,
+ callback_eject);
+ }
+ }
+ }
+}
+
+bool enable_freeze_eject(const LLSD& avatar_id)
+{
+ // Use avatar_id if available, otherwise default to right-click avatar
+ LLVOAvatar* avatar = NULL;
+ if (avatar_id.asUUID().notNull())
+ {
+ avatar = find_avatar_from_object(avatar_id.asUUID());
+ }
+ else
+ {
+ avatar = find_avatar_from_object(
+ LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+ }
+ if (!avatar) return false;
+
+ // Gods can always freeze
+ if (gAgent.isGodlike()) return true;
+
+ // Estate owners / managers can freeze
+ // Parcel owners can also freeze
+ const LLVector3& pos = avatar->getPositionRegion();
+ const LLVector3d& pos_global = avatar->getPositionGlobal();
+ LLParcel* parcel = LLViewerParcelMgr::getInstance()->selectParcelAt(pos_global)->getParcel();
+ LLViewerRegion* region = avatar->getRegion();
+ if (!region) return false;
+
+ bool new_value = region->isOwnedSelf(pos);
+ if (!new_value || region->isOwnedGroup(pos))
+ {
+ new_value = LLViewerParcelMgr::getInstance()->isParcelOwnedByAgent(parcel,GP_LAND_ADMIN);
+ }
+ return new_value;
+}
+
+
+void login_done(S32 which, void *user)
+{
+ llinfos << "Login done " << which << llendl;
+
+ LLPanelLogin::closePanel();
+}
+
+
+bool callback_leave_group(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0)
+ {
+ LLMessageSystem *msg = gMessageSystem;
+
+ msg->newMessageFast(_PREHASH_LeaveGroupRequest);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_GroupData);
+ msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID() );
+ gAgent.sendReliableMessage();
+ }
+ return false;
+}
+
+void append_aggregate(std::string& string, const LLAggregatePermissions& ag_perm, PermissionBit bit, const char* txt)
+{
+ LLAggregatePermissions::EValue val = ag_perm.getValue(bit);
+ std::string buffer;
+ switch(val)
+ {
+ case LLAggregatePermissions::AP_NONE:
+ buffer = llformat( "* %s None\n", txt);
+ break;
+ case LLAggregatePermissions::AP_SOME:
+ buffer = llformat( "* %s Some\n", txt);
+ break;
+ case LLAggregatePermissions::AP_ALL:
+ buffer = llformat( "* %s All\n", txt);
+ break;
+ case LLAggregatePermissions::AP_EMPTY:
+ default:
+ break;
+ }
+ string.append(buffer);
+}
+
+bool enable_buy_object()
+{
+ // In order to buy, there must only be 1 purchaseable object in
+ // the selection manger.
+ if(LLSelectMgr::getInstance()->getSelection()->getRootObjectCount() != 1) return false;
+ LLViewerObject* obj = NULL;
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if(node)
+ {
+ obj = node->getObject();
+ if(!obj) return false;
+
+ if( for_sale_selection(node) )
+ {
+ // *NOTE: Is this needed? This checks to see if anyone owns the
+ // object, dating back to when we had "public" objects owned by
+ // no one. JC
+ if(obj->permAnyOwner()) return true;
+ }
+ }
+ return false;
+}
+
+// Note: This will only work if the selected object's data has been
+// received by the viewer and cached in the selection manager.
+void handle_buy_object(LLSaleInfo sale_info)
+{
+ if(!LLSelectMgr::getInstance()->selectGetAllRootsValid())
+ {
+ LLNotificationsUtil::add("UnableToBuyWhileDownloading");
+ return;
+ }
+
+ LLUUID owner_id;
+ std::string owner_name;
+ BOOL owners_identical = LLSelectMgr::getInstance()->selectGetOwner(owner_id, owner_name);
+ if (!owners_identical)
+ {
+ LLNotificationsUtil::add("CannotBuyObjectsFromDifferentOwners");
+ return;
+ }
+
+ LLPermissions perm;
+ BOOL valid = LLSelectMgr::getInstance()->selectGetPermissions(perm);
+ LLAggregatePermissions ag_perm;
+ valid &= LLSelectMgr::getInstance()->selectGetAggregatePermissions(ag_perm);
+ if(!valid || !sale_info.isForSale() || !perm.allowTransferTo(gAgent.getID()))
+ {
+ LLNotificationsUtil::add("ObjectNotForSale");
+ return;
+ }
+
+ LLFloaterBuy::show(sale_info);
+}
+
+
+void handle_buy_contents(LLSaleInfo sale_info)
+{
+ LLFloaterBuyContents::show(sale_info);
+}
+
+void handle_region_dump_temp_asset_data(void*)
+{
+ llinfos << "Dumping temporary asset data to simulator logs" << llendl;
+ std::vector<std::string> strings;
+ LLUUID invoice;
+ send_generic_message("dumptempassetdata", strings, invoice);
+}
+
+void handle_region_clear_temp_asset_data(void*)
+{
+ llinfos << "Clearing temporary asset data" << llendl;
+ std::vector<std::string> strings;
+ LLUUID invoice;
+ send_generic_message("cleartempassetdata", strings, invoice);
+}
+
+void handle_region_dump_settings(void*)
+{
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if (regionp)
+ {
+ llinfos << "Damage: " << (regionp->getAllowDamage() ? "on" : "off") << llendl;
+ llinfos << "Landmark: " << (regionp->getAllowLandmark() ? "on" : "off") << llendl;
+ llinfos << "SetHome: " << (regionp->getAllowSetHome() ? "on" : "off") << llendl;
+ llinfos << "ResetHome: " << (regionp->getResetHomeOnTeleport() ? "on" : "off") << llendl;
+ llinfos << "SunFixed: " << (regionp->getSunFixed() ? "on" : "off") << llendl;
+ llinfos << "BlockFly: " << (regionp->getBlockFly() ? "on" : "off") << llendl;
+ llinfos << "AllowP2P: " << (regionp->getAllowDirectTeleport() ? "on" : "off") << llendl;
+ llinfos << "Water: " << (regionp->getWaterHeight()) << llendl;
+ }
+}
+
+void handle_dump_group_info(void *)
+{
+ gAgent.dumpGroupInfo();
+}
+
+void handle_dump_capabilities_info(void *)
+{
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if (regionp)
+ {
+ regionp->logActiveCapabilities();
+ }
+}
+
+void handle_dump_region_object_cache(void*)
+{
+ LLViewerRegion* regionp = gAgent.getRegion();
+ if (regionp)
+ {
+ regionp->dumpCache();
+ }
+}
+
+void handle_dump_focus()
+{
+ LLUICtrl *ctrl = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+
+ llinfos << "Keyboard focus " << (ctrl ? ctrl->getName() : "(none)") << llendl;
+}
+
+class LLSelfStandUp : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.standUp();
+ return true;
+ }
+};
+
+bool enable_standup_self()
+{
+ return isAgentAvatarValid() && gAgentAvatarp->isSitting();
+}
+
+class LLSelfSitDown : public view_listener_t
+ {
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.sitDown();
+ return true;
+ }
+ };
+
+bool enable_sitdown_self()
+{
+ return isAgentAvatarValid() && !gAgentAvatarp->isSitting() && !gAgent.getFlying();
+}
+
+// Used from the login screen to aid in UI work on side tray
+void handle_show_side_tray()
+{
+ LLSideTray* side_tray = LLSideTray::getInstance();
+ LLView* root = gViewerWindow->getRootView();
+ // automatically removes and re-adds if there already
+ root->addChild(side_tray);
+}
+
+// Toggle one of "People" panel tabs in side tray.
+class LLTogglePanelPeopleTab : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string panel_name = userdata.asString();
+
+ LLSD param;
+ param["people_panel_tab_name"] = panel_name;
+
+ static LLPanel* friends_panel = NULL;
+ static LLPanel* groups_panel = NULL;
+ static LLPanel* nearby_panel = NULL;
+
+ if (panel_name == "friends_panel")
+ {
+ return togglePeoplePanel(friends_panel, panel_name, param);
+ }
+ else if (panel_name == "groups_panel")
+ {
+ return togglePeoplePanel(groups_panel, panel_name, param);
+ }
+ else if (panel_name == "nearby_panel")
+ {
+ return togglePeoplePanel(nearby_panel, panel_name, param);
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ static bool togglePeoplePanel(LLPanel* &panel, const std::string& panel_name, const LLSD& param)
+ {
+ if(!panel)
+ {
+ panel = LLSideTray::getInstance()->getPanel(panel_name);
+ if(!panel)
+ return false;
+ }
+
+ LLSideTray::getInstance()->togglePanel(panel, "panel_people", param);
+
+ return true;
+ }
+};
+
+BOOL check_admin_override(void*)
+{
+ return gAgent.getAdminOverride();
+}
+
+void handle_admin_override_toggle(void*)
+{
+ gAgent.setAdminOverride(!gAgent.getAdminOverride());
+
+ // The above may have affected which debug menus are visible
+ show_debug_menus();
+}
+
+void handle_god_mode(void*)
+{
+ gAgent.requestEnterGodMode();
+}
+
+void handle_leave_god_mode(void*)
+{
+ gAgent.requestLeaveGodMode();
+}
+
+void set_god_level(U8 god_level)
+{
+ U8 old_god_level = gAgent.getGodLevel();
+ gAgent.setGodLevel( god_level );
+ LLViewerParcelMgr::getInstance()->notifyObservers();
+
+ // God mode changes region visibility
+ LLWorldMap::getInstance()->reloadItems(true);
+
+ // inventory in items may change in god mode
+ gObjectList.dirtyAllObjectInventory();
+
+ if(gViewerWindow)
+ {
+ gViewerWindow->setMenuBackgroundColor(god_level > GOD_NOT,
+ LLGridManager::getInstance()->isInProductionGrid());
+ }
+
+ LLSD args;
+ if(god_level > GOD_NOT)
+ {
+ args["LEVEL"] = llformat("%d",(S32)god_level);
+ LLNotificationsUtil::add("EnteringGodMode", args);
+ }
+ else
+ {
+ args["LEVEL"] = llformat("%d",(S32)old_god_level);
+ LLNotificationsUtil::add("LeavingGodMode", args);
+ }
+
+ // changing god-level can affect which menus we see
+ show_debug_menus();
+
+ // changing god-level can invalidate search results
+ LLFloaterSearch *search = dynamic_cast<LLFloaterSearch*>(LLFloaterReg::getInstance("search"));
+ if (search)
+ {
+ search->godLevelChanged(god_level);
+ }
+}
+
+#ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+void handle_toggle_hacked_godmode(void*)
+{
+ gHackGodmode = !gHackGodmode;
+ set_god_level(gHackGodmode ? GOD_MAINTENANCE : GOD_NOT);
+}
+
+BOOL check_toggle_hacked_godmode(void*)
+{
+ return gHackGodmode;
+}
+
+bool enable_toggle_hacked_godmode(void*)
+{
+ return !LLGridManager::getInstance()->isInProductionGrid();
+}
+#endif
+
+void process_grant_godlike_powers(LLMessageSystem* msg, void**)
+{
+ LLUUID agent_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_AgentID, agent_id);
+ LLUUID session_id;
+ msg->getUUIDFast(_PREHASH_AgentData, _PREHASH_SessionID, session_id);
+ if((agent_id == gAgent.getID()) && (session_id == gAgent.getSessionID()))
+ {
+ U8 god_level;
+ msg->getU8Fast(_PREHASH_GrantData, _PREHASH_GodLevel, god_level);
+ set_god_level(god_level);
+ }
+ else
+ {
+ llwarns << "Grant godlike for wrong agent " << agent_id << llendl;
+ }
+}
+
+/*
+class LLHaveCallingcard : public LLInventoryCollectFunctor
+{
+public:
+ LLHaveCallingcard(const LLUUID& agent_id);
+ virtual ~LLHaveCallingcard() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+ BOOL isThere() const { return mIsThere;}
+protected:
+ LLUUID mID;
+ BOOL mIsThere;
+};
+
+LLHaveCallingcard::LLHaveCallingcard(const LLUUID& agent_id) :
+ mID(agent_id),
+ mIsThere(FALSE)
+{
+}
+
+bool LLHaveCallingcard::operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item)
+{
+ if(item)
+ {
+ if((item->getType() == LLAssetType::AT_CALLINGCARD)
+ && (item->getCreatorUUID() == mID))
+ {
+ mIsThere = TRUE;
+ }
+ }
+ return FALSE;
+}
+*/
+
+BOOL is_agent_mappable(const LLUUID& agent_id)
+{
+ const LLRelationship* buddy_info = NULL;
+ bool is_friend = LLAvatarActions::isFriend(agent_id);
+
+ if (is_friend)
+ buddy_info = LLAvatarTracker::instance().getBuddyInfo(agent_id);
+
+ return (buddy_info &&
+ buddy_info->isOnline() &&
+ buddy_info->isRightGrantedFrom(LLRelationship::GRANT_MAP_LOCATION)
+ );
+}
+
+
+// Enable a menu item when you don't have someone's card.
+class LLAvatarEnableAddFriend : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object(LLSelectMgr::getInstance()->getSelection()->getPrimaryObject());
+ bool new_value = avatar && !LLAvatarActions::isFriend(avatar->getID());
+ return new_value;
+ }
+};
+
+void request_friendship(const LLUUID& dest_id)
+{
+ LLViewerObject* dest = gObjectList.findObject(dest_id);
+ if(dest && dest->isAvatar())
+ {
+ std::string full_name;
+ LLNameValue* nvfirst = dest->getNVPair("FirstName");
+ LLNameValue* nvlast = dest->getNVPair("LastName");
+ if(nvfirst && nvlast)
+ {
+ full_name = LLCacheName::buildFullName(
+ nvfirst->getString(), nvlast->getString());
+ }
+ if (!full_name.empty())
+ {
+ LLAvatarActions::requestFriendshipDialog(dest_id, full_name);
+ }
+ else
+ {
+ LLNotificationsUtil::add("CantOfferFriendship");
+ }
+ }
+}
+
+
+class LLEditEnableCustomizeAvatar : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gAgentWearables.areWearablesLoaded();
+ return new_value;
+ }
+};
+
+class LLEnableEditShape : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gAgentWearables.isWearableModifiable(LLWearableType::WT_SHAPE, 0);
+ }
+};
+
+bool is_object_sittable()
+{
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+
+ if (object && object->getPCode() == LL_PCODE_VOLUME)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+
+// only works on pie menu
+void handle_object_sit_or_stand()
+{
+ LLPickInfo pick = LLToolPie::getInstance()->getPick();
+ LLViewerObject *object = pick.getObject();;
+ if (!object || pick.mPickType == LLPickInfo::PICK_FLORA)
+ {
+ return;
+ }
+
+ if (sitting_on_selection())
+ {
+ gAgent.standUp();
+ return;
+ }
+
+ // get object selection offset
+
+ if (object && object->getPCode() == LL_PCODE_VOLUME)
+ {
+
+ gMessageSystem->newMessageFast(_PREHASH_AgentRequestSit);
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ gMessageSystem->nextBlockFast(_PREHASH_TargetObject);
+ gMessageSystem->addUUIDFast(_PREHASH_TargetID, object->mID);
+ gMessageSystem->addVector3Fast(_PREHASH_Offset, pick.mObjectOffset);
+
+ object->getRegion()->sendReliableMessage();
+ }
+}
+
+void near_sit_down_point(BOOL success, void *)
+{
+ if (success)
+ {
+ gAgent.setFlying(FALSE);
+ gAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND);
+
+ // Might be first sit
+ //LLFirstUse::useSit();
+ }
+}
+
+class LLLandSit : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.standUp();
+ LLViewerParcelMgr::getInstance()->deselectLand();
+
+ LLVector3d posGlobal = LLToolPie::getInstance()->getPick().mPosGlobal;
+
+ LLQuaternion target_rot;
+ if (isAgentAvatarValid())
+ {
+ target_rot = gAgentAvatarp->getRotation();
+ }
+ else
+ {
+ target_rot = gAgent.getFrameAgent().getQuaternion();
+ }
+ gAgent.startAutoPilotGlobal(posGlobal, "Sit", &target_rot, near_sit_down_point, NULL, 0.7f);
+ return true;
+ }
+};
+
+//-------------------------------------------------------------------
+// Help menu functions
+//-------------------------------------------------------------------
+
+//
+// Major mode switching
+//
+void reset_view_final( BOOL proceed );
+
+void handle_reset_view()
+{
+ if (gAgentCamera.cameraCustomizeAvatar())
+ {
+ // switching to outfit selector should automagically save any currently edited wearable
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "my_outfits"));
+ }
+
+ gAgentCamera.switchCameraPreset(CAMERA_PRESET_REAR_VIEW);
+ reset_view_final( TRUE );
+ LLFloaterCamera::resetCameraMode();
+}
+
+class LLViewResetView : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ handle_reset_view();
+ return true;
+ }
+};
+
+// Note: extra parameters allow this function to be called from dialog.
+void reset_view_final( BOOL proceed )
+{
+ if( !proceed )
+ {
+ return;
+ }
+
+ gAgentCamera.resetView(TRUE, TRUE);
+ gAgentCamera.setLookAt(LOOKAT_TARGET_CLEAR);
+}
+
+class LLViewLookAtLastChatter : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgentCamera.lookAtLastChat();
+ return true;
+ }
+};
+
+class LLViewMouselook : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (!gAgentCamera.cameraMouselook())
+ {
+ gAgentCamera.changeCameraToMouselook();
+ }
+ else
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+ return true;
+ }
+};
+
+class LLViewDefaultUISize : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gSavedSettings.setF32("UIScaleFactor", 1.0f);
+ gSavedSettings.setBOOL("UIAutoScale", FALSE);
+ gViewerWindow->reshape(gViewerWindow->getWindowWidthRaw(), gViewerWindow->getWindowHeightRaw());
+ return true;
+ }
+};
+
+class LLEditDuplicate : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if(LLEditMenuHandler::gEditMenuHandler)
+ {
+ LLEditMenuHandler::gEditMenuHandler->duplicate();
+ }
+ return true;
+ }
+};
+
+class LLEditEnableDuplicate : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDuplicate();
+ return new_value;
+ }
+};
+
+void handle_duplicate_in_place(void*)
+{
+ llinfos << "handle_duplicate_in_place" << llendl;
+
+ LLVector3 offset(0.f, 0.f, 0.f);
+ LLSelectMgr::getInstance()->selectDuplicate(offset, TRUE);
+}
+
+/* dead code 30-apr-2008
+void handle_deed_object_to_group(void*)
+{
+ LLUUID group_id;
+
+ LLSelectMgr::getInstance()->selectGetGroup(group_id);
+ LLSelectMgr::getInstance()->sendOwner(LLUUID::null, group_id, FALSE);
+ LLViewerStats::getInstance()->incStat(LLViewerStats::ST_RELEASE_COUNT);
+}
+
+BOOL enable_deed_object_to_group(void*)
+{
+ if(LLSelectMgr::getInstance()->getSelection()->isEmpty()) return FALSE;
+ LLPermissions perm;
+ LLUUID group_id;
+
+ if (LLSelectMgr::getInstance()->selectGetGroup(group_id) &&
+ gAgent.hasPowerInGroup(group_id, GP_OBJECT_DEED) &&
+ LLSelectMgr::getInstance()->selectGetPermissions(perm) &&
+ perm.deedToGroup(gAgent.getID(), group_id))
+ {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+*/
+
+
+/*
+ * No longer able to support viewer side manipulations in this way
+ *
+void god_force_inv_owner_permissive(LLViewerObject* object,
+ LLInventoryObject::object_list_t* inventory,
+ S32 serial_num,
+ void*)
+{
+ typedef std::vector<LLPointer<LLViewerInventoryItem> > item_array_t;
+ item_array_t items;
+
+ LLInventoryObject::object_list_t::const_iterator inv_it = inventory->begin();
+ LLInventoryObject::object_list_t::const_iterator inv_end = inventory->end();
+ for ( ; inv_it != inv_end; ++inv_it)
+ {
+ if(((*inv_it)->getType() != LLAssetType::AT_CATEGORY))
+ {
+ LLInventoryObject* obj = *inv_it;
+ LLPointer<LLViewerInventoryItem> new_item = new LLViewerInventoryItem((LLViewerInventoryItem*)obj);
+ LLPermissions perm(new_item->getPermissions());
+ perm.setMaskBase(PERM_ALL);
+ perm.setMaskOwner(PERM_ALL);
+ new_item->setPermissions(perm);
+ items.push_back(new_item);
+ }
+ }
+ item_array_t::iterator end = items.end();
+ item_array_t::iterator it;
+ for(it = items.begin(); it != end; ++it)
+ {
+ // since we have the inventory item in the callback, it should not
+ // invalidate iteration through the selection manager.
+ object->updateInventory((*it), TASK_INVENTORY_ITEM_KEY, false);
+ }
+}
+*/
+
+void handle_object_owner_permissive(void*)
+{
+ // only send this if they're a god.
+ if(gAgent.isGodlike())
+ {
+ // do the objects.
+ LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_BASE, TRUE, PERM_ALL, TRUE);
+ LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, TRUE, PERM_ALL, TRUE);
+ }
+}
+
+void handle_object_owner_self(void*)
+{
+ // only send this if they're a god.
+ if(gAgent.isGodlike())
+ {
+ LLSelectMgr::getInstance()->sendOwner(gAgent.getID(), gAgent.getGroupID(), TRUE);
+ }
+}
+
+// Shortcut to set owner permissions to not editable.
+void handle_object_lock(void*)
+{
+ LLSelectMgr::getInstance()->selectionSetObjectPermissions(PERM_OWNER, FALSE, PERM_MODIFY);
+}
+
+void handle_object_asset_ids(void*)
+{
+ // only send this if they're a god.
+ if (gAgent.isGodlike())
+ {
+ LLSelectMgr::getInstance()->sendGodlikeRequest("objectinfo", "assetids");
+ }
+}
+
+void handle_force_parcel_owner_to_me(void*)
+{
+ LLViewerParcelMgr::getInstance()->sendParcelGodForceOwner( gAgent.getID() );
+}
+
+void handle_force_parcel_to_content(void*)
+{
+ LLViewerParcelMgr::getInstance()->sendParcelGodForceToContent();
+}
+
+void handle_claim_public_land(void*)
+{
+ if (LLViewerParcelMgr::getInstance()->getSelectionRegion() != gAgent.getRegion())
+ {
+ LLNotificationsUtil::add("ClaimPublicLand");
+ return;
+ }
+
+ LLVector3d west_south_global;
+ LLVector3d east_north_global;
+ LLViewerParcelMgr::getInstance()->getSelection(west_south_global, east_north_global);
+ LLVector3 west_south = gAgent.getPosAgentFromGlobal(west_south_global);
+ LLVector3 east_north = gAgent.getPosAgentFromGlobal(east_north_global);
+
+ LLMessageSystem* msg = gMessageSystem;
+ msg->newMessage("GodlikeMessage");
+ msg->nextBlock("AgentData");
+ msg->addUUID("AgentID", gAgent.getID());
+ msg->addUUID("SessionID", gAgent.getSessionID());
+ msg->addUUIDFast(_PREHASH_TransactionID, LLUUID::null); //not used
+ msg->nextBlock("MethodData");
+ msg->addString("Method", "claimpublicland");
+ msg->addUUID("Invoice", LLUUID::null);
+ std::string buffer;
+ buffer = llformat( "%f", west_south.mV[VX]);
+ msg->nextBlock("ParamList");
+ msg->addString("Parameter", buffer);
+ buffer = llformat( "%f", west_south.mV[VY]);
+ msg->nextBlock("ParamList");
+ msg->addString("Parameter", buffer);
+ buffer = llformat( "%f", east_north.mV[VX]);
+ msg->nextBlock("ParamList");
+ msg->addString("Parameter", buffer);
+ buffer = llformat( "%f", east_north.mV[VY]);
+ msg->nextBlock("ParamList");
+ msg->addString("Parameter", buffer);
+ gAgent.sendReliableMessage();
+}
+
+
+
+// HACK for easily testing new avatar geometry
+void handle_god_request_avatar_geometry(void *)
+{
+ if (gAgent.isGodlike())
+ {
+ LLSelectMgr::getInstance()->sendGodlikeRequest("avatar toggle", "");
+ }
+}
+
+
+void derez_objects(EDeRezDestination dest, const LLUUID& dest_id)
+{
+ if(gAgentCamera.cameraMouselook())
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+ //gInventoryView->setPanelOpen(TRUE);
+
+ std::string error;
+ LLDynamicArray<LLViewerObject*> derez_objects;
+
+ // Check conditions that we can't deal with, building a list of
+ // everything that we'll actually be derezzing.
+ LLViewerRegion* first_region = NULL;
+ for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+ LLViewerRegion* region = object->getRegion();
+ if (!first_region)
+ {
+ first_region = region;
+ }
+ else
+ {
+ if(region != first_region)
+ {
+ // Derez doesn't work at all if the some of the objects
+ // are in regions besides the first object selected.
+
+ // ...crosses region boundaries
+ error = "AcquireErrorObjectSpan";
+ break;
+ }
+ }
+ if (object->isAvatar())
+ {
+ // ...don't acquire avatars
+ continue;
+ }
+
+ // If AssetContainers are being sent back, they will appear as
+ // boxes in the owner's inventory.
+ if (object->getNVPair("AssetContainer")
+ && dest != DRD_RETURN_TO_OWNER)
+ {
+ // this object is an asset container, derez its contents, not it
+ llwarns << "Attempt to derez deprecated AssetContainer object type not supported." << llendl;
+ /*
+ object->requestInventory(container_inventory_arrived,
+ (void *)(BOOL)(DRD_TAKE_INTO_AGENT_INVENTORY == dest));
+ */
+ continue;
+ }
+ BOOL can_derez_current = FALSE;
+ switch(dest)
+ {
+ case DRD_TAKE_INTO_AGENT_INVENTORY:
+ case DRD_TRASH:
+ if( (node->mPermissions->allowTransferTo(gAgent.getID()) && object->permModify())
+ || (node->allowOperationOnNode(PERM_OWNER, GP_OBJECT_MANIPULATE)) )
+ {
+ can_derez_current = TRUE;
+ }
+ break;
+
+ case DRD_RETURN_TO_OWNER:
+ can_derez_current = TRUE;
+ break;
+
+ default:
+ if((node->mPermissions->allowTransferTo(gAgent.getID())
+ && object->permCopy())
+ || gAgent.isGodlike())
+ {
+ can_derez_current = TRUE;
+ }
+ break;
+ }
+ if(can_derez_current)
+ {
+ derez_objects.put(object);
+ }
+ }
+
+ // This constant is based on (1200 - HEADER_SIZE) / 4 bytes per
+ // root. I lopped off a few (33) to provide a bit
+ // pad. HEADER_SIZE is currently 67 bytes, most of which is UUIDs.
+ // This gives us a maximum of 63500 root objects - which should
+ // satisfy anybody.
+ const S32 MAX_ROOTS_PER_PACKET = 250;
+ const S32 MAX_PACKET_COUNT = 254;
+ F32 packets = ceil((F32)derez_objects.count() / (F32)MAX_ROOTS_PER_PACKET);
+ if(packets > (F32)MAX_PACKET_COUNT)
+ {
+ error = "AcquireErrorTooManyObjects";
+ }
+
+ if(error.empty() && derez_objects.count() > 0)
+ {
+ U8 d = (U8)dest;
+ LLUUID tid;
+ tid.generate();
+ U8 packet_count = (U8)packets;
+ S32 object_index = 0;
+ S32 objects_in_packet = 0;
+ LLMessageSystem* msg = gMessageSystem;
+ for(U8 packet_number = 0;
+ packet_number < packet_count;
+ ++packet_number)
+ {
+ msg->newMessageFast(_PREHASH_DeRezObject);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->nextBlockFast(_PREHASH_AgentBlock);
+ msg->addUUIDFast(_PREHASH_GroupID, gAgent.getGroupID());
+ msg->addU8Fast(_PREHASH_Destination, d);
+ msg->addUUIDFast(_PREHASH_DestinationID, dest_id);
+ msg->addUUIDFast(_PREHASH_TransactionID, tid);
+ msg->addU8Fast(_PREHASH_PacketCount, packet_count);
+ msg->addU8Fast(_PREHASH_PacketNumber, packet_number);
+ objects_in_packet = 0;
+ while((object_index < derez_objects.count())
+ && (objects_in_packet++ < MAX_ROOTS_PER_PACKET))
+
+ {
+ LLViewerObject* object = derez_objects.get(object_index++);
+ msg->nextBlockFast(_PREHASH_ObjectData);
+ msg->addU32Fast(_PREHASH_ObjectLocalID, object->getLocalID());
+ // VEFFECT: DerezObject
+ LLHUDEffectSpiral* effectp = (LLHUDEffectSpiral*)LLHUDManager::getInstance()->createViewerEffect(LLHUDObject::LL_HUD_EFFECT_POINT, TRUE);
+ effectp->setPositionGlobal(object->getPositionGlobal());
+ effectp->setColor(LLColor4U(gAgent.getEffectColor()));
+ }
+ msg->sendReliable(first_region->getHost());
+ }
+ make_ui_sound("UISndObjectRezOut");
+
+ // Busy count decremented by inventory update, so only increment
+ // if will be causing an update.
+ if (dest != DRD_RETURN_TO_OWNER)
+ {
+ gViewerWindow->getWindow()->incBusyCount();
+ }
+ }
+ else if(!error.empty())
+ {
+ LLNotificationsUtil::add(error);
+ }
+}
+
+void handle_take_copy()
+{
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
+
+ const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
+ derez_objects(DRD_ACQUIRE_TO_AGENT_INVENTORY, category_id);
+}
+
+// You can return an object to its owner if it is on your land.
+class LLObjectReturn : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return true;
+
+ mObjectSelection = LLSelectMgr::getInstance()->getEditSelection();
+
+ LLNotificationsUtil::add("ReturnToOwner", LLSD(), LLSD(), boost::bind(&LLObjectReturn::onReturnToOwner, this, _1, _2));
+ return true;
+ }
+
+ bool onReturnToOwner(const LLSD& notification, const LLSD& response)
+ {
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ // Ignore category ID for this derez destination.
+ derez_objects(DRD_RETURN_TO_OWNER, LLUUID::null);
+ }
+
+ // drop reference to current selection
+ mObjectSelection = NULL;
+ return false;
+ }
+
+protected:
+ LLObjectSelectionHandle mObjectSelection;
+};
+
+
+// Allow return to owner if one or more of the selected items is
+// over land you own.
+class LLObjectEnableReturn : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ // Do not enable if nothing selected
+ return false;
+ }
+#ifdef HACKED_GODLIKE_VIEWER
+ bool new_value = true;
+#else
+ bool new_value = false;
+ if (gAgent.isGodlike())
+ {
+ new_value = true;
+ }
+ else
+ {
+ LLViewerRegion* region = gAgent.getRegion();
+ if (region)
+ {
+ // Estate owners and managers can always return objects.
+ if (region->canManageEstate())
+ {
+ new_value = true;
+ }
+ else
+ {
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* obj)
+ {
+ return
+ obj->permModify() ||
+ obj->isReturnable();
+ }
+ } func;
+ const bool firstonly = true;
+ new_value = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
+ }
+ }
+ }
+#endif
+ return new_value;
+ }
+};
+
+void force_take_copy(void*)
+{
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
+ const LLUUID category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
+ derez_objects(DRD_FORCE_TO_GOD_INVENTORY, category_id);
+}
+
+void handle_take()
+{
+ // we want to use the folder this was derezzed from if it's
+ // available. Otherwise, derez to the normal place.
+ if(LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ return;
+ }
+
+ BOOL you_own_everything = TRUE;
+ BOOL locked_but_takeable_object = FALSE;
+ LLUUID category_id;
+
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+ if(object)
+ {
+ if(!object->permYouOwner())
+ {
+ you_own_everything = FALSE;
+ }
+
+ if(!object->permMove())
+ {
+ locked_but_takeable_object = TRUE;
+ }
+ }
+ if(node->mFolderID.notNull())
+ {
+ if(category_id.isNull())
+ {
+ category_id = node->mFolderID;
+ }
+ else if(category_id != node->mFolderID)
+ {
+ // we have found two potential destinations. break out
+ // now and send to the default location.
+ category_id.setNull();
+ break;
+ }
+ }
+ }
+ if(category_id.notNull())
+ {
+ // there is an unambiguous destination. See if this agent has
+ // such a location and it is not in the trash or library
+ if(!gInventory.getCategory(category_id))
+ {
+ // nope, set to NULL.
+ category_id.setNull();
+ }
+ if(category_id.notNull())
+ {
+ // check trash
+ const LLUUID trash = gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH);
+ if(category_id == trash || gInventory.isObjectDescendentOf(category_id, trash))
+ {
+ category_id.setNull();
+ }
+
+ // check library
+ if(gInventory.isObjectDescendentOf(category_id, gInventory.getLibraryRootFolderID()))
+ {
+ category_id.setNull();
+ }
+
+ }
+ }
+ if(category_id.isNull())
+ {
+ category_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_OBJECT);
+ }
+ LLSD payload;
+ payload["folder_id"] = category_id;
+
+ LLNotification::Params params("ConfirmObjectTakeLock");
+ params.payload(payload);
+ params.functor.function(confirm_take);
+
+ if(locked_but_takeable_object ||
+ !you_own_everything)
+ {
+ if(locked_but_takeable_object && you_own_everything)
+ {
+ params.name("ConfirmObjectTakeLock");
+ }
+ else if(!locked_but_takeable_object && !you_own_everything)
+ {
+ params.name("ConfirmObjectTakeNoOwn");
+ }
+ else
+ {
+ params.name("ConfirmObjectTakeLockNoOwn");
+ }
+
+ LLNotifications::instance().add(params);
+ }
+ else
+ {
+ LLNotifications::instance().forceResponse(params, 0);
+ }
+}
+
+void handle_object_show_inspector()
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ LLViewerObject* objectp = selection->getFirstRootObject(TRUE);
+ if (!objectp)
+ {
+ return;
+ }
+
+ LLSD params;
+ params["object_id"] = objectp->getID();
+ LLFloaterReg::showInstance("inspect_object", params);
+}
+
+void handle_avatar_show_inspector()
+{
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLSD params;
+ params["avatar_id"] = avatar->getID();
+ LLFloaterReg::showInstance("inspect_avatar", params);
+ }
+}
+
+
+
+bool confirm_take(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if(enable_take() && (option == 0))
+ {
+ derez_objects(DRD_TAKE_INTO_AGENT_INVENTORY, notification["payload"]["folder_id"].asUUID());
+ }
+ return false;
+}
+
+// You can take an item when it is public and transferrable, or when
+// you own it. We err on the side of enabling the item when at least
+// one item selected can be copied to inventory.
+BOOL enable_take()
+{
+ if (sitting_on_selection())
+ {
+ return FALSE;
+ }
+
+ for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+ if (object->isAvatar())
+ {
+ // ...don't acquire avatars
+ continue;
+ }
+
+#ifdef HACKED_GODLIKE_VIEWER
+ return TRUE;
+#else
+# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+ if (!LLGridManager::getInstance()->isInProductionGrid()
+ && gAgent.isGodlike())
+ {
+ return TRUE;
+ }
+# endif
+ if((node->mPermissions->allowTransferTo(gAgent.getID())
+ && object->permModify())
+ || (node->mPermissions->getOwner() == gAgent.getID()))
+ {
+ return TRUE;
+ }
+#endif
+ }
+ return FALSE;
+}
+
+
+void handle_buy_or_take()
+{
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ return;
+ }
+
+ if (is_selection_buy_not_take())
+ {
+ S32 total_price = selection_price();
+
+ if (total_price <= gStatusBar->getBalance() || total_price == 0)
+ {
+ handle_buy();
+ }
+ else
+ {
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", total_price);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString( "BuyingCosts", args ), total_price );
+ }
+ }
+ else
+ {
+ handle_take();
+ }
+}
+
+bool visible_buy_object()
+{
+ return is_selection_buy_not_take() && enable_buy_object();
+}
+
+bool visible_take_object()
+{
+ return !is_selection_buy_not_take() && enable_take();
+}
+
+bool tools_visible_buy_object()
+{
+ return is_selection_buy_not_take();
+}
+
+bool tools_visible_take_object()
+{
+ return !is_selection_buy_not_take();
+}
+
+class LLToolsEnableBuyOrTake : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool is_buy = is_selection_buy_not_take();
+ bool new_value = is_buy ? enable_buy_object() : enable_take();
+ return new_value;
+ }
+};
+
+// This is a small helper function to determine if we have a buy or a
+// take in the selection. This method is to help with the aliasing
+// problems of putting buy and take in the same pie menu space. After
+// a fair amont of discussion, it was determined to prefer buy over
+// take. The reasoning follows from the fact that when users walk up
+// to buy something, they will click on one or more items. Thus, if
+// anything is for sale, it becomes a buy operation, and the server
+// will group all of the buy items, and copyable/modifiable items into
+// one package and give the end user as much as the permissions will
+// allow. If the user wanted to take something, they will select fewer
+// and fewer items until only 'takeable' items are left. The one
+// exception is if you own everything in the selection that is for
+// sale, in this case, you can't buy stuff from yourself, so you can
+// take it.
+// return value = TRUE if selection is a 'buy'.
+// FALSE if selection is a 'take'
+BOOL is_selection_buy_not_take()
+{
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* obj = node->getObject();
+ if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale()))
+ {
+ // you do not own the object and it is for sale, thus,
+ // it's a buy
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+S32 selection_price()
+{
+ S32 total_price = 0;
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* obj = node->getObject();
+ if(obj && !(obj->permYouOwner()) && (node->mSaleInfo.isForSale()))
+ {
+ // you do not own the object and it is for sale.
+ // Add its price.
+ total_price += node->mSaleInfo.getSalePrice();
+ }
+ }
+
+ return total_price;
+}
+/*
+bool callback_show_buy_currency(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ llinfos << "Loading page " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL") << llendl;
+ LLWeb::loadURL(LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL"));
+ }
+ return false;
+}
+*/
+
+void show_buy_currency(const char* extra)
+{
+ // Don't show currency web page for branded clients.
+/*
+ std::ostringstream mesg;
+ if (extra != NULL)
+ {
+ mesg << extra << "\n \n";
+ }
+ mesg << "Go to " << LLNotifications::instance().getGlobalString("BUY_CURRENCY_URL")<< "\nfor information on purchasing currency?";
+*/
+ LLSD args;
+ if (extra != NULL)
+ {
+ args["EXTRA"] = extra;
+ }
+ LLNotificationsUtil::add("PromptGoToCurrencyPage", args);//, LLSD(), callback_show_buy_currency);
+}
+
+void handle_buy()
+{
+ if (LLSelectMgr::getInstance()->getSelection()->isEmpty()) return;
+
+ LLSaleInfo sale_info;
+ BOOL valid = LLSelectMgr::getInstance()->selectGetSaleInfo(sale_info);
+ if (!valid) return;
+
+ S32 price = sale_info.getSalePrice();
+
+ if (price > 0 && price > gStatusBar->getBalance())
+ {
+ LLStringUtil::format_map_t args;
+ args["AMOUNT"] = llformat("%d", price);
+ LLBuyCurrencyHTML::openCurrencyFloater( LLTrans::getString("this_object_costs", args), price );
+ return;
+ }
+
+ if (sale_info.getSaleType() == LLSaleInfo::FS_CONTENTS)
+ {
+ handle_buy_contents(sale_info);
+ }
+ else
+ {
+ handle_buy_object(sale_info);
+ }
+}
+
+bool anyone_copy_selection(LLSelectNode* nodep)
+{
+ bool perm_copy = (bool)(nodep->getObject()->permCopy());
+ bool all_copy = (bool)(nodep->mPermissions->getMaskEveryone() & PERM_COPY);
+ return perm_copy && all_copy;
+}
+
+bool for_sale_selection(LLSelectNode* nodep)
+{
+ return nodep->mSaleInfo.isForSale()
+ && nodep->mPermissions->getMaskOwner() & PERM_TRANSFER
+ && (nodep->mPermissions->getMaskOwner() & PERM_COPY
+ || nodep->mSaleInfo.getSaleType() != LLSaleInfo::FS_COPY);
+}
+
+BOOL sitting_on_selection()
+{
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if (!node)
+ {
+ return FALSE;
+ }
+
+ if (!node->mValid)
+ {
+ return FALSE;
+ }
+
+ LLViewerObject* root_object = node->getObject();
+ if (!root_object)
+ {
+ return FALSE;
+ }
+
+ // Need to determine if avatar is sitting on this object
+ if (!isAgentAvatarValid()) return FALSE;
+
+ return (gAgentAvatarp->isSitting() && gAgentAvatarp->getRoot() == root_object);
+}
+
+class LLToolsSaveToInventory : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if(enable_save_into_inventory(NULL))
+ {
+ derez_objects(DRD_SAVE_INTO_AGENT_INVENTORY, LLUUID::null);
+ }
+ return true;
+ }
+};
+
+class LLToolsSaveToObjectInventory : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if(node && (node->mValid) && (!node->mFromTaskID.isNull()))
+ {
+ // *TODO: check to see if the fromtaskid object exists.
+ derez_objects(DRD_SAVE_INTO_TASK_INVENTORY, node->mFromTaskID);
+ }
+ return true;
+ }
+};
+
+// Round the position of all root objects to the grid
+class LLToolsSnapObjectXY : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ F64 snap_size = (F64)gSavedSettings.getF32("GridResolution");
+
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* obj = node->getObject();
+ if (obj->permModify())
+ {
+ LLVector3d pos_global = obj->getPositionGlobal();
+ F64 round_x = fmod(pos_global.mdV[VX], snap_size);
+ if (round_x < snap_size * 0.5)
+ {
+ // closer to round down
+ pos_global.mdV[VX] -= round_x;
+ }
+ else
+ {
+ // closer to round up
+ pos_global.mdV[VX] -= round_x;
+ pos_global.mdV[VX] += snap_size;
+ }
+
+ F64 round_y = fmod(pos_global.mdV[VY], snap_size);
+ if (round_y < snap_size * 0.5)
+ {
+ pos_global.mdV[VY] -= round_y;
+ }
+ else
+ {
+ pos_global.mdV[VY] -= round_y;
+ pos_global.mdV[VY] += snap_size;
+ }
+
+ obj->setPositionGlobal(pos_global, FALSE);
+ }
+ }
+ LLSelectMgr::getInstance()->sendMultipleUpdate(UPD_POSITION);
+ return true;
+ }
+};
+
+// Determine if the option to cycle between linked prims is shown
+class LLToolsEnableSelectNextPart : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = (gSavedSettings.getBOOL("EditLinkedParts") &&
+ !LLSelectMgr::getInstance()->getSelection()->isEmpty());
+ return new_value;
+ }
+};
+
+// Cycle selection through linked children in selected object.
+// FIXME: Order of children list is not always the same as sim's idea of link order. This may confuse
+// resis. Need link position added to sim messages to address this.
+class LLToolsSelectNextPart : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ S32 object_count = LLSelectMgr::getInstance()->getSelection()->getObjectCount();
+ if (gSavedSettings.getBOOL("EditLinkedParts") && object_count)
+ {
+ LLViewerObject* selected = LLSelectMgr::getInstance()->getSelection()->getFirstObject();
+ if (selected && selected->getRootEdit())
+ {
+ bool fwd = (userdata.asString() == "next");
+ bool prev = (userdata.asString() == "previous");
+ bool ifwd = (userdata.asString() == "includenext");
+ bool iprev = (userdata.asString() == "includeprevious");
+ LLViewerObject* to_select = NULL;
+ LLViewerObject::child_list_t children = selected->getRootEdit()->getChildren();
+ children.push_front(selected->getRootEdit()); // need root in the list too
+
+ for (LLViewerObject::child_list_t::iterator iter = children.begin(); iter != children.end(); ++iter)
+ {
+ if ((*iter)->isSelected())
+ {
+ if (object_count > 1 && (fwd || prev)) // multiple selection, find first or last selected if not include
+ {
+ to_select = *iter;
+ if (fwd)
+ {
+ // stop searching if going forward; repeat to get last hit if backward
+ break;
+ }
+ }
+ else if ((object_count == 1) || (ifwd || iprev)) // single selection or include
+ {
+ if (fwd || ifwd)
+ {
+ ++iter;
+ while (iter != children.end() && ((*iter)->isAvatar() || (ifwd && (*iter)->isSelected())))
+ {
+ ++iter; // skip sitting avatars and selected if include
+ }
+ }
+ else // backward
+ {
+ iter = (iter == children.begin() ? children.end() : iter);
+ --iter;
+ while (iter != children.begin() && ((*iter)->isAvatar() || (iprev && (*iter)->isSelected())))
+ {
+ --iter; // skip sitting avatars and selected if include
+ }
+ }
+ iter = (iter == children.end() ? children.begin() : iter);
+ to_select = *iter;
+ break;
+ }
+ }
+ }
+
+ if (to_select)
+ {
+ if (gFocusMgr.childHasKeyboardFocus(gFloaterTools))
+ {
+ gFocusMgr.setKeyboardFocus(NULL); // force edit toolbox to commit any changes
+ }
+ if (fwd || prev)
+ {
+ LLSelectMgr::getInstance()->deselectAll();
+ }
+ LLSelectMgr::getInstance()->selectObjectOnly(to_select);
+ return true;
+ }
+ }
+ }
+ return true;
+ }
+};
+
+class LLToolsStopAllAnimations : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.stopCurrentAnimations();
+ return true;
+ }
+};
+
+class LLToolsReleaseKeys : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.forceReleaseControls();
+
+ return true;
+ }
+};
+
+class LLToolsEnableReleaseKeys : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return gAgent.anyControlGrabbed();
+ }
+};
+
+
+class LLEditEnableCut : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCut();
+ return new_value;
+ }
+};
+
+class LLEditCut : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler )
+ {
+ LLEditMenuHandler::gEditMenuHandler->cut();
+ }
+ return true;
+ }
+};
+
+class LLEditEnableCopy : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canCopy();
+ return new_value;
+ }
+};
+
+class LLEditCopy : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler )
+ {
+ LLEditMenuHandler::gEditMenuHandler->copy();
+ }
+ return true;
+ }
+};
+
+class LLEditEnablePaste : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canPaste();
+ return new_value;
+ }
+};
+
+class LLEditPaste : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler )
+ {
+ LLEditMenuHandler::gEditMenuHandler->paste();
+ }
+ return true;
+ }
+};
+
+class LLEditEnableDelete : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete();
+ return new_value;
+ }
+};
+
+class LLEditDelete : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // If a text field can do a deletion, it gets precedence over deleting
+ // an object in the world.
+ if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDoDelete())
+ {
+ LLEditMenuHandler::gEditMenuHandler->doDelete();
+ }
+
+ // and close any pie/context menus when done
+ gMenuHolder->hideMenus();
+
+ // When deleting an object we may not actually be done
+ // Keep selection so we know what to delete when confirmation is needed about the delete
+ gMenuObject->hide();
+ return true;
+ }
+};
+
+bool enable_object_delete()
+{
+ bool new_value =
+#ifdef HACKED_GODLIKE_VIEWER
+ TRUE;
+#else
+# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+ (!LLGridManager::getInstance()->isInProductionGrid()
+ && gAgent.isGodlike()) ||
+# endif
+ LLSelectMgr::getInstance()->canDoDelete();
+#endif
+ return new_value;
+}
+
+void handle_object_delete()
+{
+
+ if (LLSelectMgr::getInstance())
+ {
+ LLSelectMgr::getInstance()->doDelete();
+ }
+
+ // and close any pie/context menus when done
+ gMenuHolder->hideMenus();
+
+ // When deleting an object we may not actually be done
+ // Keep selection so we know what to delete when confirmation is needed about the delete
+ gMenuObject->hide();
+ return;
+}
+
+void handle_force_delete(void*)
+{
+ LLSelectMgr::getInstance()->selectForceDelete();
+}
+
+class LLViewEnableJoystickFlycam : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = (gSavedSettings.getBOOL("JoystickEnabled") && gSavedSettings.getBOOL("JoystickFlycamEnabled"));
+ return new_value;
+ }
+};
+
+class LLViewEnableLastChatter : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // *TODO: add check that last chatter is in range
+ bool new_value = (gAgentCamera.cameraThirdPerson() && gAgent.getLastChatter().notNull());
+ return new_value;
+ }
+};
+
+class LLEditEnableDeselect : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canDeselect();
+ return new_value;
+ }
+};
+
+class LLEditDeselect : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler )
+ {
+ LLEditMenuHandler::gEditMenuHandler->deselect();
+ }
+ return true;
+ }
+};
+
+class LLEditEnableSelectAll : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canSelectAll();
+ return new_value;
+ }
+};
+
+
+class LLEditSelectAll : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler )
+ {
+ LLEditMenuHandler::gEditMenuHandler->selectAll();
+ }
+ return true;
+ }
+};
+
+
+class LLEditEnableUndo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo();
+ return new_value;
+ }
+};
+
+class LLEditUndo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canUndo() )
+ {
+ LLEditMenuHandler::gEditMenuHandler->undo();
+ }
+ return true;
+ }
+};
+
+class LLEditEnableRedo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo();
+ return new_value;
+ }
+};
+
+class LLEditRedo : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if( LLEditMenuHandler::gEditMenuHandler && LLEditMenuHandler::gEditMenuHandler->canRedo() )
+ {
+ LLEditMenuHandler::gEditMenuHandler->redo();
+ }
+ return true;
+ }
+};
+
+
+
+void print_object_info(void*)
+{
+ LLSelectMgr::getInstance()->selectionDump();
+}
+
+void print_agent_nvpairs(void*)
+{
+ LLViewerObject *objectp;
+
+ llinfos << "Agent Name Value Pairs" << llendl;
+
+ objectp = gObjectList.findObject(gAgentID);
+ if (objectp)
+ {
+ objectp->printNameValuePairs();
+ }
+ else
+ {
+ llinfos << "Can't find agent object" << llendl;
+ }
+
+ llinfos << "Camera at " << gAgentCamera.getCameraPositionGlobal() << llendl;
+}
+
+void show_debug_menus()
+{
+ // this might get called at login screen where there is no menu so only toggle it if one exists
+ if ( gMenuBarView )
+ {
+ BOOL debug = gSavedSettings.getBOOL("UseDebugMenus");
+ BOOL qamode = gSavedSettings.getBOOL("QAMode");
+
+ gMenuBarView->setItemVisible("Advanced", debug);
+// gMenuBarView->setItemEnabled("Advanced", debug); // Don't disable Advanced keyboard shortcuts when hidden
+
+ gMenuBarView->setItemVisible("Debug", qamode);
+ gMenuBarView->setItemEnabled("Debug", qamode);
+
+ gMenuBarView->setItemVisible("Develop", qamode);
+ gMenuBarView->setItemEnabled("Develop", qamode);
+
+ // Server ('Admin') menu hidden when not in godmode.
+ const bool show_server_menu = (gAgent.getGodLevel() > GOD_NOT || (debug && gAgent.getAdminOverride()));
+ gMenuBarView->setItemVisible("Admin", show_server_menu);
+ gMenuBarView->setItemEnabled("Admin", show_server_menu);
+ }
+ if (gLoginMenuBarView)
+ {
+ BOOL debug = gSavedSettings.getBOOL("UseDebugMenus");
+ gLoginMenuBarView->setItemVisible("Debug", debug);
+ gLoginMenuBarView->setItemEnabled("Debug", debug);
+ }
+}
+
+void toggle_debug_menus(void*)
+{
+ BOOL visible = ! gSavedSettings.getBOOL("UseDebugMenus");
+ gSavedSettings.setBOOL("UseDebugMenus", visible);
+ show_debug_menus();
+}
+
+
+// LLUUID gExporterRequestID;
+// std::string gExportDirectory;
+
+// LLUploadDialog *gExportDialog = NULL;
+
+// void handle_export_selected( void * )
+// {
+// LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+// if (selection->isEmpty())
+// {
+// return;
+// }
+// llinfos << "Exporting selected objects:" << llendl;
+
+// gExporterRequestID.generate();
+// gExportDirectory = "";
+
+// LLMessageSystem* msg = gMessageSystem;
+// msg->newMessageFast(_PREHASH_ObjectExportSelected);
+// msg->nextBlockFast(_PREHASH_AgentData);
+// msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+// msg->addUUIDFast(_PREHASH_RequestID, gExporterRequestID);
+// msg->addS16Fast(_PREHASH_VolumeDetail, 4);
+
+// for (LLObjectSelection::root_iterator iter = selection->root_begin();
+// iter != selection->root_end(); iter++)
+// {
+// LLSelectNode* node = *iter;
+// LLViewerObject* object = node->getObject();
+// msg->nextBlockFast(_PREHASH_ObjectData);
+// msg->addUUIDFast(_PREHASH_ObjectID, object->getID());
+// llinfos << "Object: " << object->getID() << llendl;
+// }
+// msg->sendReliable(gAgent.getRegion()->getHost());
+
+// gExportDialog = LLUploadDialog::modalUploadDialog("Exporting selected objects...");
+// }
+//
+
+
+class LLWorldSetHomeLocation : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // we just send the message and let the server check for failure cases
+ // server will echo back a "Home position set." alert if it succeeds
+ // and the home location screencapture happens when that alert is recieved
+ gAgent.setStartPosition(START_LOCATION_ID_HOME);
+ return true;
+ }
+};
+
+class LLWorldTeleportHome : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gAgent.teleportHome();
+ return true;
+ }
+};
+
+class LLWorldAlwaysRun : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // as well as altering the default walk-vs-run state,
+ // we also change the *current* walk-vs-run state.
+ if (gAgent.getAlwaysRun())
+ {
+ gAgent.clearAlwaysRun();
+ gAgent.clearRunning();
+ }
+ else
+ {
+ gAgent.setAlwaysRun();
+ gAgent.setRunning();
+ }
+
+ // tell the simulator.
+ gAgent.sendWalkRun(gAgent.getAlwaysRun());
+
+ // Update Movement Controls according to AlwaysRun mode
+ LLFloaterMove::setAlwaysRunMode(gAgent.getAlwaysRun());
+
+ return true;
+ }
+};
+
+class LLWorldCheckAlwaysRun : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gAgent.getAlwaysRun();
+ return new_value;
+ }
+};
+
+class LLWorldSetAway : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgent.getAFK())
+ {
+ gAgent.clearAFK();
+ }
+ else
+ {
+ gAgent.setAFK();
+ }
+ return true;
+ }
+};
+
+class LLWorldSetBusy : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgent.getBusy())
+ {
+ gAgent.clearBusy();
+ }
+ else
+ {
+ gAgent.setBusy();
+ LLNotificationsUtil::add("BusyModeSet");
+ }
+ return true;
+ }
+};
+
+class LLWorldCreateLandmark : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "create_landmark"));
+
+ return true;
+ }
+};
+
+class LLWorldPlaceProfile : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSideTray::getInstance()->showPanel("panel_places", LLSD().with("type", "agent"));
+
+ return true;
+ }
+};
+
+void handle_look_at_selection(const LLSD& param)
+{
+ const F32 PADDING_FACTOR = 1.75f;
+ BOOL zoom = (param.asString() == "zoom");
+ if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+
+ LLBBox selection_bbox = LLSelectMgr::getInstance()->getBBoxOfSelection();
+ F32 angle_of_view = llmax(0.1f, LLViewerCamera::getInstance()->getAspect() > 1.f ? LLViewerCamera::getInstance()->getView() * LLViewerCamera::getInstance()->getAspect() : LLViewerCamera::getInstance()->getView());
+ F32 distance = selection_bbox.getExtentLocal().magVec() * PADDING_FACTOR / atan(angle_of_view);
+
+ LLVector3 obj_to_cam = LLViewerCamera::getInstance()->getOrigin() - selection_bbox.getCenterAgent();
+ obj_to_cam.normVec();
+
+ LLUUID object_id;
+ if (LLSelectMgr::getInstance()->getSelection()->getPrimaryObject())
+ {
+ object_id = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject()->mID;
+ }
+ if (zoom)
+ {
+ // Make sure we are not increasing the distance between the camera and object
+ LLVector3d orig_distance = gAgentCamera.getCameraPositionGlobal() - LLSelectMgr::getInstance()->getSelectionCenterGlobal();
+ distance = llmin(distance, (F32) orig_distance.length());
+
+ gAgentCamera.setCameraPosAndFocusGlobal(LLSelectMgr::getInstance()->getSelectionCenterGlobal() + LLVector3d(obj_to_cam * distance),
+ LLSelectMgr::getInstance()->getSelectionCenterGlobal(),
+ object_id );
+
+ }
+ else
+ {
+ gAgentCamera.setFocusGlobal( LLSelectMgr::getInstance()->getSelectionCenterGlobal(), object_id );
+ }
+ }
+}
+
+void handle_zoom_to_object(LLUUID object_id)
+{
+ const F32 PADDING_FACTOR = 2.f;
+
+ LLViewerObject* object = gObjectList.findObject(object_id);
+
+ 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,
+ object_id );
+ }
+}
+
+class LLAvatarInviteToGroup : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLAvatarActions::inviteToGroup(avatar->getID());
+ }
+ return true;
+ }
+};
+
+class LLAvatarAddFriend : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar && !LLAvatarActions::isFriend(avatar->getID()))
+ {
+ request_friendship(avatar->getID());
+ }
+ return true;
+ }
+};
+
+class LLAvatarAddContact : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ create_inventory_callingcard(avatar->getID());
+ }
+ return true;
+ }
+};
+
+bool complete_give_money(const LLSD& notification, const LLSD& response, LLObjectSelectionHandle selection)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option == 0)
+ {
+ gAgent.clearBusy();
+ }
+
+ LLViewerObject* objectp = selection->getPrimaryObject();
+
+ // Show avatar's name if paying attachment
+ if (objectp && objectp->isAttachment())
+ {
+ while (objectp && !objectp->isAvatar())
+ {
+ objectp = (LLViewerObject*)objectp->getParent();
+ }
+ }
+
+ if (objectp)
+ {
+ if (objectp->isAvatar())
+ {
+ const bool is_group = false;
+ LLFloaterPayUtil::payDirectly(&give_money,
+ objectp->getID(),
+ is_group);
+ }
+ else
+ {
+ LLFloaterPayUtil::payViaObject(&give_money, selection);
+ }
+ }
+ return false;
+}
+
+void handle_give_money_dialog()
+{
+ LLNotification::Params params("BusyModePay");
+ params.functor.function(boost::bind(complete_give_money, _1, _2, LLSelectMgr::getInstance()->getSelection()));
+
+ if (gAgent.getBusy())
+ {
+ // warn users of being in busy mode during a transaction
+ LLNotifications::instance().add(params);
+ }
+ else
+ {
+ LLNotifications::instance().forceResponse(params, 1);
+ }
+}
+
+bool enable_pay_avatar()
+{
+ LLViewerObject* obj = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ LLVOAvatar* avatar = find_avatar_from_object(obj);
+ return (avatar != NULL);
+}
+
+bool enable_pay_object()
+{
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if( object )
+ {
+ LLViewerObject *parent = (LLViewerObject *)object->getParent();
+ if((object->flagTakesMoney()) || (parent && parent->flagTakesMoney()))
+ {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool enable_object_stand_up()
+{
+ // 'Object Stand Up' menu item is enabled when agent is sitting on selection
+ return sitting_on_selection();
+}
+
+bool enable_object_sit(LLUICtrl* ctrl)
+{
+ // 'Object Sit' menu item is enabled when agent is not sitting on selection
+ bool sitting_on_sel = sitting_on_selection();
+ if (!sitting_on_sel)
+ {
+ std::string item_name = ctrl->getName();
+
+ // init default labels
+ init_default_item_label(item_name);
+
+ // Update label
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if (node && node->mValid && !node->mSitName.empty())
+ {
+ gMenuHolder->childSetText(item_name, node->mSitName);
+ }
+ else
+ {
+ gMenuHolder->childSetText(item_name, get_default_item_label(item_name));
+ }
+ }
+ return !sitting_on_sel && is_object_sittable();
+}
+
+void dump_select_mgr(void*)
+{
+ LLSelectMgr::getInstance()->dump();
+}
+
+void dump_inventory(void*)
+{
+ gInventory.dumpInventory();
+}
+
+
+void handle_dump_followcam(void*)
+{
+ LLFollowCamMgr::dump();
+}
+
+void handle_viewer_enable_message_log(void*)
+{
+ gMessageSystem->startLogging();
+}
+
+void handle_viewer_disable_message_log(void*)
+{
+ gMessageSystem->stopLogging();
+}
+
+void handle_customize_avatar()
+{
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "my_outfits"));
+}
+
+void handle_edit_outfit()
+{
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_outfit"));
+}
+
+void handle_edit_shape()
+{
+ LLSideTray::getInstance()->showPanel("sidepanel_appearance", LLSD().with("type", "edit_shape"));
+}
+
+void handle_report_abuse()
+{
+ // Prevent menu from appearing in screen shot.
+ gMenuHolder->hideMenus();
+ LLFloaterReporter::showFromMenu(COMPLAINT_REPORT);
+}
+
+void handle_buy_currency()
+{
+ LLBuyCurrencyHTML::openCurrencyFloater();
+}
+
+class LLFloaterVisible : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string floater_name = userdata.asString();
+ bool new_value = false;
+ {
+ new_value = LLFloaterReg::instanceVisible(floater_name);
+ }
+ return new_value;
+ }
+};
+
+class LLShowHelp : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string help_topic = userdata.asString();
+ LLViewerHelp* vhelp = LLViewerHelp::getInstance();
+ vhelp->showTopic(help_topic);
+ return true;
+ }
+};
+
+class LLToggleHelp : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloater* help_browser = (LLFloaterReg::findInstance("help_browser"));
+ if (help_browser && help_browser->isInVisibleChain())
+ {
+ help_browser->closeFloater();
+ }
+ else
+ {
+ std::string help_topic = userdata.asString();
+ LLViewerHelp* vhelp = LLViewerHelp::getInstance();
+ vhelp->showTopic(help_topic);
+ }
+ return true;
+ }
+};
+
+class LLShowSidetrayPanel : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string panel_name = userdata.asString();
+
+ LLPanel* panel = LLSideTray::getInstance()->getPanel(panel_name);
+ if (panel)
+ {
+ if (panel->isInVisibleChain())
+ {
+ LLSideTray::getInstance()->hidePanel(panel_name);
+ }
+ else
+ {
+ LLSideTray::getInstance()->showPanel(panel_name);
+ }
+ }
+ return true;
+ }
+};
+
+class LLSidetrayPanelVisible : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string panel_name = userdata.asString();
+ // Toggle the panel
+ if (LLSideTray::getInstance()->isPanelActive(panel_name))
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+
+ }
+};
+
+
+bool callback_show_url(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ LLWeb::loadURL(notification["payload"]["url"].asString());
+ }
+ return false;
+}
+
+class LLPromptShowURL : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string param = userdata.asString();
+ std::string::size_type offset = param.find(",");
+ if (offset != param.npos)
+ {
+ std::string alert = param.substr(0, offset);
+ std::string url = param.substr(offset+1);
+
+ if(gSavedSettings.getBOOL("UseExternalBrowser"))
+ {
+ LLSD payload;
+ payload["url"] = url;
+ LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_url);
+ }
+ else
+ {
+ LLWeb::loadURL(url);
+ }
+ }
+ else
+ {
+ llinfos << "PromptShowURL invalid parameters! Expecting \"ALERT,URL\"." << llendl;
+ }
+ return true;
+ }
+};
+
+bool callback_show_file(const LLSD& notification, const LLSD& response)
+{
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (0 == option)
+ {
+ LLWeb::loadURL(notification["payload"]["url"]);
+ }
+ return false;
+}
+
+class LLPromptShowFile : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string param = userdata.asString();
+ std::string::size_type offset = param.find(",");
+ if (offset != param.npos)
+ {
+ std::string alert = param.substr(0, offset);
+ std::string file = param.substr(offset+1);
+
+ LLSD payload;
+ payload["url"] = file;
+ LLNotificationsUtil::add(alert, LLSD(), payload, callback_show_file);
+ }
+ else
+ {
+ llinfos << "PromptShowFile invalid parameters! Expecting \"ALERT,FILE\"." << llendl;
+ }
+ return true;
+ }
+};
+
+class LLShowAgentProfile : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLUUID agent_id;
+ if (userdata.asString() == "agent")
+ {
+ agent_id = gAgent.getID();
+ }
+ else if (userdata.asString() == "hit object")
+ {
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (objectp)
+ {
+ agent_id = objectp->getID();
+ }
+ }
+ else
+ {
+ agent_id = userdata.asUUID();
+ }
+
+ LLVOAvatar* avatar = find_avatar_from_object(agent_id);
+ if (avatar)
+ {
+ LLAvatarActions::showProfile(avatar->getID());
+ }
+ return true;
+ }
+};
+
+class LLToggleAgentProfile : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLUUID agent_id;
+ if (userdata.asString() == "agent")
+ {
+ agent_id = gAgent.getID();
+ }
+ else if (userdata.asString() == "hit object")
+ {
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (objectp)
+ {
+ agent_id = objectp->getID();
+ }
+ }
+ else
+ {
+ agent_id = userdata.asUUID();
+ }
+
+ LLVOAvatar* avatar = find_avatar_from_object(agent_id);
+ if (avatar)
+ {
+ if (!LLAvatarActions::profileVisible(avatar->getID()))
+ {
+ LLAvatarActions::showProfile(avatar->getID());
+ }
+ else
+ {
+ LLAvatarActions::hideProfile(avatar->getID());
+ }
+ }
+ return true;
+ }
+};
+
+class LLLandEdit : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ if (gAgentCamera.getFocusOnAvatar() && gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ // zoom in if we're looking at the avatar
+ gAgentCamera.setFocusOnAvatar(FALSE, ANIMATE);
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+
+ gAgentCamera.cameraOrbitOver( F_PI * 0.25f );
+ gViewerWindow->moveCursorToCenter();
+ }
+ else if ( gSavedSettings.getBOOL("EditCameraMovement") )
+ {
+ gAgentCamera.setFocusGlobal(LLToolPie::getInstance()->getPick());
+ gViewerWindow->moveCursorToCenter();
+ }
+
+
+ LLViewerParcelMgr::getInstance()->selectParcelAt( LLToolPie::getInstance()->getPick().mPosGlobal );
+
+ LLFloaterReg::showInstance("build");
+
+ // Switch to land edit toolset
+ LLToolMgr::getInstance()->getCurrentToolset()->selectTool( LLToolSelectLand::getInstance() );
+ return true;
+ }
+};
+
+class LLWorldEnableBuyLand : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLViewerParcelMgr::getInstance()->canAgentBuyParcel(
+ LLViewerParcelMgr::getInstance()->selectionEmpty()
+ ? LLViewerParcelMgr::getInstance()->getAgentParcel()
+ : LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(),
+ false);
+ return new_value;
+ }
+};
+
+BOOL enable_buy_land(void*)
+{
+ return LLViewerParcelMgr::getInstance()->canAgentBuyParcel(
+ LLViewerParcelMgr::getInstance()->getParcelSelection()->getParcel(), false);
+}
+
+void handle_buy_land()
+{
+ LLViewerParcelMgr* vpm = LLViewerParcelMgr::getInstance();
+ if (vpm->selectionEmpty())
+ {
+ vpm->selectParcelAt(gAgent.getPositionGlobal());
+ }
+ vpm->startBuyLand();
+}
+
+class LLObjectAttachToAvatar : public view_listener_t
+{
+public:
+ LLObjectAttachToAvatar(bool replace) : mReplace(replace) {}
+ static void setObjectSelection(LLObjectSelectionHandle selection) { sObjectSelection = selection; }
+
+private:
+ bool handleEvent(const LLSD& userdata)
+ {
+ setObjectSelection(LLSelectMgr::getInstance()->getSelection());
+ LLViewerObject* selectedObject = sObjectSelection->getFirstRootObject();
+ if (selectedObject)
+ {
+ S32 index = userdata.asInteger();
+ LLViewerJointAttachment* attachment_point = NULL;
+ if (index > 0)
+ attachment_point = get_if_there(gAgentAvatarp->mAttachmentPoints, index, (LLViewerJointAttachment*)NULL);
+ confirmReplaceAttachment(0, attachment_point);
+ }
+ return true;
+ }
+
+ static void onNearAttachObject(BOOL success, void *user_data);
+ void confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point);
+
+ struct CallbackData
+ {
+ CallbackData(LLViewerJointAttachment* point, bool replace) : mAttachmentPoint(point), mReplace(replace) {}
+
+ LLViewerJointAttachment* mAttachmentPoint;
+ bool mReplace;
+ };
+
+protected:
+ static LLObjectSelectionHandle sObjectSelection;
+ bool mReplace;
+};
+
+LLObjectSelectionHandle LLObjectAttachToAvatar::sObjectSelection;
+
+// static
+void LLObjectAttachToAvatar::onNearAttachObject(BOOL success, void *user_data)
+{
+ if (!user_data) return;
+ CallbackData* cb_data = static_cast<CallbackData*>(user_data);
+
+ if (success)
+ {
+ const LLViewerJointAttachment *attachment = cb_data->mAttachmentPoint;
+
+ U8 attachment_id = 0;
+ if (attachment)
+ {
+ for (LLVOAvatar::attachment_map_t::const_iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end(); ++iter)
+ {
+ if (iter->second == attachment)
+ {
+ attachment_id = iter->first;
+ break;
+ }
+ }
+ }
+ else
+ {
+ // interpret 0 as "default location"
+ attachment_id = 0;
+ }
+ LLSelectMgr::getInstance()->sendAttach(attachment_id, cb_data->mReplace);
+ }
+ LLObjectAttachToAvatar::setObjectSelection(NULL);
+
+ delete cb_data;
+}
+
+// static
+void LLObjectAttachToAvatar::confirmReplaceAttachment(S32 option, LLViewerJointAttachment* attachment_point)
+{
+ if (option == 0/*YES*/)
+ {
+ LLViewerObject* selectedObject = LLSelectMgr::getInstance()->getSelection()->getFirstRootObject();
+ if (selectedObject)
+ {
+ const F32 MIN_STOP_DISTANCE = 1.f; // meters
+ const F32 ARM_LENGTH = 0.5f; // meters
+ const F32 SCALE_FUDGE = 1.5f;
+
+ F32 stop_distance = SCALE_FUDGE * selectedObject->getMaxScale() + ARM_LENGTH;
+ if (stop_distance < MIN_STOP_DISTANCE)
+ {
+ stop_distance = MIN_STOP_DISTANCE;
+ }
+
+ LLVector3 walkToSpot = selectedObject->getPositionAgent();
+
+ // make sure we stop in front of the object
+ LLVector3 delta = walkToSpot - gAgent.getPositionAgent();
+ delta.normVec();
+ delta = delta * 0.5f;
+ walkToSpot -= delta;
+
+ // The callback will be called even if avatar fails to get close enough to the object, so we won't get a memory leak.
+ CallbackData* user_data = new CallbackData(attachment_point, mReplace);
+ gAgent.startAutoPilotGlobal(gAgent.getPosGlobalFromAgent(walkToSpot), "Attach", NULL, onNearAttachObject, user_data, stop_distance);
+ gAgentCamera.clearFocusObject();
+ }
+ }
+}
+
+void callback_attachment_drop(const LLSD& notification, const LLSD& response)
+{
+ // Ensure user confirmed the drop
+ S32 option = LLNotificationsUtil::getSelectedOption(notification, response);
+ if (option != 0) return;
+
+ // Called when the user clicked on an object attached to them
+ // and selected "Drop".
+ LLUUID object_id = notification["payload"]["object_id"].asUUID();
+ LLViewerObject *object = gObjectList.findObject(object_id);
+
+ if (!object)
+ {
+ llwarns << "handle_drop_attachment() - no object to drop" << llendl;
+ return;
+ }
+
+ LLViewerObject *parent = (LLViewerObject*)object->getParent();
+ while (parent)
+ {
+ if(parent->isAvatar())
+ {
+ break;
+ }
+ object = parent;
+ parent = (LLViewerObject*)parent->getParent();
+ }
+
+ if (!object)
+ {
+ llwarns << "handle_detach() - no object to detach" << llendl;
+ return;
+ }
+
+ if (object->isAvatar())
+ {
+ llwarns << "Trying to detach avatar from avatar." << llendl;
+ return;
+ }
+
+ // reselect the object
+ LLSelectMgr::getInstance()->selectObjectAndFamily(object);
+
+ LLSelectMgr::getInstance()->sendDropAttachment();
+
+ return;
+}
+
+class LLAttachmentDrop : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSD payload;
+ LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+
+ if (object)
+ {
+ payload["object_id"] = object->getID();
+ }
+ else
+ {
+ llwarns << "Drop object not found" << llendl;
+ return true;
+ }
+
+ LLNotificationsUtil::add("AttachmentDrop", LLSD(), payload, &callback_attachment_drop);
+ return true;
+ }
+};
+
+// called from avatar pie menu
+class LLAttachmentDetachFromPoint : public view_listener_t
+{
+ bool handleEvent(const LLSD& user_data)
+ {
+ const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, user_data.asInteger(), (LLViewerJointAttachment*)NULL);
+ if (attachment->getNumObjects() > 0)
+ {
+ gMessageSystem->newMessage("ObjectDetach");
+ gMessageSystem->nextBlockFast(_PREHASH_AgentData);
+ gMessageSystem->addUUIDFast(_PREHASH_AgentID, gAgent.getID() );
+ gMessageSystem->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+
+ for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator iter = attachment->mAttachedObjects.begin();
+ iter != attachment->mAttachedObjects.end();
+ iter++)
+ {
+ LLViewerObject *attached_object = (*iter);
+ gMessageSystem->nextBlockFast(_PREHASH_ObjectData);
+ gMessageSystem->addU32Fast(_PREHASH_ObjectLocalID, attached_object->getLocalID());
+ }
+ gMessageSystem->sendReliable( gAgent.getRegionHost() );
+ }
+ return true;
+ }
+};
+
+static bool onEnableAttachmentLabel(LLUICtrl* ctrl, const LLSD& data)
+{
+ std::string label;
+ LLMenuItemGL* menu = dynamic_cast<LLMenuItemGL*>(ctrl);
+ if (menu)
+ {
+ const LLViewerJointAttachment *attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, data["index"].asInteger(), (LLViewerJointAttachment*)NULL);
+ if (attachment)
+ {
+ label = data["label"].asString();
+ for (LLViewerJointAttachment::attachedobjs_vec_t::const_iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ const LLViewerObject* attached_object = (*attachment_iter);
+ if (attached_object)
+ {
+ LLViewerInventoryItem* itemp = gInventory.getItem(attached_object->getAttachmentItemID());
+ if (itemp)
+ {
+ label += std::string(" (") + itemp->getName() + std::string(")");
+ break;
+ }
+ }
+ }
+ }
+ menu->setLabel(label);
+ }
+ return true;
+}
+
+class LLAttachmentDetach : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // Called when the user clicked on an object attached to them
+ // and selected "Detach".
+ LLViewerObject *object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (!object)
+ {
+ llwarns << "handle_detach() - no object to detach" << llendl;
+ return true;
+ }
+
+ LLViewerObject *parent = (LLViewerObject*)object->getParent();
+ while (parent)
+ {
+ if(parent->isAvatar())
+ {
+ break;
+ }
+ object = parent;
+ parent = (LLViewerObject*)parent->getParent();
+ }
+
+ if (!object)
+ {
+ llwarns << "handle_detach() - no object to detach" << llendl;
+ return true;
+ }
+
+ if (object->isAvatar())
+ {
+ llwarns << "Trying to detach avatar from avatar." << llendl;
+ return true;
+ }
+
+ // The sendDetach() method works on the list of selected
+ // objects. Thus we need to clear the list, make sure it only
+ // contains the object the user clicked, send the message,
+ // then clear the list.
+ // We use deselectAll to update the simulator's notion of what's
+ // selected, and removeAll just to change things locally.
+ //RN: I thought it was more useful to detach everything that was selected
+ if (LLSelectMgr::getInstance()->getSelection()->isAttachment())
+ {
+ LLSelectMgr::getInstance()->sendDetach();
+ }
+ return true;
+ }
+};
+
+//Adding an observer for a Jira 2422 and needs to be a fetch observer
+//for Jira 3119
+class LLWornItemFetchedObserver : public LLInventoryFetchItemsObserver
+{
+public:
+ LLWornItemFetchedObserver(const LLUUID& worn_item_id) :
+ LLInventoryFetchItemsObserver(worn_item_id)
+ {}
+ virtual ~LLWornItemFetchedObserver() {}
+
+protected:
+ virtual void done()
+ {
+ gMenuAttachmentSelf->buildDrawLabels();
+ gInventory.removeObserver(this);
+ delete this;
+ }
+};
+
+// You can only drop items on parcels where you can build.
+class LLAttachmentEnableDrop : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ BOOL can_build = gAgent.isGodlike() || (LLViewerParcelMgr::getInstance()->allowAgentBuild());
+
+ //Add an inventory observer to only allow dropping the newly attached item
+ //once it exists in your inventory. Look at Jira 2422.
+ //-jwolk
+
+ // A bug occurs when you wear/drop an item before it actively is added to your inventory
+ // if this is the case (you're on a slow sim, etc.) a copy of the object,
+ // well, a newly created object with the same properties, is placed
+ // in your inventory. Therefore, we disable the drop option until the
+ // item is in your inventory
+
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ LLViewerJointAttachment* attachment = NULL;
+ LLInventoryItem* item = NULL;
+
+ // Do not enable drop if all faces of object are not enabled
+ if (object && LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES ))
+ {
+ S32 attachmentID = ATTACHMENT_ID_FROM_STATE(object->getState());
+ attachment = get_if_there(gAgentAvatarp->mAttachmentPoints, attachmentID, (LLViewerJointAttachment*)NULL);
+
+ if (attachment)
+ {
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ // make sure item is in your inventory (it could be a delayed attach message being sent from the sim)
+ // so check to see if the item is in the inventory already
+ item = gInventory.getItem((*attachment_iter)->getAttachmentItemID());
+ if (!item)
+ {
+ // Item does not exist, make an observer to enable the pie menu
+ // when the item finishes fetching worst case scenario
+ // if a fetch is already out there (being sent from a slow sim)
+ // we refetch and there are 2 fetches
+ LLWornItemFetchedObserver* worn_item_fetched = new LLWornItemFetchedObserver((*attachment_iter)->getAttachmentItemID());
+ worn_item_fetched->startFetch();
+ gInventory.addObserver(worn_item_fetched);
+ }
+ }
+ }
+ }
+
+ //now check to make sure that the item is actually in the inventory before we enable dropping it
+ bool new_value = enable_detach() && can_build && item;
+
+ return new_value;
+ }
+};
+
+BOOL enable_detach(const LLSD&)
+{
+ LLViewerObject* object = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+
+ // Only enable detach if all faces of object are selected
+ if (!object ||
+ !object->isAttachment() ||
+ !LLSelectMgr::getInstance()->getSelection()->contains(object,SELECT_ALL_TES ))
+ {
+ return FALSE;
+ }
+
+ // Find the avatar who owns this attachment
+ LLViewerObject* avatar = object;
+ while (avatar)
+ {
+ // ...if it's you, good to detach
+ if (avatar->getID() == gAgent.getID())
+ {
+ return TRUE;
+ }
+
+ avatar = (LLViewerObject*)avatar->getParent();
+ }
+
+ return FALSE;
+}
+
+class LLAttachmentEnableDetach : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = enable_detach();
+ return new_value;
+ }
+};
+
+// Used to tell if the selected object can be attached to your avatar.
+BOOL object_selected_and_point_valid()
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ for (LLObjectSelection::root_iterator iter = selection->root_begin();
+ iter != selection->root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ LLViewerObject* object = node->getObject();
+ LLViewerObject::const_child_list_t& child_list = object->getChildren();
+ for (LLViewerObject::child_list_t::const_iterator iter = child_list.begin();
+ iter != child_list.end(); iter++)
+ {
+ LLViewerObject* child = *iter;
+ if (child->isAvatar())
+ {
+ return FALSE;
+ }
+ }
+ }
+
+ return (selection->getRootObjectCount() == 1) &&
+ (selection->getFirstRootObject()->getPCode() == LL_PCODE_VOLUME) &&
+ selection->getFirstRootObject()->permYouOwner() &&
+ selection->getFirstRootObject()->flagObjectMove() &&
+ !((LLViewerObject*)selection->getFirstRootObject()->getRoot())->isAvatar() &&
+ (selection->getFirstRootObject()->getNVPair("AssetContainer") == NULL);
+}
+
+
+BOOL object_is_wearable()
+{
+ if (!object_selected_and_point_valid())
+ {
+ return FALSE;
+ }
+ if (sitting_on_selection())
+ {
+ return FALSE;
+ }
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ for (LLObjectSelection::valid_root_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->valid_root_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+ if (node->mPermissions->getOwner() == gAgent.getID())
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+class LLAttachmentPointFilled : public view_listener_t
+{
+ bool handleEvent(const LLSD& user_data)
+ {
+ bool enable = false;
+ LLVOAvatar::attachment_map_t::iterator found_it = gAgentAvatarp->mAttachmentPoints.find(user_data.asInteger());
+ if (found_it != gAgentAvatarp->mAttachmentPoints.end())
+ {
+ enable = found_it->second->getNumObjects() > 0;
+ }
+ return enable;
+ }
+};
+
+class LLAvatarSendIM : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLAvatarActions::startIM(avatar->getID());
+ }
+ return true;
+ }
+};
+
+class LLAvatarCall : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLVOAvatar* avatar = find_avatar_from_object( LLSelectMgr::getInstance()->getSelection()->getPrimaryObject() );
+ if(avatar)
+ {
+ LLAvatarActions::startCall(avatar->getID());
+ }
+ return true;
+ }
+};
+
+namespace
+{
+ struct QueueObjects : public LLSelectedObjectFunctor
+ {
+ BOOL scripted;
+ BOOL modifiable;
+ LLFloaterScriptQueue* mQueue;
+ QueueObjects(LLFloaterScriptQueue* q) : mQueue(q), scripted(FALSE), modifiable(FALSE) {}
+ virtual bool apply(LLViewerObject* obj)
+ {
+ scripted = obj->flagScripted();
+ modifiable = obj->permModify();
+
+ if( scripted && modifiable )
+ {
+ mQueue->addObject(obj->getID());
+ return false;
+ }
+ else
+ {
+ return true; // fail: stop applying
+ }
+ }
+ };
+}
+
+void queue_actions(LLFloaterScriptQueue* q, const std::string& msg)
+{
+ QueueObjects func(q);
+ LLSelectMgr *mgr = LLSelectMgr::getInstance();
+ LLObjectSelectionHandle selectHandle = mgr->getSelection();
+ bool fail = selectHandle->applyToObjects(&func);
+ if(fail)
+ {
+ if ( !func.scripted )
+ {
+ std::string noscriptmsg = std::string("Cannot") + msg + "SelectObjectsNoScripts";
+ LLNotificationsUtil::add(noscriptmsg);
+ }
+ else if ( !func.modifiable )
+ {
+ std::string nomodmsg = std::string("Cannot") + msg + "SelectObjectsNoPermission";
+ LLNotificationsUtil::add(nomodmsg);
+ }
+ else
+ {
+ llerrs << "Bad logic." << llendl;
+ }
+ }
+ else
+ {
+ if (!q->start())
+ {
+ llwarns << "Unexpected script compile failure." << llendl;
+ }
+ }
+}
+
+class LLToolsSelectedScriptAction : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string action = userdata.asString();
+ bool mono = false;
+ std::string msg, name;
+ if (action == "compile mono")
+ {
+ name = "compile_queue";
+ mono = true;
+ msg = "Recompile";
+ }
+ if (action == "compile lsl")
+ {
+ name = "compile_queue";
+ msg = "Recompile";
+ }
+ else if (action == "reset")
+ {
+ name = "reset_queue";
+ msg = "Reset";
+ }
+ else if (action == "start")
+ {
+ name = "start_queue";
+ msg = "Running";
+ }
+ else if (action == "stop")
+ {
+ name = "stop_queue";
+ msg = "RunningNot";
+ }
+ LLUUID id; id.generate();
+
+ LLFloaterScriptQueue* queue =LLFloaterReg::getTypedInstance<LLFloaterScriptQueue>(name, LLSD(id));
+ if (queue)
+ {
+ queue->setMono(mono);
+ queue_actions(queue, msg);
+ }
+ else
+ {
+ llwarns << "Failed to generate LLFloaterScriptQueue with action: " << action << llendl;
+ }
+ return true;
+ }
+};
+
+void handle_selected_texture_info(void*)
+{
+ for (LLObjectSelection::valid_iterator iter = LLSelectMgr::getInstance()->getSelection()->valid_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->valid_end(); iter++)
+ {
+ LLSelectNode* node = *iter;
+
+ std::string msg;
+ msg.assign("Texture info for: ");
+ msg.append(node->mName);
+
+ LLSD args;
+ args["MESSAGE"] = msg;
+ LLNotificationsUtil::add("SystemMessage", args);
+
+ U8 te_count = node->getObject()->getNumTEs();
+ // map from texture ID to list of faces using it
+ typedef std::map< LLUUID, std::vector<U8> > map_t;
+ map_t faces_per_texture;
+ for (U8 i = 0; i < te_count; i++)
+ {
+ if (!node->isTESelected(i)) continue;
+
+ LLViewerTexture* img = node->getObject()->getTEImage(i);
+ LLUUID image_id = img->getID();
+ faces_per_texture[image_id].push_back(i);
+ }
+ // Per-texture, dump which faces are using it.
+ map_t::iterator it;
+ for (it = faces_per_texture.begin(); it != faces_per_texture.end(); ++it)
+ {
+ LLUUID image_id = it->first;
+ U8 te = it->second[0];
+ LLViewerTexture* img = node->getObject()->getTEImage(te);
+ S32 height = img->getHeight();
+ S32 width = img->getWidth();
+ S32 components = img->getComponents();
+ msg = llformat("%dx%d %s on face ",
+ width,
+ height,
+ (components == 4 ? "alpha" : "opaque"));
+ for (U8 i = 0; i < it->second.size(); ++i)
+ {
+ msg.append( llformat("%d ", (S32)(it->second[i])));
+ }
+
+ LLSD args;
+ args["MESSAGE"] = msg;
+ LLNotificationsUtil::add("SystemMessage", args);
+ }
+ }
+}
+
+void handle_test_male(void*)
+{
+ LLAppearanceMgr::instance().wearOutfitByName("Male Shape & Outfit");
+ //gGestureList.requestResetFromServer( TRUE );
+}
+
+void handle_test_female(void*)
+{
+ LLAppearanceMgr::instance().wearOutfitByName("Female Shape & Outfit");
+ //gGestureList.requestResetFromServer( FALSE );
+}
+
+void handle_toggle_pg(void*)
+{
+ gAgent.setTeen( !gAgent.isTeen() );
+
+ LLFloaterWorldMap::reloadIcons(NULL);
+
+ llinfos << "PG status set to " << (S32)gAgent.isTeen() << llendl;
+}
+
+void handle_dump_attachments(void*)
+{
+ if(!isAgentAvatarValid()) return;
+
+ for (LLVOAvatar::attachment_map_t::iterator iter = gAgentAvatarp->mAttachmentPoints.begin();
+ iter != gAgentAvatarp->mAttachmentPoints.end(); )
+ {
+ LLVOAvatar::attachment_map_t::iterator curiter = iter++;
+ LLViewerJointAttachment* attachment = curiter->second;
+ S32 key = curiter->first;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ LLViewerObject *attached_object = (*attachment_iter);
+ BOOL visible = (attached_object != NULL &&
+ attached_object->mDrawable.notNull() &&
+ !attached_object->mDrawable->isRenderType(0));
+ LLVector3 pos;
+ if (visible) pos = attached_object->mDrawable->getPosition();
+ llinfos << "ATTACHMENT " << key << ": item_id=" << attached_object->getAttachmentItemID()
+ << (attached_object ? " present " : " absent ")
+ << (visible ? "visible " : "invisible ")
+ << " at " << pos
+ << " and " << (visible ? attached_object->getPosition() : LLVector3::zero)
+ << llendl;
+ }
+ }
+}
+
+
+// these are used in the gl menus to set control values, generically.
+class LLToggleControl : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string control_name = userdata.asString();
+ BOOL checked = gSavedSettings.getBOOL( control_name );
+ gSavedSettings.setBOOL( control_name, !checked );
+ return true;
+ }
+};
+
+class LLCheckControl : public view_listener_t
+{
+ bool handleEvent( const LLSD& userdata)
+ {
+ std::string callback_data = userdata.asString();
+ bool new_value = gSavedSettings.getBOOL(callback_data);
+ return new_value;
+ }
+};
+
+// not so generic
+
+class LLAdvancedCheckRenderShadowOption: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string control_name = userdata.asString();
+ S32 current_shadow_level = gSavedSettings.getS32(control_name);
+ if (current_shadow_level == 0) // is off
+ {
+ return false;
+ }
+ else // is on
+ {
+ return true;
+ }
+ }
+};
+
+class LLAdvancedClickRenderShadowOption: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string control_name = userdata.asString();
+ S32 current_shadow_level = gSavedSettings.getS32(control_name);
+ if (current_shadow_level == 0) // upgrade to level 2
+ {
+ gSavedSettings.setS32(control_name, 2);
+ }
+ else // downgrade to level 0
+ {
+ gSavedSettings.setS32(control_name, 0);
+ }
+ return true;
+ }
+};
+
+void menu_toggle_attached_lights(void* user_data)
+{
+ LLPipeline::sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
+}
+
+void menu_toggle_attached_particles(void* user_data)
+{
+ LLPipeline::sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
+}
+
+class LLAdvancedHandleAttachedLightParticles: public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string control_name = userdata.asString();
+
+ // toggle the control
+ gSavedSettings.setBOOL(control_name,
+ !gSavedSettings.getBOOL(control_name));
+
+ // update internal flags
+ if (control_name == "RenderAttachedLights")
+ {
+ menu_toggle_attached_lights(NULL);
+ }
+ else if (control_name == "RenderAttachedParticles")
+ {
+ menu_toggle_attached_particles(NULL);
+ }
+ return true;
+ }
+};
+
+class LLSomethingSelected : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = !(LLSelectMgr::getInstance()->getSelection()->isEmpty());
+ return new_value;
+ }
+};
+
+class LLSomethingSelectedNoHUD : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+ bool new_value = !(selection->isEmpty()) && !(selection->getSelectType() == SELECT_TYPE_HUD);
+ return new_value;
+ }
+};
+
+static bool is_editable_selected()
+{
+ return (LLSelectMgr::getInstance()->getSelection()->getFirstEditableObject() != NULL);
+}
+
+class LLEditableSelected : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return is_editable_selected();
+ }
+};
+
+class LLEditableSelectedMono : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = false;
+ LLViewerRegion* region = gAgent.getRegion();
+ if(region && gMenuHolder)
+ {
+ bool have_cap = (! region->getCapability("UpdateScriptTask").empty());
+ new_value = is_editable_selected() && have_cap;
+ }
+ return new_value;
+ }
+};
+
+bool enable_object_take_copy()
+{
+ bool all_valid = false;
+ if (LLSelectMgr::getInstance())
+ {
+ if (!LLSelectMgr::getInstance()->getSelection()->isEmpty())
+ {
+ all_valid = true;
+#ifndef HACKED_GODLIKE_VIEWER
+# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+ if (LLGridManager::getInstance()->isInProductionGrid()
+ || !gAgent.isGodlike())
+# endif
+ {
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* obj)
+ {
+ return (!obj->permCopy() || obj->isAttachment());
+ }
+ } func;
+ const bool firstonly = true;
+ bool any_invalid = LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func, firstonly);
+ all_valid = !any_invalid;
+ }
+#endif // HACKED_GODLIKE_VIEWER
+ }
+ }
+
+ return all_valid;
+}
+
+
+class LLHasAsset : public LLInventoryCollectFunctor
+{
+public:
+ LLHasAsset(const LLUUID& id) : mAssetID(id), mHasAsset(FALSE) {}
+ virtual ~LLHasAsset() {}
+ virtual bool operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item);
+ BOOL hasAsset() const { return mHasAsset; }
+
+protected:
+ LLUUID mAssetID;
+ BOOL mHasAsset;
+};
+
+bool LLHasAsset::operator()(LLInventoryCategory* cat,
+ LLInventoryItem* item)
+{
+ if(item && item->getAssetUUID() == mAssetID)
+ {
+ mHasAsset = TRUE;
+ }
+ return FALSE;
+}
+
+BOOL enable_save_into_inventory(void*)
+{
+ // *TODO: clean this up
+ // find the last root
+ LLSelectNode* last_node = NULL;
+ for (LLObjectSelection::root_iterator iter = LLSelectMgr::getInstance()->getSelection()->root_begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->root_end(); iter++)
+ {
+ last_node = *iter;
+ }
+
+#ifdef HACKED_GODLIKE_VIEWER
+ return TRUE;
+#else
+# ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+ if (!LLGridManager::getInstance()->isInProductionGrid()
+ && gAgent.isGodlike())
+ {
+ return TRUE;
+ }
+# endif
+ // check all pre-req's for save into inventory.
+ if(last_node && last_node->mValid && !last_node->mItemID.isNull()
+ && (last_node->mPermissions->getOwner() == gAgent.getID())
+ && (gInventory.getItem(last_node->mItemID) != NULL))
+ {
+ LLViewerObject* obj = last_node->getObject();
+ if( obj && !obj->isAttachment() )
+ {
+ return TRUE;
+ }
+ }
+#endif
+ return FALSE;
+}
+
+class LLToolsEnableSaveToInventory : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = enable_save_into_inventory(NULL);
+ return new_value;
+ }
+};
+
+BOOL enable_save_into_task_inventory(void*)
+{
+ LLSelectNode* node = LLSelectMgr::getInstance()->getSelection()->getFirstRootNode();
+ if(node && (node->mValid) && (!node->mFromTaskID.isNull()))
+ {
+ // *TODO: check to see if the fromtaskid object exists.
+ LLViewerObject* obj = node->getObject();
+ if( obj && !obj->isAttachment() )
+ {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+class LLToolsEnableSaveToObjectInventory : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = enable_save_into_task_inventory(NULL);
+ return new_value;
+ }
+};
+
+
+class LLViewEnableMouselook : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // You can't go directly from customize avatar to mouselook.
+ // TODO: write code with appropriate dialogs to handle this transition.
+ bool new_value = (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && !gSavedSettings.getBOOL("FreezeTime"));
+ return new_value;
+ }
+};
+
+class LLToolsEnableToolNotPie : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = ( LLToolMgr::getInstance()->getBaseTool() != LLToolPie::getInstance() );
+ return new_value;
+ }
+};
+
+class LLWorldEnableCreateLandmark : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ return !LLLandmarkActions::landmarkAlreadyExists();
+ }
+};
+
+class LLWorldEnableSetHomeLocation : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gAgent.isGodlike() ||
+ (gAgent.getRegion() && gAgent.getRegion()->getAllowSetHome());
+ return new_value;
+ }
+};
+
+class LLWorldEnableTeleportHome : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLViewerRegion* regionp = gAgent.getRegion();
+ bool agent_on_prelude = (regionp && regionp->isPrelude());
+ bool enable_teleport_home = gAgent.isGodlike() || !agent_on_prelude;
+ return enable_teleport_home;
+ }
+};
+
+BOOL enable_god_full(void*)
+{
+ return gAgent.getGodLevel() >= GOD_FULL;
+}
+
+BOOL enable_god_liaison(void*)
+{
+ return gAgent.getGodLevel() >= GOD_LIAISON;
+}
+
+bool is_god_customer_service()
+{
+ return gAgent.getGodLevel() >= GOD_CUSTOMER_SERVICE;
+}
+
+BOOL enable_god_basic(void*)
+{
+ return gAgent.getGodLevel() > GOD_NOT;
+}
+
+
+void toggle_show_xui_names(void *)
+{
+ gSavedSettings.setBOOL("DebugShowXUINames", !gSavedSettings.getBOOL("DebugShowXUINames"));
+}
+
+BOOL check_show_xui_names(void *)
+{
+ return gSavedSettings.getBOOL("DebugShowXUINames");
+}
+
+class LLToolsSelectOnlyMyObjects : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ BOOL cur_val = gSavedSettings.getBOOL("SelectOwnedOnly");
+
+ gSavedSettings.setBOOL("SelectOwnedOnly", ! cur_val );
+
+ return true;
+ }
+};
+
+class LLToolsSelectOnlyMovableObjects : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ BOOL cur_val = gSavedSettings.getBOOL("SelectMovableOnly");
+
+ gSavedSettings.setBOOL("SelectMovableOnly", ! cur_val );
+
+ return true;
+ }
+};
+
+class LLToolsSelectBySurrounding : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSelectMgr::sRectSelectInclusive = !LLSelectMgr::sRectSelectInclusive;
+
+ gSavedSettings.setBOOL("RectangleSelectInclusive", LLSelectMgr::sRectSelectInclusive);
+ return true;
+ }
+};
+
+class LLToolsShowHiddenSelection : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // TomY TODO Merge these
+ LLSelectMgr::sRenderHiddenSelections = !LLSelectMgr::sRenderHiddenSelections;
+
+ gSavedSettings.setBOOL("RenderHiddenSelections", LLSelectMgr::sRenderHiddenSelections);
+ return true;
+ }
+};
+
+class LLToolsShowSelectionLightRadius : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ // TomY TODO merge these
+ LLSelectMgr::sRenderLightRadius = !LLSelectMgr::sRenderLightRadius;
+
+ gSavedSettings.setBOOL("RenderLightRadius", LLSelectMgr::sRenderLightRadius);
+ return true;
+ }
+};
+
+class LLToolsEditLinkedParts : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ BOOL select_individuals = !gSavedSettings.getBOOL("EditLinkedParts");
+ gSavedSettings.setBOOL( "EditLinkedParts", select_individuals );
+ if (select_individuals)
+ {
+ LLSelectMgr::getInstance()->demoteSelectionToIndividuals();
+ }
+ else
+ {
+ LLSelectMgr::getInstance()->promoteSelectionToRoot();
+ }
+ return true;
+ }
+};
+
+void reload_vertex_shader(void *)
+{
+ //THIS WOULD BE AN AWESOME PLACE TO RELOAD SHADERS... just a thought - DaveP
+}
+
+void handle_dump_avatar_local_textures(void*)
+{
+ gAgentAvatarp->dumpLocalTextures();
+}
+
+void handle_dump_timers()
+{
+ LLFastTimer::dumpCurTimes();
+}
+
+void handle_debug_avatar_textures(void*)
+{
+ LLViewerObject* objectp = LLSelectMgr::getInstance()->getSelection()->getPrimaryObject();
+ if (objectp)
+ {
+ LLFloaterReg::showInstance( "avatar_textures", LLSD(objectp->getID()) );
+ }
+}
+
+void handle_grab_baked_texture(void* data)
+{
+ EBakedTextureIndex baked_tex_index = (EBakedTextureIndex)((intptr_t)data);
+ if (!isAgentAvatarValid()) return;
+
+ const LLUUID& asset_id = gAgentAvatarp->grabBakedTexture(baked_tex_index);
+ LL_INFOS("texture") << "Adding baked texture " << asset_id << " to inventory." << llendl;
+ LLAssetType::EType asset_type = LLAssetType::AT_TEXTURE;
+ LLInventoryType::EType inv_type = LLInventoryType::IT_TEXTURE;
+ const LLUUID folder_id = gInventory.findCategoryUUIDForType(LLFolderType::assetTypeToFolderType(asset_type));
+ if(folder_id.notNull())
+ {
+ std::string name;
+ name = "Baked " + LLVOAvatarDictionary::getInstance()->getBakedTexture(baked_tex_index)->mNameCapitalized + " Texture";
+
+ LLUUID item_id;
+ item_id.generate();
+ LLPermissions perm;
+ perm.init(gAgentID,
+ gAgentID,
+ LLUUID::null,
+ LLUUID::null);
+ U32 next_owner_perm = PERM_MOVE | PERM_TRANSFER;
+ perm.initMasks(PERM_ALL,
+ PERM_ALL,
+ PERM_NONE,
+ PERM_NONE,
+ next_owner_perm);
+ time_t creation_date_now = time_corrected();
+ LLPointer<LLViewerInventoryItem> item
+ = new LLViewerInventoryItem(item_id,
+ folder_id,
+ perm,
+ asset_id,
+ asset_type,
+ inv_type,
+ name,
+ LLStringUtil::null,
+ LLSaleInfo::DEFAULT,
+ LLInventoryItemFlags::II_FLAGS_NONE,
+ creation_date_now);
+
+ item->updateServer(TRUE);
+ gInventory.updateItem(item);
+ gInventory.notifyObservers();
+
+ // Show the preview panel for textures to let
+ // user know that the image is now in inventory.
+ LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel();
+ if(active_panel)
+ {
+ LLFocusableElement* focus_ctrl = gFocusMgr.getKeyboardFocus();
+
+ active_panel->setSelection(item_id, TAKE_FOCUS_NO);
+ active_panel->openSelected();
+ //LLFloaterInventory::dumpSelectionInformation((void*)view);
+ // restore keyboard focus
+ gFocusMgr.setKeyboardFocus(focus_ctrl);
+ }
+ }
+ else
+ {
+ llwarns << "Can't find a folder to put it in" << llendl;
+ }
+}
+
+BOOL enable_grab_baked_texture(void* data)
+{
+ EBakedTextureIndex index = (EBakedTextureIndex)((intptr_t)data);
+ if (isAgentAvatarValid())
+ {
+ return gAgentAvatarp->canGrabBakedTexture(index);
+ }
+ return FALSE;
+}
+
+// Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing.
+// Returns NULL on failure.
+LLVOAvatar* find_avatar_from_object( LLViewerObject* object )
+{
+ if (object)
+ {
+ if( object->isAttachment() )
+ {
+ do
+ {
+ object = (LLViewerObject*) object->getParent();
+ }
+ while( object && !object->isAvatar() );
+ }
+ else if( !object->isAvatar() )
+ {
+ object = NULL;
+ }
+ }
+
+ return (LLVOAvatar*) object;
+}
+
+
+// Returns a pointer to the avatar give the UUID of the avatar OR of an attachment the avatar is wearing.
+// Returns NULL on failure.
+LLVOAvatar* find_avatar_from_object( const LLUUID& object_id )
+{
+ return find_avatar_from_object( gObjectList.findObject(object_id) );
+}
+
+
+void handle_disconnect_viewer(void *)
+{
+ LLAppViewer::instance()->forceDisconnect(LLTrans::getString("TestingDisconnect"));
+}
+
+void force_error_breakpoint(void *)
+{
+ LLAppViewer::instance()->forceErrorBreakpoint();
+}
+
+void force_error_llerror(void *)
+{
+ LLAppViewer::instance()->forceErrorLLError();
+}
+
+void force_error_bad_memory_access(void *)
+{
+ LLAppViewer::instance()->forceErrorBadMemoryAccess();
+}
+
+void force_error_infinite_loop(void *)
+{
+ LLAppViewer::instance()->forceErrorInfiniteLoop();
+}
+
+void force_error_software_exception(void *)
+{
+ LLAppViewer::instance()->forceErrorSoftwareException();
+}
+
+void force_error_driver_crash(void *)
+{
+ LLAppViewer::instance()->forceErrorDriverCrash();
+}
+
+class LLToolsUseSelectionForGrid : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLSelectMgr::getInstance()->clearGridObjects();
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* objectp)
+ {
+ LLSelectMgr::getInstance()->addGridObject(objectp);
+ return true;
+ }
+ } func;
+ LLSelectMgr::getInstance()->getSelection()->applyToRootObjects(&func);
+ LLSelectMgr::getInstance()->setGridMode(GRID_MODE_REF_OBJECT);
+ if (gFloaterTools)
+ {
+ gFloaterTools->mComboGridMode->setCurrentByIndex((S32)GRID_MODE_REF_OBJECT);
+ }
+ return true;
+ }
+};
+
+void handle_test_load_url(void*)
+{
+ LLWeb::loadURL("");
+ LLWeb::loadURL("hacker://www.google.com/");
+ LLWeb::loadURL("http");
+ LLWeb::loadURL("http://www.google.com/");
+}
+
+//
+// LLViewerMenuHolderGL
+//
+static LLDefaultChildRegistry::Register<LLViewerMenuHolderGL> r("menu_holder");
+
+LLViewerMenuHolderGL::LLViewerMenuHolderGL(const LLViewerMenuHolderGL::Params& p)
+: LLMenuHolderGL(p)
+{}
+
+BOOL LLViewerMenuHolderGL::hideMenus()
+{
+ BOOL handled = LLMenuHolderGL::hideMenus();
+
+ // drop pie menu selection
+ mParcelSelection = NULL;
+ mObjectSelection = NULL;
+
+ if (gMenuBarView)
+ {
+ gMenuBarView->clearHoverItem();
+ gMenuBarView->resetMenuTrigger();
+ }
+
+ return handled;
+}
+
+void LLViewerMenuHolderGL::setParcelSelection(LLSafeHandle<LLParcelSelection> selection)
+{
+ mParcelSelection = selection;
+}
+
+void LLViewerMenuHolderGL::setObjectSelection(LLSafeHandle<LLObjectSelection> selection)
+{
+ mObjectSelection = selection;
+}
+
+
+const LLRect LLViewerMenuHolderGL::getMenuRect() const
+{
+ return LLRect(0, getRect().getHeight() - MENU_BAR_HEIGHT, getRect().getWidth(), STATUS_BAR_HEIGHT);
+}
+
+void handle_web_browser_test(const LLSD& param)
+{
+ std::string url = param.asString();
+ if (url.empty())
+ {
+ url = "about:blank";
+ }
+ LLWeb::loadURLInternal(url);
+}
+
+void handle_web_content_test(const LLSD& param)
+{
+ std::string url = param.asString();
+ LLWeb::loadWebURLInternal(url);
+}
+
+void handle_buy_currency_test(void*)
+{
+ std::string url =
+ "http://sarahd-sl-13041.webdev.lindenlab.com/app/lindex/index.php?agent_id=[AGENT_ID]&secure_session_id=[SESSION_ID]&lang=[LANGUAGE]";
+
+ LLStringUtil::format_map_t replace;
+ replace["[AGENT_ID]"] = gAgent.getID().asString();
+ replace["[SESSION_ID]"] = gAgent.getSecureSessionID().asString();
+ replace["[LANGUAGE]"] = LLUI::getLanguage();
+ LLStringUtil::format(url, replace);
+
+ llinfos << "buy currency url " << url << llendl;
+
+ LLFloaterReg::showInstance("buy_currency_html", LLSD(url));
+}
+
+void handle_rebake_textures(void*)
+{
+ if (!isAgentAvatarValid()) return;
+
+ // Slam pending upload count to "unstick" things
+ bool slam_for_debug = true;
+ gAgentAvatarp->forceBakeAllTextures(slam_for_debug);
+}
+
+void toggle_visibility(void* user_data)
+{
+ LLView* viewp = (LLView*)user_data;
+ viewp->setVisible(!viewp->getVisible());
+}
+
+BOOL get_visibility(void* user_data)
+{
+ LLView* viewp = (LLView*)user_data;
+ return viewp->getVisible();
+}
+
+// TomY TODO: Get rid of these?
+class LLViewShowHoverTips : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ gSavedSettings.setBOOL("ShowHoverTips", !gSavedSettings.getBOOL("ShowHoverTips"));
+ return true;
+ }
+};
+
+class LLViewCheckShowHoverTips : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = gSavedSettings.getBOOL("ShowHoverTips");
+ return new_value;
+ }
+};
+
+// TomY TODO: Get rid of these?
+class LLViewHighlightTransparent : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLDrawPoolAlpha::sShowDebugAlpha = !LLDrawPoolAlpha::sShowDebugAlpha;
+ return true;
+ }
+};
+
+class LLViewCheckHighlightTransparent : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLDrawPoolAlpha::sShowDebugAlpha;
+ return new_value;
+ }
+};
+
+class LLViewBeaconWidth : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string width = userdata.asString();
+ if(width == "1")
+ {
+ gSavedSettings.setS32("DebugBeaconLineWidth", 1);
+ }
+ else if(width == "4")
+ {
+ gSavedSettings.setS32("DebugBeaconLineWidth", 4);
+ }
+ else if(width == "16")
+ {
+ gSavedSettings.setS32("DebugBeaconLineWidth", 16);
+ }
+ else if(width == "32")
+ {
+ gSavedSettings.setS32("DebugBeaconLineWidth", 32);
+ }
+
+ return true;
+ }
+};
+
+
+class LLViewToggleBeacon : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string beacon = userdata.asString();
+ if (beacon == "scriptsbeacon")
+ {
+ LLPipeline::toggleRenderScriptedBeacons(NULL);
+ gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons(NULL) );
+ // toggle the other one off if it's on
+ if (LLPipeline::getRenderScriptedBeacons(NULL) && LLPipeline::getRenderScriptedTouchBeacons(NULL))
+ {
+ LLPipeline::toggleRenderScriptedTouchBeacons(NULL);
+ gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons(NULL) );
+ }
+ }
+ else if (beacon == "physicalbeacon")
+ {
+ LLPipeline::toggleRenderPhysicalBeacons(NULL);
+ gSavedSettings.setBOOL( "physicalbeacon", LLPipeline::getRenderPhysicalBeacons(NULL) );
+ }
+ else if (beacon == "soundsbeacon")
+ {
+ LLPipeline::toggleRenderSoundBeacons(NULL);
+ gSavedSettings.setBOOL( "soundsbeacon", LLPipeline::getRenderSoundBeacons(NULL) );
+ }
+ else if (beacon == "particlesbeacon")
+ {
+ LLPipeline::toggleRenderParticleBeacons(NULL);
+ gSavedSettings.setBOOL( "particlesbeacon", LLPipeline::getRenderParticleBeacons(NULL) );
+ }
+ else if (beacon == "scripttouchbeacon")
+ {
+ LLPipeline::toggleRenderScriptedTouchBeacons(NULL);
+ gSavedSettings.setBOOL( "scripttouchbeacon", LLPipeline::getRenderScriptedTouchBeacons(NULL) );
+ // toggle the other one off if it's on
+ if (LLPipeline::getRenderScriptedBeacons(NULL) && LLPipeline::getRenderScriptedTouchBeacons(NULL))
+ {
+ LLPipeline::toggleRenderScriptedBeacons(NULL);
+ gSavedSettings.setBOOL( "scriptsbeacon", LLPipeline::getRenderScriptedBeacons(NULL) );
+ }
+ }
+ else if (beacon == "renderbeacons")
+ {
+ LLPipeline::toggleRenderBeacons(NULL);
+ gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons(NULL) );
+ // toggle the other one on if it's not
+ if (!LLPipeline::getRenderBeacons(NULL) && !LLPipeline::getRenderHighlights(NULL))
+ {
+ LLPipeline::toggleRenderHighlights(NULL);
+ gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights(NULL) );
+ }
+ }
+ else if (beacon == "renderhighlights")
+ {
+ LLPipeline::toggleRenderHighlights(NULL);
+ gSavedSettings.setBOOL( "renderhighlights", LLPipeline::getRenderHighlights(NULL) );
+ // toggle the other one on if it's not
+ if (!LLPipeline::getRenderBeacons(NULL) && !LLPipeline::getRenderHighlights(NULL))
+ {
+ LLPipeline::toggleRenderBeacons(NULL);
+ gSavedSettings.setBOOL( "renderbeacons", LLPipeline::getRenderBeacons(NULL) );
+ }
+ }
+
+ return true;
+ }
+};
+
+class LLViewCheckBeaconEnabled : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string beacon = userdata.asString();
+ bool new_value = false;
+ if (beacon == "scriptsbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "scriptsbeacon");
+ LLPipeline::setRenderScriptedBeacons(new_value);
+ }
+ else if (beacon == "physicalbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "physicalbeacon");
+ LLPipeline::setRenderPhysicalBeacons(new_value);
+ }
+ else if (beacon == "soundsbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "soundsbeacon");
+ LLPipeline::setRenderSoundBeacons(new_value);
+ }
+ else if (beacon == "particlesbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "particlesbeacon");
+ LLPipeline::setRenderParticleBeacons(new_value);
+ }
+ else if (beacon == "scripttouchbeacon")
+ {
+ new_value = gSavedSettings.getBOOL( "scripttouchbeacon");
+ LLPipeline::setRenderScriptedTouchBeacons(new_value);
+ }
+ else if (beacon == "renderbeacons")
+ {
+ new_value = gSavedSettings.getBOOL( "renderbeacons");
+ LLPipeline::setRenderBeacons(new_value);
+ }
+ else if (beacon == "renderhighlights")
+ {
+ new_value = gSavedSettings.getBOOL( "renderhighlights");
+ LLPipeline::setRenderHighlights(new_value);
+ }
+ return new_value;
+ }
+};
+
+class LLViewToggleRenderType : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string type = userdata.asString();
+ if (type == "hideparticles")
+ {
+ LLPipeline::toggleRenderType(LLPipeline::RENDER_TYPE_PARTICLES);
+ }
+ return true;
+ }
+};
+
+class LLViewCheckRenderType : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string type = userdata.asString();
+ bool new_value = false;
+ if (type == "hideparticles")
+ {
+ new_value = LLPipeline::toggleRenderTypeControlNegated((void *)LLPipeline::RENDER_TYPE_PARTICLES);
+ }
+ return new_value;
+ }
+};
+
+class LLViewShowHUDAttachments : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLPipeline::sShowHUDAttachments = !LLPipeline::sShowHUDAttachments;
+ return true;
+ }
+};
+
+class LLViewCheckHUDAttachments : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool new_value = LLPipeline::sShowHUDAttachments;
+ return new_value;
+ }
+};
+
+class LLEditEnableTakeOff : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string clothing = userdata.asString();
+ LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
+ if (type >= LLWearableType::WT_SHAPE && type < LLWearableType::WT_COUNT)
+ return LLAgentWearables::selfHasWearable(type);
+ return false;
+ }
+};
+
+class LLEditTakeOff : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string clothing = userdata.asString();
+ if (clothing == "all")
+ LLWearableBridge::removeAllClothesFromAvatar();
+ else
+ {
+ LLWearableType::EType type = LLWearableType::typeNameToType(clothing);
+ if (type >= LLWearableType::WT_SHAPE
+ && type < LLWearableType::WT_COUNT
+ && (gAgentWearables.getWearableCount(type) > 0))
+ {
+ // MULTI-WEARABLES: assuming user wanted to remove top shirt.
+ U32 wearable_index = gAgentWearables.getWearableCount(type) - 1;
+ LLViewerInventoryItem *item = dynamic_cast<LLViewerInventoryItem*>(gAgentWearables.getWearableInventoryItem(type,wearable_index));
+ LLWearableBridge::removeItemFromAvatar(item);
+ }
+
+ }
+ return true;
+ }
+};
+
+class LLToolsSelectTool : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string tool_name = userdata.asString();
+ if (tool_name == "focus")
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(1);
+ }
+ else if (tool_name == "move")
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(2);
+ }
+ else if (tool_name == "edit")
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(3);
+ }
+ else if (tool_name == "create")
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(4);
+ }
+ else if (tool_name == "land")
+ {
+ LLToolMgr::getInstance()->getCurrentToolset()->selectToolByIndex(5);
+ }
+ return true;
+ }
+};
+
+/// WINDLIGHT callbacks
+class LLWorldEnvSettings : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string tod = userdata.asString();
+ LLVector3 sun_direction;
+
+ if (tod == "editor")
+ {
+ // if not there or is hidden, show it
+ LLFloaterReg::toggleInstance("env_settings");
+ return true;
+ }
+
+ if (tod == "sunrise")
+ {
+ // set the value, turn off animation
+ LLWLParamManager::instance()->mAnimator.setDayTime(0.25);
+ LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+ LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+ // then call update once
+ LLWLParamManager::instance()->mAnimator.update(
+ LLWLParamManager::instance()->mCurParams);
+ }
+ else if (tod == "noon")
+ {
+ // set the value, turn off animation
+ LLWLParamManager::instance()->mAnimator.setDayTime(0.567);
+ LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+ LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+ // then call update once
+ LLWLParamManager::instance()->mAnimator.update(
+ LLWLParamManager::instance()->mCurParams);
+ }
+ else if (tod == "sunset")
+ {
+ // set the value, turn off animation
+ LLWLParamManager::instance()->mAnimator.setDayTime(0.75);
+ LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+ LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+ // then call update once
+ LLWLParamManager::instance()->mAnimator.update(
+ LLWLParamManager::instance()->mCurParams);
+ }
+ else if (tod == "midnight")
+ {
+ // set the value, turn off animation
+ LLWLParamManager::instance()->mAnimator.setDayTime(0.0);
+ LLWLParamManager::instance()->mAnimator.mIsRunning = false;
+ LLWLParamManager::instance()->mAnimator.mUseLindenTime = false;
+
+ // then call update once
+ LLWLParamManager::instance()->mAnimator.update(
+ LLWLParamManager::instance()->mCurParams);
+ }
+ else
+ {
+ LLWLParamManager::instance()->mAnimator.mIsRunning = true;
+ LLWLParamManager::instance()->mAnimator.mUseLindenTime = true;
+ }
+ return true;
+ }
+};
+
+/// Water Menu callbacks
+class LLWorldWaterSettings : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterReg::toggleInstance("env_water");
+ return true;
+ }
+};
+
+/// Post-Process callbacks
+class LLWorldPostProcess : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterReg::showInstance("env_post_process");
+ return true;
+ }
+};
+
+/// Day Cycle callbacks
+class LLWorldDayCycle : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLFloaterReg::showInstance("env_day_cycle");
+ return true;
+ }
+};
+
+class LLWorldToggleMovementControls : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLBottomTray::getInstance()->toggleMovementControls();
+ return true;
+ }
+};
+
+class LLWorldToggleCameraControls : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ LLBottomTray::getInstance()->toggleCameraControls();
+ return true;
+ }
+};
+
+void handle_flush_name_caches()
+{
+ // Toggle display names on and off to flush
+ bool use_display_names = LLAvatarNameCache::useDisplayNames();
+ LLAvatarNameCache::setUseDisplayNames(!use_display_names);
+ LLAvatarNameCache::setUseDisplayNames(use_display_names);
+
+ if (gCacheName) gCacheName->clear();
+}
+
+class LLUploadCostCalculator : public view_listener_t
+{
+ std::string mCostStr;
+
+ bool handleEvent(const LLSD& userdata)
+ {
+ std::string menu_name = userdata.asString();
+ gMenuHolder->childSetLabelArg(menu_name, "[COST]", mCostStr);
+
+ return true;
+ }
+
+ void calculateCost();
+
+public:
+ LLUploadCostCalculator()
+ {
+ calculateCost();
+ }
+};
+
+class LLToggleUIHints : public view_listener_t
+{
+ bool handleEvent(const LLSD& userdata)
+ {
+ bool ui_hints_enabled = gSavedSettings.getBOOL("EnableUIHints");
+ // toggle
+ ui_hints_enabled = !ui_hints_enabled;
+ gSavedSettings.setBOOL("EnableUIHints", ui_hints_enabled);
+ return true;
+ }
+};
+
+void LLUploadCostCalculator::calculateCost()
+{
+ S32 upload_cost = LLGlobalEconomy::Singleton::getInstance()->getPriceUpload();
+
+ // getPriceUpload() returns -1 if no data available yet.
+ if(upload_cost >= 0)
+ {
+ mCostStr = llformat("%d", upload_cost);
+ }
+ else
+ {
+ mCostStr = llformat("%d", gSavedSettings.getU32("DefaultUploadCost"));
+ }
+}
+
+void show_navbar_context_menu(LLView* ctrl, S32 x, S32 y)
+{
+ static LLMenuGL* show_navbar_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_hide_navbar.xml",
+ gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+ if(gMenuHolder->hasVisibleMenu())
+ {
+ gMenuHolder->hideMenus();
+ }
+ show_navbar_context_menu->buildDrawLabels();
+ show_navbar_context_menu->updateParent(LLMenuGL::sMenuContainer);
+ LLMenuGL::showPopup(ctrl, show_navbar_context_menu, x, y);
+}
+
+void show_topinfobar_context_menu(LLView* ctrl, S32 x, S32 y)
+{
+ static LLMenuGL* show_topbarinfo_context_menu = LLUICtrlFactory::getInstance()->createFromFile<LLMenuGL>("menu_topinfobar.xml",
+ gMenuHolder, LLViewerMenuHolderGL::child_registry_t::instance());
+
+ LLMenuItemGL* landmark_item = show_topbarinfo_context_menu->getChild<LLMenuItemGL>("Landmark");
+ if (!LLLandmarkActions::landmarkAlreadyExists())
+ {
+ landmark_item->setLabel(LLTrans::getString("AddLandmarkNavBarMenu"));
+ }
+ else
+ {
+ landmark_item->setLabel(LLTrans::getString("EditLandmarkNavBarMenu"));
+ }
+
+ if(gMenuHolder->hasVisibleMenu())
+ {
+ gMenuHolder->hideMenus();
+ }
+
+ show_topbarinfo_context_menu->buildDrawLabels();
+ show_topbarinfo_context_menu->updateParent(LLMenuGL::sMenuContainer);
+ LLMenuGL::showPopup(ctrl, show_topbarinfo_context_menu, x, y);
+}
+
+void initialize_edit_menu()
+{
+ view_listener_t::addMenu(new LLEditUndo(), "Edit.Undo");
+ view_listener_t::addMenu(new LLEditRedo(), "Edit.Redo");
+ view_listener_t::addMenu(new LLEditCut(), "Edit.Cut");
+ view_listener_t::addMenu(new LLEditCopy(), "Edit.Copy");
+ view_listener_t::addMenu(new LLEditPaste(), "Edit.Paste");
+ view_listener_t::addMenu(new LLEditDelete(), "Edit.Delete");
+ view_listener_t::addMenu(new LLEditSelectAll(), "Edit.SelectAll");
+ view_listener_t::addMenu(new LLEditDeselect(), "Edit.Deselect");
+ view_listener_t::addMenu(new LLEditDuplicate(), "Edit.Duplicate");
+ view_listener_t::addMenu(new LLEditTakeOff(), "Edit.TakeOff");
+ view_listener_t::addMenu(new LLEditEnableUndo(), "Edit.EnableUndo");
+ view_listener_t::addMenu(new LLEditEnableRedo(), "Edit.EnableRedo");
+ view_listener_t::addMenu(new LLEditEnableCut(), "Edit.EnableCut");
+ view_listener_t::addMenu(new LLEditEnableCopy(), "Edit.EnableCopy");
+ view_listener_t::addMenu(new LLEditEnablePaste(), "Edit.EnablePaste");
+ view_listener_t::addMenu(new LLEditEnableDelete(), "Edit.EnableDelete");
+ view_listener_t::addMenu(new LLEditEnableSelectAll(), "Edit.EnableSelectAll");
+ view_listener_t::addMenu(new LLEditEnableDeselect(), "Edit.EnableDeselect");
+ view_listener_t::addMenu(new LLEditEnableDuplicate(), "Edit.EnableDuplicate");
+
+}
+
+void initialize_menus()
+{
+ // A parameterized event handler used as ctrl-8/9/0 zoom controls below.
+ class LLZoomer : public view_listener_t
+ {
+ public:
+ // The "mult" parameter says whether "val" is a multiplier or used to set the value.
+ LLZoomer(F32 val, bool mult=true) : mVal(val), mMult(mult) {}
+ bool handleEvent(const LLSD& userdata)
+ {
+ F32 new_fov_rad = mMult ? LLViewerCamera::getInstance()->getDefaultFOV() * mVal : mVal;
+ LLViewerCamera::getInstance()->setDefaultFOV(new_fov_rad);
+ gSavedSettings.setF32("CameraAngle", LLViewerCamera::getInstance()->getView()); // setView may have clamped it.
+ return true;
+ }
+ private:
+ F32 mVal;
+ bool mMult;
+ };
+
+ LLUICtrl::EnableCallbackRegistry::Registrar& enable = LLUICtrl::EnableCallbackRegistry::currentRegistrar();
+ LLUICtrl::CommitCallbackRegistry::Registrar& commit = LLUICtrl::CommitCallbackRegistry::currentRegistrar();
+
+ // Generic enable and visible
+ // Don't prepend MenuName.Foo because these can be used in any menu.
+ enable.add("IsGodCustomerService", boost::bind(&is_god_customer_service));
+
+ view_listener_t::addEnable(new LLUploadCostCalculator(), "Upload.CalculateCosts");
+
+ // Agent
+ commit.add("Agent.toggleFlying", boost::bind(&LLAgent::toggleFlying));
+ enable.add("Agent.enableFlying", boost::bind(&LLAgent::enableFlying));
+
+ // File menu
+ init_menu_file();
+
+ view_listener_t::addMenu(new LLEditEnableTakeOff(), "Edit.EnableTakeOff");
+ view_listener_t::addMenu(new LLEditEnableCustomizeAvatar(), "Edit.EnableCustomizeAvatar");
+ view_listener_t::addMenu(new LLEnableEditShape(), "Edit.EnableEditShape");
+ commit.add("CustomizeAvatar", boost::bind(&handle_customize_avatar));
+ commit.add("EditOutfit", boost::bind(&handle_edit_outfit));
+ commit.add("EditShape", boost::bind(&handle_edit_shape));
+
+ // View menu
+ view_listener_t::addMenu(new LLViewMouselook(), "View.Mouselook");
+ view_listener_t::addMenu(new LLViewJoystickFlycam(), "View.JoystickFlycam");
+ view_listener_t::addMenu(new LLViewResetView(), "View.ResetView");
+ view_listener_t::addMenu(new LLViewLookAtLastChatter(), "View.LookAtLastChatter");
+ view_listener_t::addMenu(new LLViewShowHoverTips(), "View.ShowHoverTips");
+ view_listener_t::addMenu(new LLViewHighlightTransparent(), "View.HighlightTransparent");
+ view_listener_t::addMenu(new LLViewToggleRenderType(), "View.ToggleRenderType");
+ view_listener_t::addMenu(new LLViewShowHUDAttachments(), "View.ShowHUDAttachments");
+ view_listener_t::addMenu(new LLZoomer(1.2f), "View.ZoomOut");
+ view_listener_t::addMenu(new LLZoomer(1/1.2f), "View.ZoomIn");
+ view_listener_t::addMenu(new LLZoomer(DEFAULT_FIELD_OF_VIEW, false), "View.ZoomDefault");
+ view_listener_t::addMenu(new LLViewDefaultUISize(), "View.DefaultUISize");
+
+ view_listener_t::addMenu(new LLViewEnableMouselook(), "View.EnableMouselook");
+ view_listener_t::addMenu(new LLViewEnableJoystickFlycam(), "View.EnableJoystickFlycam");
+ view_listener_t::addMenu(new LLViewEnableLastChatter(), "View.EnableLastChatter");
+
+ view_listener_t::addMenu(new LLViewCheckJoystickFlycam(), "View.CheckJoystickFlycam");
+ view_listener_t::addMenu(new LLViewCheckShowHoverTips(), "View.CheckShowHoverTips");
+ view_listener_t::addMenu(new LLViewCheckHighlightTransparent(), "View.CheckHighlightTransparent");
+ view_listener_t::addMenu(new LLViewCheckRenderType(), "View.CheckRenderType");
+ view_listener_t::addMenu(new LLViewCheckHUDAttachments(), "View.CheckHUDAttachments");
+
+ // Me > Movement
+ view_listener_t::addMenu(new LLAdvancedAgentFlyingInfo(), "Agent.getFlying");
+
+ // World menu
+ commit.add("World.Chat", boost::bind(&handle_chat, (void*)NULL));
+ view_listener_t::addMenu(new LLWorldAlwaysRun(), "World.AlwaysRun");
+ view_listener_t::addMenu(new LLWorldCreateLandmark(), "World.CreateLandmark");
+ view_listener_t::addMenu(new LLWorldPlaceProfile(), "World.PlaceProfile");
+ view_listener_t::addMenu(new LLWorldSetHomeLocation(), "World.SetHomeLocation");
+ view_listener_t::addMenu(new LLWorldTeleportHome(), "World.TeleportHome");
+ view_listener_t::addMenu(new LLWorldSetAway(), "World.SetAway");
+ view_listener_t::addMenu(new LLWorldSetBusy(), "World.SetBusy");
+
+ view_listener_t::addMenu(new LLWorldEnableCreateLandmark(), "World.EnableCreateLandmark");
+ view_listener_t::addMenu(new LLWorldEnableSetHomeLocation(), "World.EnableSetHomeLocation");
+ view_listener_t::addMenu(new LLWorldEnableTeleportHome(), "World.EnableTeleportHome");
+ view_listener_t::addMenu(new LLWorldEnableBuyLand(), "World.EnableBuyLand");
+
+ view_listener_t::addMenu(new LLWorldCheckAlwaysRun(), "World.CheckAlwaysRun");
+
+ view_listener_t::addMenu(new LLWorldEnvSettings(), "World.EnvSettings");
+ view_listener_t::addMenu(new LLWorldWaterSettings(), "World.WaterSettings");
+ view_listener_t::addMenu(new LLWorldPostProcess(), "World.PostProcess");
+ view_listener_t::addMenu(new LLWorldDayCycle(), "World.DayCycle");
+
+ view_listener_t::addMenu(new LLWorldToggleMovementControls(), "World.Toggle.MovementControls");
+ view_listener_t::addMenu(new LLWorldToggleCameraControls(), "World.Toggle.CameraControls");
+
+ // Tools menu
+ view_listener_t::addMenu(new LLToolsSelectTool(), "Tools.SelectTool");
+ view_listener_t::addMenu(new LLToolsSelectOnlyMyObjects(), "Tools.SelectOnlyMyObjects");
+ view_listener_t::addMenu(new LLToolsSelectOnlyMovableObjects(), "Tools.SelectOnlyMovableObjects");
+ view_listener_t::addMenu(new LLToolsSelectBySurrounding(), "Tools.SelectBySurrounding");
+ view_listener_t::addMenu(new LLToolsShowHiddenSelection(), "Tools.ShowHiddenSelection");
+ view_listener_t::addMenu(new LLToolsShowSelectionLightRadius(), "Tools.ShowSelectionLightRadius");
+ view_listener_t::addMenu(new LLToolsEditLinkedParts(), "Tools.EditLinkedParts");
+ view_listener_t::addMenu(new LLToolsSnapObjectXY(), "Tools.SnapObjectXY");
+ view_listener_t::addMenu(new LLToolsUseSelectionForGrid(), "Tools.UseSelectionForGrid");
+ view_listener_t::addMenu(new LLToolsSelectNextPart(), "Tools.SelectNextPart");
+ commit.add("Tools.Link", boost::bind(&LLSelectMgr::linkObjects, LLSelectMgr::getInstance()));
+ commit.add("Tools.Unlink", boost::bind(&LLSelectMgr::unlinkObjects, LLSelectMgr::getInstance()));
+ view_listener_t::addMenu(new LLToolsStopAllAnimations(), "Tools.StopAllAnimations");
+ view_listener_t::addMenu(new LLToolsReleaseKeys(), "Tools.ReleaseKeys");
+ view_listener_t::addMenu(new LLToolsEnableReleaseKeys(), "Tools.EnableReleaseKeys");
+ commit.add("Tools.LookAtSelection", boost::bind(&handle_look_at_selection, _2));
+ commit.add("Tools.BuyOrTake", boost::bind(&handle_buy_or_take));
+ commit.add("Tools.TakeCopy", boost::bind(&handle_take_copy));
+ view_listener_t::addMenu(new LLToolsSaveToInventory(), "Tools.SaveToInventory");
+ view_listener_t::addMenu(new LLToolsSaveToObjectInventory(), "Tools.SaveToObjectInventory");
+ view_listener_t::addMenu(new LLToolsSelectedScriptAction(), "Tools.SelectedScriptAction");
+
+ view_listener_t::addMenu(new LLToolsEnableToolNotPie(), "Tools.EnableToolNotPie");
+ view_listener_t::addMenu(new LLToolsEnableSelectNextPart(), "Tools.EnableSelectNextPart");
+ enable.add("Tools.EnableLink", boost::bind(&LLSelectMgr::enableLinkObjects, LLSelectMgr::getInstance()));
+ enable.add("Tools.EnableUnlink", boost::bind(&LLSelectMgr::enableUnlinkObjects, LLSelectMgr::getInstance()));
+ view_listener_t::addMenu(new LLToolsEnableBuyOrTake(), "Tools.EnableBuyOrTake");
+ enable.add("Tools.EnableTakeCopy", boost::bind(&enable_object_take_copy));
+ enable.add("Tools.VisibleBuyObject", boost::bind(&tools_visible_buy_object));
+ enable.add("Tools.VisibleTakeObject", boost::bind(&tools_visible_take_object));
+ view_listener_t::addMenu(new LLToolsEnableSaveToInventory(), "Tools.EnableSaveToInventory");
+ view_listener_t::addMenu(new LLToolsEnableSaveToObjectInventory(), "Tools.EnableSaveToObjectInventory");
+
+ // Help menu
+ // most items use the ShowFloater method
+
+ // Advanced menu
+ view_listener_t::addMenu(new LLAdvancedToggleConsole(), "Advanced.ToggleConsole");
+ view_listener_t::addMenu(new LLAdvancedCheckConsole(), "Advanced.CheckConsole");
+ view_listener_t::addMenu(new LLAdvancedDumpInfoToConsole(), "Advanced.DumpInfoToConsole");
+
+ // Advanced > HUD Info
+ view_listener_t::addMenu(new LLAdvancedToggleHUDInfo(), "Advanced.ToggleHUDInfo");
+ view_listener_t::addMenu(new LLAdvancedCheckHUDInfo(), "Advanced.CheckHUDInfo");
+
+ // Advanced Other Settings
+ view_listener_t::addMenu(new LLAdvancedClearGroupCache(), "Advanced.ClearGroupCache");
+
+ // Advanced > Render > Types
+ view_listener_t::addMenu(new LLAdvancedToggleRenderType(), "Advanced.ToggleRenderType");
+ view_listener_t::addMenu(new LLAdvancedCheckRenderType(), "Advanced.CheckRenderType");
+
+ //// Advanced > Render > Features
+ view_listener_t::addMenu(new LLAdvancedToggleFeature(), "Advanced.ToggleFeature");
+ view_listener_t::addMenu(new LLAdvancedCheckFeature(), "Advanced.CheckFeature");
+ // Advanced > Render > Info Displays
+ view_listener_t::addMenu(new LLAdvancedToggleInfoDisplay(), "Advanced.ToggleInfoDisplay");
+ view_listener_t::addMenu(new LLAdvancedCheckInfoDisplay(), "Advanced.CheckInfoDisplay");
+ view_listener_t::addMenu(new LLAdvancedSelectedTextureInfo(), "Advanced.SelectedTextureInfo");
+ view_listener_t::addMenu(new LLAdvancedToggleWireframe(), "Advanced.ToggleWireframe");
+ view_listener_t::addMenu(new LLAdvancedCheckWireframe(), "Advanced.CheckWireframe");
+ // Develop > Render
+ view_listener_t::addMenu(new LLAdvancedToggleTextureAtlas(), "Advanced.ToggleTextureAtlas");
+ view_listener_t::addMenu(new LLAdvancedCheckTextureAtlas(), "Advanced.CheckTextureAtlas");
+ view_listener_t::addMenu(new LLAdvancedEnableObjectObjectOcclusion(), "Advanced.EnableObjectObjectOcclusion");
+ view_listener_t::addMenu(new LLAdvancedEnableRenderFBO(), "Advanced.EnableRenderFBO");
+ view_listener_t::addMenu(new LLAdvancedEnableRenderDeferred(), "Advanced.EnableRenderDeferred");
+ view_listener_t::addMenu(new LLAdvancedEnableRenderDeferredOptions(), "Advanced.EnableRenderDeferredOptions");
+ view_listener_t::addMenu(new LLAdvancedToggleRandomizeFramerate(), "Advanced.ToggleRandomizeFramerate");
+ view_listener_t::addMenu(new LLAdvancedCheckRandomizeFramerate(), "Advanced.CheckRandomizeFramerate");
+ view_listener_t::addMenu(new LLAdvancedTogglePeriodicSlowFrame(), "Advanced.TogglePeriodicSlowFrame");
+ view_listener_t::addMenu(new LLAdvancedCheckPeriodicSlowFrame(), "Advanced.CheckPeriodicSlowFrame");
+ view_listener_t::addMenu(new LLAdvancedVectorizePerfTest(), "Advanced.VectorizePerfTest");
+ view_listener_t::addMenu(new LLAdvancedToggleFrameTest(), "Advanced.ToggleFrameTest");
+ view_listener_t::addMenu(new LLAdvancedCheckFrameTest(), "Advanced.CheckFrameTest");
+ view_listener_t::addMenu(new LLAdvancedHandleAttachedLightParticles(), "Advanced.HandleAttachedLightParticles");
+ view_listener_t::addMenu(new LLAdvancedCheckRenderShadowOption(), "Advanced.CheckRenderShadowOption");
+ view_listener_t::addMenu(new LLAdvancedClickRenderShadowOption(), "Advanced.ClickRenderShadowOption");
+
+
+ #ifdef TOGGLE_HACKED_GODLIKE_VIEWER
+ view_listener_t::addMenu(new LLAdvancedHandleToggleHackedGodmode(), "Advanced.HandleToggleHackedGodmode");
+ view_listener_t::addMenu(new LLAdvancedCheckToggleHackedGodmode(), "Advanced.CheckToggleHackedGodmode");
+ view_listener_t::addMenu(new LLAdvancedEnableToggleHackedGodmode(), "Advanced.EnableToggleHackedGodmode");
+ #endif
+
+ // Advanced > World
+ view_listener_t::addMenu(new LLAdvancedDumpScriptedCamera(), "Advanced.DumpScriptedCamera");
+ view_listener_t::addMenu(new LLAdvancedDumpRegionObjectCache(), "Advanced.DumpRegionObjectCache");
+
+ // Advanced > UI
+ commit.add("Advanced.WebBrowserTest", boost::bind(&handle_web_browser_test, _2)); // sigh! this one opens the MEDIA browser
+ commit.add("Advanced.WebContentTest", boost::bind(&handle_web_content_test, _2)); // this one opens the Web Content floater
+ view_listener_t::addMenu(new LLAdvancedBuyCurrencyTest(), "Advanced.BuyCurrencyTest");
+ view_listener_t::addMenu(new LLAdvancedDumpSelectMgr(), "Advanced.DumpSelectMgr");
+ view_listener_t::addMenu(new LLAdvancedDumpInventory(), "Advanced.DumpInventory");
+ commit.add("Advanced.DumpTimers", boost::bind(&handle_dump_timers) );
+ commit.add("Advanced.DumpFocusHolder", boost::bind(&handle_dump_focus) );
+ view_listener_t::addMenu(new LLAdvancedPrintSelectedObjectInfo(), "Advanced.PrintSelectedObjectInfo");
+ view_listener_t::addMenu(new LLAdvancedPrintAgentInfo(), "Advanced.PrintAgentInfo");
+ view_listener_t::addMenu(new LLAdvancedPrintTextureMemoryStats(), "Advanced.PrintTextureMemoryStats");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugClicks(), "Advanced.ToggleDebugClicks");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugClicks(), "Advanced.CheckDebugClicks");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugViews(), "Advanced.CheckDebugViews");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugViews(), "Advanced.ToggleDebugViews");
+ view_listener_t::addMenu(new LLAdvancedToggleXUINameTooltips(), "Advanced.ToggleXUINameTooltips");
+ view_listener_t::addMenu(new LLAdvancedCheckXUINameTooltips(), "Advanced.CheckXUINameTooltips");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugMouseEvents(), "Advanced.ToggleDebugMouseEvents");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugMouseEvents(), "Advanced.CheckDebugMouseEvents");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugKeys(), "Advanced.ToggleDebugKeys");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugKeys(), "Advanced.CheckDebugKeys");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugWindowProc(), "Advanced.ToggleDebugWindowProc");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugWindowProc(), "Advanced.CheckDebugWindowProc");
+ commit.add("Advanced.ShowSideTray", boost::bind(&handle_show_side_tray));
+
+ // Advanced > XUI
+ commit.add("Advanced.ReloadColorSettings", boost::bind(&LLUIColorTable::loadFromSettings, LLUIColorTable::getInstance()));
+ view_listener_t::addMenu(new LLAdvancedToggleXUINames(), "Advanced.ToggleXUINames");
+ view_listener_t::addMenu(new LLAdvancedCheckXUINames(), "Advanced.CheckXUINames");
+ view_listener_t::addMenu(new LLAdvancedSendTestIms(), "Advanced.SendTestIMs");
+ commit.add("Advanced.FlushNameCaches", boost::bind(&handle_flush_name_caches));
+
+ // Advanced > Character > Grab Baked Texture
+ view_listener_t::addMenu(new LLAdvancedGrabBakedTexture(), "Advanced.GrabBakedTexture");
+ view_listener_t::addMenu(new LLAdvancedEnableGrabBakedTexture(), "Advanced.EnableGrabBakedTexture");
+
+ // Advanced > Character > Character Tests
+ view_listener_t::addMenu(new LLAdvancedAppearanceToXML(), "Advanced.AppearanceToXML");
+ view_listener_t::addMenu(new LLAdvancedToggleCharacterGeometry(), "Advanced.ToggleCharacterGeometry");
+
+ view_listener_t::addMenu(new LLAdvancedTestMale(), "Advanced.TestMale");
+ view_listener_t::addMenu(new LLAdvancedTestFemale(), "Advanced.TestFemale");
+ view_listener_t::addMenu(new LLAdvancedTogglePG(), "Advanced.TogglePG");
+
+ // Advanced > Character (toplevel)
+ view_listener_t::addMenu(new LLAdvancedForceParamsToDefault(), "Advanced.ForceParamsToDefault");
+ view_listener_t::addMenu(new LLAdvancedReloadVertexShader(), "Advanced.ReloadVertexShader");
+ view_listener_t::addMenu(new LLAdvancedToggleAnimationInfo(), "Advanced.ToggleAnimationInfo");
+ view_listener_t::addMenu(new LLAdvancedCheckAnimationInfo(), "Advanced.CheckAnimationInfo");
+ view_listener_t::addMenu(new LLAdvancedToggleShowLookAt(), "Advanced.ToggleShowLookAt");
+ view_listener_t::addMenu(new LLAdvancedCheckShowLookAt(), "Advanced.CheckShowLookAt");
+ view_listener_t::addMenu(new LLAdvancedToggleShowPointAt(), "Advanced.ToggleShowPointAt");
+ view_listener_t::addMenu(new LLAdvancedCheckShowPointAt(), "Advanced.CheckShowPointAt");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugJointUpdates(), "Advanced.ToggleDebugJointUpdates");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugJointUpdates(), "Advanced.CheckDebugJointUpdates");
+ view_listener_t::addMenu(new LLAdvancedToggleDisableLOD(), "Advanced.ToggleDisableLOD");
+ view_listener_t::addMenu(new LLAdvancedCheckDisableLOD(), "Advanced.CheckDisableLOD");
+ view_listener_t::addMenu(new LLAdvancedToggleDebugCharacterVis(), "Advanced.ToggleDebugCharacterVis");
+ view_listener_t::addMenu(new LLAdvancedCheckDebugCharacterVis(), "Advanced.CheckDebugCharacterVis");
+ view_listener_t::addMenu(new LLAdvancedDumpAttachments(), "Advanced.DumpAttachments");
+ view_listener_t::addMenu(new LLAdvancedRebakeTextures(), "Advanced.RebakeTextures");
+ view_listener_t::addMenu(new LLAdvancedDebugAvatarTextures(), "Advanced.DebugAvatarTextures");
+ view_listener_t::addMenu(new LLAdvancedDumpAvatarLocalTextures(), "Advanced.DumpAvatarLocalTextures");
+ // Advanced > Network
+ view_listener_t::addMenu(new LLAdvancedEnableMessageLog(), "Advanced.EnableMessageLog");
+ view_listener_t::addMenu(new LLAdvancedDisableMessageLog(), "Advanced.DisableMessageLog");
+ view_listener_t::addMenu(new LLAdvancedDropPacket(), "Advanced.DropPacket");
+
+ // Advanced > Recorder
+ view_listener_t::addMenu(new LLAdvancedAgentPilot(), "Advanced.AgentPilot");
+ view_listener_t::addMenu(new LLAdvancedToggleAgentPilotLoop(), "Advanced.ToggleAgentPilotLoop");
+ view_listener_t::addMenu(new LLAdvancedCheckAgentPilotLoop(), "Advanced.CheckAgentPilotLoop");
+
+ // Advanced > Debugging
+ view_listener_t::addMenu(new LLAdvancedForceErrorBreakpoint(), "Advanced.ForceErrorBreakpoint");
+ view_listener_t::addMenu(new LLAdvancedForceErrorLlerror(), "Advanced.ForceErrorLlerror");
+ view_listener_t::addMenu(new LLAdvancedForceErrorBadMemoryAccess(), "Advanced.ForceErrorBadMemoryAccess");
+ view_listener_t::addMenu(new LLAdvancedForceErrorInfiniteLoop(), "Advanced.ForceErrorInfiniteLoop");
+ view_listener_t::addMenu(new LLAdvancedForceErrorSoftwareException(), "Advanced.ForceErrorSoftwareException");
+ view_listener_t::addMenu(new LLAdvancedForceErrorDriverCrash(), "Advanced.ForceErrorDriverCrash");
+ view_listener_t::addMenu(new LLAdvancedForceErrorDisconnectViewer(), "Advanced.ForceErrorDisconnectViewer");
+
+ // Advanced (toplevel)
+ view_listener_t::addMenu(new LLAdvancedToggleShowObjectUpdates(), "Advanced.ToggleShowObjectUpdates");
+ view_listener_t::addMenu(new LLAdvancedCheckShowObjectUpdates(), "Advanced.CheckShowObjectUpdates");
+ view_listener_t::addMenu(new LLAdvancedCompressImage(), "Advanced.CompressImage");
+ view_listener_t::addMenu(new LLAdvancedShowDebugSettings(), "Advanced.ShowDebugSettings");
+ view_listener_t::addMenu(new LLAdvancedEnableViewAdminOptions(), "Advanced.EnableViewAdminOptions");
+ view_listener_t::addMenu(new LLAdvancedToggleViewAdminOptions(), "Advanced.ToggleViewAdminOptions");
+ view_listener_t::addMenu(new LLAdvancedCheckViewAdminOptions(), "Advanced.CheckViewAdminOptions");
+ view_listener_t::addMenu(new LLAdvancedRequestAdminStatus(), "Advanced.RequestAdminStatus");
+ view_listener_t::addMenu(new LLAdvancedLeaveAdminStatus(), "Advanced.LeaveAdminStatus");
+
+
+ // Admin >Object
+ view_listener_t::addMenu(new LLAdminForceTakeCopy(), "Admin.ForceTakeCopy");
+ view_listener_t::addMenu(new LLAdminHandleObjectOwnerSelf(), "Admin.HandleObjectOwnerSelf");
+ view_listener_t::addMenu(new LLAdminHandleObjectOwnerPermissive(), "Admin.HandleObjectOwnerPermissive");
+ view_listener_t::addMenu(new LLAdminHandleForceDelete(), "Admin.HandleForceDelete");
+ view_listener_t::addMenu(new LLAdminHandleObjectLock(), "Admin.HandleObjectLock");
+ view_listener_t::addMenu(new LLAdminHandleObjectAssetIDs(), "Admin.HandleObjectAssetIDs");
+
+ // Admin >Parcel
+ view_listener_t::addMenu(new LLAdminHandleForceParcelOwnerToMe(), "Admin.HandleForceParcelOwnerToMe");
+ view_listener_t::addMenu(new LLAdminHandleForceParcelToContent(), "Admin.HandleForceParcelToContent");
+ view_listener_t::addMenu(new LLAdminHandleClaimPublicLand(), "Admin.HandleClaimPublicLand");
+
+ // Admin >Region
+ view_listener_t::addMenu(new LLAdminHandleRegionDumpTempAssetData(), "Admin.HandleRegionDumpTempAssetData");
+ // Admin top level
+ view_listener_t::addMenu(new LLAdminOnSaveState(), "Admin.OnSaveState");
+
+ // Self context menu
+ view_listener_t::addMenu(new LLSelfStandUp(), "Self.StandUp");
+ enable.add("Self.EnableStandUp", boost::bind(&enable_standup_self));
+ view_listener_t::addMenu(new LLSelfSitDown(), "Self.SitDown");
+ enable.add("Self.EnableSitDown", boost::bind(&enable_sitdown_self));
+ view_listener_t::addMenu(new LLSelfRemoveAllAttachments(), "Self.RemoveAllAttachments");
+
+ view_listener_t::addMenu(new LLSelfEnableRemoveAllAttachments(), "Self.EnableRemoveAllAttachments");
+
+ // we don't use boost::bind directly to delay side tray construction
+ view_listener_t::addMenu( new LLTogglePanelPeopleTab(), "SideTray.PanelPeopleTab");
+
+ // Avatar pie menu
+ view_listener_t::addMenu(new LLObjectMute(), "Avatar.Mute");
+ view_listener_t::addMenu(new LLAvatarAddFriend(), "Avatar.AddFriend");
+ view_listener_t::addMenu(new LLAvatarAddContact(), "Avatar.AddContact");
+ commit.add("Avatar.Freeze", boost::bind(&handle_avatar_freeze, LLSD()));
+ view_listener_t::addMenu(new LLAvatarDebug(), "Avatar.Debug");
+ view_listener_t::addMenu(new LLAvatarVisibleDebug(), "Avatar.VisibleDebug");
+ view_listener_t::addMenu(new LLAvatarInviteToGroup(), "Avatar.InviteToGroup");
+ commit.add("Avatar.Eject", boost::bind(&handle_avatar_eject, LLSD()));
+ commit.add("Avatar.ShowInspector", boost::bind(&handle_avatar_show_inspector));
+ view_listener_t::addMenu(new LLAvatarSendIM(), "Avatar.SendIM");
+ view_listener_t::addMenu(new LLAvatarCall(), "Avatar.Call");
+ enable.add("Avatar.EnableCall", boost::bind(&LLAvatarActions::canCall));
+ view_listener_t::addMenu(new LLAvatarReportAbuse(), "Avatar.ReportAbuse");
+
+ view_listener_t::addMenu(new LLAvatarEnableAddFriend(), "Avatar.EnableAddFriend");
+ enable.add("Avatar.EnableFreezeEject", boost::bind(&enable_freeze_eject, _2));
+
+ // Object pie menu
+ view_listener_t::addMenu(new LLObjectBuild(), "Object.Build");
+ commit.add("Object.Touch", boost::bind(&handle_object_touch));
+ commit.add("Object.SitOrStand", boost::bind(&handle_object_sit_or_stand));
+ commit.add("Object.Delete", boost::bind(&handle_object_delete));
+ view_listener_t::addMenu(new LLObjectAttachToAvatar(true), "Object.AttachToAvatar");
+ view_listener_t::addMenu(new LLObjectAttachToAvatar(false), "Object.AttachAddToAvatar");
+ view_listener_t::addMenu(new LLObjectReturn(), "Object.Return");
+ view_listener_t::addMenu(new LLObjectReportAbuse(), "Object.ReportAbuse");
+ view_listener_t::addMenu(new LLObjectMute(), "Object.Mute");
+
+ enable.add("Object.VisibleTake", boost::bind(&visible_take_object));
+ enable.add("Object.VisibleBuy", boost::bind(&visible_buy_object));
+
+ commit.add("Object.Buy", boost::bind(&handle_buy));
+ commit.add("Object.Edit", boost::bind(&handle_object_edit));
+ commit.add("Object.Inspect", boost::bind(&handle_object_inspect));
+ commit.add("Object.Open", boost::bind(&handle_object_open));
+ commit.add("Object.Take", boost::bind(&handle_take));
+ commit.add("Object.ShowInspector", boost::bind(&handle_object_show_inspector));
+ enable.add("Object.EnableOpen", boost::bind(&enable_object_open));
+ enable.add("Object.EnableTouch", boost::bind(&enable_object_touch, _1));
+ enable.add("Object.EnableDelete", boost::bind(&enable_object_delete));
+ enable.add("Object.EnableWear", boost::bind(&object_selected_and_point_valid));
+
+ enable.add("Object.EnableStandUp", boost::bind(&enable_object_stand_up));
+ enable.add("Object.EnableSit", boost::bind(&enable_object_sit, _1));
+
+ view_listener_t::addMenu(new LLObjectEnableReturn(), "Object.EnableReturn");
+ view_listener_t::addMenu(new LLObjectEnableReportAbuse(), "Object.EnableReportAbuse");
+
+ enable.add("Avatar.EnableMute", boost::bind(&enable_object_mute));
+ enable.add("Object.EnableMute", boost::bind(&enable_object_mute));
+ enable.add("Object.EnableBuy", boost::bind(&enable_buy_object));
+ commit.add("Object.ZoomIn", boost::bind(&handle_look_at_selection, "zoom"));
+
+ // Attachment pie menu
+ enable.add("Attachment.Label", boost::bind(&onEnableAttachmentLabel, _1, _2));
+ view_listener_t::addMenu(new LLAttachmentDrop(), "Attachment.Drop");
+ view_listener_t::addMenu(new LLAttachmentDetachFromPoint(), "Attachment.DetachFromPoint");
+ view_listener_t::addMenu(new LLAttachmentDetach(), "Attachment.Detach");
+ view_listener_t::addMenu(new LLAttachmentPointFilled(), "Attachment.PointFilled");
+ view_listener_t::addMenu(new LLAttachmentEnableDrop(), "Attachment.EnableDrop");
+ view_listener_t::addMenu(new LLAttachmentEnableDetach(), "Attachment.EnableDetach");
+
+ // Land pie menu
+ view_listener_t::addMenu(new LLLandBuild(), "Land.Build");
+ view_listener_t::addMenu(new LLLandSit(), "Land.Sit");
+ view_listener_t::addMenu(new LLLandBuyPass(), "Land.BuyPass");
+ view_listener_t::addMenu(new LLLandEdit(), "Land.Edit");
+
+ view_listener_t::addMenu(new LLLandEnableBuyPass(), "Land.EnableBuyPass");
+ commit.add("Land.Buy", boost::bind(&handle_buy_land));
+
+ // Generic actions
+ commit.add("ReportAbuse", boost::bind(&handle_report_abuse));
+ commit.add("BuyCurrency", boost::bind(&handle_buy_currency));
+ view_listener_t::addMenu(new LLShowHelp(), "ShowHelp");
+ view_listener_t::addMenu(new LLToggleHelp(), "ToggleHelp");
+ view_listener_t::addMenu(new LLPromptShowURL(), "PromptShowURL");
+ view_listener_t::addMenu(new LLShowAgentProfile(), "ShowAgentProfile");
+ view_listener_t::addMenu(new LLToggleAgentProfile(), "ToggleAgentProfile");
+ view_listener_t::addMenu(new LLToggleControl(), "ToggleControl");
+ view_listener_t::addMenu(new LLCheckControl(), "CheckControl");
+ view_listener_t::addMenu(new LLGoToObject(), "GoToObject");
+ commit.add("PayObject", boost::bind(&handle_give_money_dialog));
+
+ enable.add("EnablePayObject", boost::bind(&enable_pay_object));
+ enable.add("EnablePayAvatar", boost::bind(&enable_pay_avatar));
+ enable.add("EnableEdit", boost::bind(&enable_object_edit));
+ enable.add("VisibleBuild", boost::bind(&enable_object_build));
+
+ view_listener_t::addMenu(new LLFloaterVisible(), "FloaterVisible");
+ view_listener_t::addMenu(new LLShowSidetrayPanel(), "ShowSidetrayPanel");
+ view_listener_t::addMenu(new LLSidetrayPanelVisible(), "SidetrayPanelVisible");
+ view_listener_t::addMenu(new LLSomethingSelected(), "SomethingSelected");
+ view_listener_t::addMenu(new LLSomethingSelectedNoHUD(), "SomethingSelectedNoHUD");
+ view_listener_t::addMenu(new LLEditableSelected(), "EditableSelected");
+ view_listener_t::addMenu(new LLEditableSelectedMono(), "EditableSelectedMono");
+
+ view_listener_t::addMenu(new LLToggleUIHints(), "ToggleUIHints");
+
+ commit.add("Destination.show", boost::bind(&toggle_destination_and_avatar_picker, 0));
+ commit.add("Avatar.show", boost::bind(&toggle_destination_and_avatar_picker, 1));
+}
diff --git a/indra/newview/llviewermenu.h b/indra/newview/llviewermenu.h
index 87cb4efbc4..b4e239b0cd 100644
--- a/indra/newview/llviewermenu.h
+++ b/indra/newview/llviewermenu.h
@@ -126,6 +126,8 @@ bool enable_pay_object();
bool enable_buy_object();
bool handle_go_to();
+void toggle_destination_and_avatar_picker(const LLSD& show);
+
// Export to XML or Collada
void handle_export_selected( void * );
diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp
index 947408f125..8b52d478e6 100644
--- a/indra/newview/llviewermessage.cpp
+++ b/indra/newview/llviewermessage.cpp
@@ -1199,7 +1199,6 @@ void open_inventory_offer(const uuid_vec_t& objects, const std::string& from_nam
// Highlight item
const BOOL auto_open =
gSavedSettings.getBOOL("ShowInInventory") && // don't open if showininventory is false
- !(asset_type == LLAssetType::AT_CALLINGCARD) && // don't open if it's a calling card
!from_name.empty(); // don't open if it's not from anyone.
LLInventoryPanel *active_panel = LLInventoryPanel::getActiveInventoryPanel(auto_open);
if(active_panel)
@@ -1463,15 +1462,18 @@ bool LLOfferInfo::inventory_offer_callback(const LLSD& notification, const LLSD&
// This is an offer from an agent. In this case, the back
// end has already copied the items into your inventory,
// so we can fetch it out of our inventory.
- LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string);
- open_agent_offer->startFetch();
- if(catp || (itemp && itemp->isFinished()))
+ if (gSavedSettings.getBOOL("ShowOfferedInventory"))
{
- open_agent_offer->done();
- }
- else
- {
- opener = open_agent_offer;
+ LLOpenAgentOffer* open_agent_offer = new LLOpenAgentOffer(mObjectID, from_string);
+ open_agent_offer->startFetch();
+ if(catp || (itemp && itemp->isFinished()))
+ {
+ open_agent_offer->done();
+ }
+ else
+ {
+ opener = open_agent_offer;
+ }
}
}
break;
@@ -1715,15 +1717,18 @@ bool LLOfferInfo::inventory_task_offer_callback(const LLSD& notification, const
msg->addBinaryDataFast(_PREHASH_BinaryBucket, EMPTY_BINARY_BUCKET, EMPTY_BINARY_BUCKET_SIZE);
// send the message
msg->sendReliable(mHost);
+
+ if (gSavedSettings.getBOOL("LogInventoryDecline"))
{
LLStringUtil::format_map_t log_message_args;
log_message_args["DESC"] = mDesc;
log_message_args["NAME"] = mFromName;
log_message = LLTrans::getString("InvOfferDecline", log_message_args);
+
+ LLSD args;
+ args["MESSAGE"] = log_message;
+ LLNotificationsUtil::add("SystemMessage", args);
}
- LLSD args;
- args["MESSAGE"] = log_message;
- LLNotificationsUtil::add("SystemMessage", args);
if (busy && (!mFromGroup && !mFromObject))
{
diff --git a/indra/newview/llviewernetwork.cpp b/indra/newview/llviewernetwork.cpp
index b91e407c6d..a59afdc28a 100644
--- a/indra/newview/llviewernetwork.cpp
+++ b/indra/newview/llviewernetwork.cpp
@@ -31,6 +31,7 @@
#include "llviewercontrol.h"
#include "llsdserialize.h"
#include "llsecapi.h"
+#include "lltrans.h"
#include "llweb.h"
@@ -504,7 +505,8 @@ void LLGridManager::setGridChoice(const std::string& grid)
addGrid(grid_data);
}
mGrid = grid;
- gSavedSettings.setString("CurrentGrid", grid);
+ gSavedSettings.setString("CurrentGrid", grid);
+
updateIsInProductionGrid();
}
diff --git a/indra/newview/llviewerobjectlist.cpp b/indra/newview/llviewerobjectlist.cpp
index 81479e8b49..979d91cfcb 100644
--- a/indra/newview/llviewerobjectlist.cpp
+++ b/indra/newview/llviewerobjectlist.cpp
@@ -1180,6 +1180,7 @@ void LLViewerObjectList::clearAllMapObjectsInRegion(LLViewerRegion* regionp)
}
}
+
void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap)
{
LLColor4 above_water_color = LLUIColorTable::instance().getColor( "NetMapOtherOwnAboveWater" );
@@ -1199,7 +1200,6 @@ void LLViewerObjectList::renderObjectsForMap(LLNetMap &netmap)
{
LLViewerObject* objectp = *iter;
- //llassert_always(!objectp->isDead());
if(objectp->isDead())//some dead objects somehow not cleaned.
{
continue ;
diff --git a/indra/newview/llviewerregion.cpp b/indra/newview/llviewerregion.cpp
index 23b7b921b8..e1d3e8a0b3 100644
--- a/indra/newview/llviewerregion.cpp
+++ b/indra/newview/llviewerregion.cpp
@@ -67,6 +67,7 @@
#include "llworld.h"
#include "llspatialpartition.h"
#include "stringize.h"
+#include "llviewercontrol.h"
#ifdef LL_WINDOWS
#pragma warning(disable:4355)
@@ -1387,10 +1388,15 @@ void LLViewerRegion::setSeedCapability(const std::string& url)
capabilityNames.append("EventQueueGet");
capabilityNames.append("ObjectMedia");
capabilityNames.append("ObjectMediaNavigate");
- capabilityNames.append("FetchLib2");
- capabilityNames.append("FetchLibDescendents2");
- capabilityNames.append("FetchInventory2");
- capabilityNames.append("FetchInventoryDescendents2");
+
+ if (gSavedSettings.getBOOL("UseHTTPInventory"))
+ {
+ capabilityNames.append("FetchLib2");
+ capabilityNames.append("FetchLibDescendents2");
+ capabilityNames.append("FetchInventory2");
+ capabilityNames.append("FetchInventoryDescendents2");
+ }
+
capabilityNames.append("GetDisplayNames");
capabilityNames.append("GetTexture");
capabilityNames.append("GroupProposalBallot");
diff --git a/indra/newview/llviewerstats.cpp b/indra/newview/llviewerstats.cpp
index 546ee9a334..874519a59f 100644
--- a/indra/newview/llviewerstats.cpp
+++ b/indra/newview/llviewerstats.cpp
@@ -852,6 +852,8 @@ void send_stats()
body["DisplayNamesEnabled"] = gSavedSettings.getBOOL("UseDisplayNames");
body["DisplayNamesShowUsername"] = gSavedSettings.getBOOL("NameTagShowUsernames");
+ body["MinimalSkin"] = !gSavedSettings.getString("SessionSettingsFile").empty();
+
LLViewerStats::getInstance()->addToMessage(body);
LLHTTPClient::post(url, body, new ViewerStatsResponder());
}
diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp
index 62944a22e7..2843e4e9ae 100644
--- a/indra/newview/llviewerwindow.cpp
+++ b/indra/newview/llviewerwindow.cpp
@@ -1,5036 +1,5034 @@
-/**
- * @file llviewerwindow.cpp
- * @brief Implementation of the LLViewerWindow class.
- *
- * $LicenseInfo:firstyear=2001&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "llviewerwindow.h"
-
-#if LL_WINDOWS
-#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
-#endif
-
-// system library includes
-#include <stdio.h>
-#include <iostream>
-#include <fstream>
-#include <algorithm>
-
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "llfloaterreg.h"
-#include "llpanellogin.h"
-#include "llviewerkeyboard.h"
-#include "llviewermenu.h"
-
-#include "llviewquery.h"
-#include "llxmltree.h"
-#include "llslurl.h"
-//#include "llviewercamera.h"
-#include "llrender.h"
-
-#include "llvoiceclient.h" // for push-to-talk button handling
-
-//
-// TODO: Many of these includes are unnecessary. Remove them.
-//
-
-// linden library includes
-#include "llaudioengine.h" // mute on minimize
-#include "indra_constants.h"
-#include "llassetstorage.h"
-#include "llerrorcontrol.h"
-#include "llfontgl.h"
-#include "llmousehandler.h"
-#include "llrect.h"
-#include "llsky.h"
-#include "llstring.h"
-#include "llui.h"
-#include "lluuid.h"
-#include "llview.h"
-#include "llxfermanager.h"
-#include "message.h"
-#include "object_flags.h"
-#include "lltimer.h"
-#include "timing.h"
-#include "llviewermenu.h"
-#include "lltooltip.h"
-#include "llmediaentry.h"
-#include "llurldispatcher.h"
-
-// newview includes
-#include "llagent.h"
-#include "llbox.h"
-#include "llconsole.h"
-#include "llviewercontrol.h"
-#include "llcylinder.h"
-#include "lldebugview.h"
-#include "lldir.h"
-#include "lldrawable.h"
-#include "lldrawpoolalpha.h"
-#include "lldrawpoolbump.h"
-#include "lldrawpoolwater.h"
-#include "llmaniptranslate.h"
-#include "llface.h"
-#include "llfeaturemanager.h"
-#include "llfilepicker.h"
-#include "llfirstuse.h"
-#include "llfloater.h"
-#include "llfloaterbuildoptions.h"
-#include "llfloaterbuyland.h"
-#include "llfloatercamera.h"
-#include "llfloaterland.h"
-#include "llfloaterinspect.h"
-#include "llfloatermap.h"
-#include "llfloaternamedesc.h"
-#include "llfloaterpreference.h"
-#include "llfloatersnapshot.h"
-#include "llfloatertools.h"
-#include "llfloaterworldmap.h"
-#include "llfocusmgr.h"
-#include "llfontfreetype.h"
-#include "llgesturemgr.h"
-#include "llglheaders.h"
-#include "lltooltip.h"
-#include "llhudmanager.h"
-#include "llhudobject.h"
-#include "llhudview.h"
-#include "llimagebmp.h"
-#include "llimagej2c.h"
-#include "llimageworker.h"
-#include "llkeyboard.h"
-#include "lllineeditor.h"
-#include "llmenugl.h"
-#include "llmodaldialog.h"
-#include "llmorphview.h"
-#include "llmoveview.h"
-#include "llnavigationbar.h"
-#include "llpopupview.h"
-#include "llpreviewtexture.h"
-#include "llprogressview.h"
-#include "llresmgr.h"
-#include "llsidetray.h"
-#include "llselectmgr.h"
-#include "llrootview.h"
-#include "llrendersphere.h"
-#include "llstartup.h"
-#include "llstatusbar.h"
-#include "llstatview.h"
-#include "llsurface.h"
-#include "llsurfacepatch.h"
-#include "lltexlayer.h"
-#include "lltextbox.h"
-#include "lltexturecache.h"
-#include "lltexturefetch.h"
-#include "lltextureview.h"
-#include "lltool.h"
-#include "lltoolcomp.h"
-#include "lltooldraganddrop.h"
-#include "lltoolface.h"
-#include "lltoolfocus.h"
-#include "lltoolgrab.h"
-#include "lltoolmgr.h"
-#include "lltoolmorph.h"
-#include "lltoolpie.h"
-#include "lltoolselectland.h"
-#include "lltrans.h"
-#include "lluictrlfactory.h"
-#include "llurldispatcher.h" // SLURL from other app instance
-#include "llversioninfo.h"
-#include "llvieweraudio.h"
-#include "llviewercamera.h"
-#include "llviewergesture.h"
-#include "llviewertexturelist.h"
-#include "llviewerinventory.h"
-#include "llviewerkeyboard.h"
-#include "llviewermedia.h"
-#include "llviewermediafocus.h"
-#include "llviewermenu.h"
-#include "llviewermessage.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h"
-#include "llviewershadermgr.h"
-#include "llviewerstats.h"
-#include "llvoavatarself.h"
-#include "llvovolume.h"
-#include "llworld.h"
-#include "llworldmapview.h"
-#include "pipeline.h"
-#include "llappviewer.h"
-#include "llviewerdisplay.h"
-#include "llspatialpartition.h"
-#include "llviewerjoystick.h"
-#include "llviewernetwork.h"
-#include "llpostprocess.h"
-#include "llbottomtray.h"
-#include "llnearbychatbar.h"
-#include "llagentui.h"
-#include "llwearablelist.h"
-
-#include "llnotifications.h"
-#include "llnotificationsutil.h"
-#include "llnotificationmanager.h"
-
-#include "llfloaternotificationsconsole.h"
-
-#include "llnearbychat.h"
-#include "llviewerwindowlistener.h"
-#include "llpaneltopinfobar.h"
-
-#if LL_WINDOWS
-#include <tchar.h> // For Unicode conversion methods
-#endif
-
-//
-// Globals
-//
-void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
-
-extern BOOL gDebugClicks;
-extern BOOL gDisplaySwapBuffers;
-extern BOOL gDepthDirty;
-extern BOOL gResizeScreenTexture;
-
-LLViewerWindow *gViewerWindow = NULL;
-
-LLFrameTimer gAwayTimer;
-LLFrameTimer gAwayTriggerTimer;
-
-BOOL gShowOverlayTitle = FALSE;
-
-LLViewerObject* gDebugRaycastObject = NULL;
-LLVector3 gDebugRaycastIntersection;
-LLVector2 gDebugRaycastTexCoord;
-LLVector3 gDebugRaycastNormal;
-LLVector3 gDebugRaycastBinormal;
-S32 gDebugRaycastFaceHit;
-
-// HUD display lines in lower right
-BOOL gDisplayWindInfo = FALSE;
-BOOL gDisplayCameraPos = FALSE;
-BOOL gDisplayFOV = FALSE;
-BOOL gDisplayBadge = FALSE;
-
-S32 CHAT_BAR_HEIGHT = 28;
-S32 OVERLAY_BAR_HEIGHT = 20;
-
-const U8 NO_FACE = 255;
-BOOL gQuietSnapshot = FALSE;
-
-const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before coming back
-const F32 MAX_FAST_FRAME_TIME = 0.5f;
-const F32 FAST_FRAME_INCREMENT = 0.1f;
-
-const F32 MIN_DISPLAY_SCALE = 0.75f;
-
-std::string LLViewerWindow::sSnapshotBaseName;
-std::string LLViewerWindow::sSnapshotDir;
-
-std::string LLViewerWindow::sMovieBaseName;
-
-class RecordToChatConsole : public LLError::Recorder, public LLSingleton<RecordToChatConsole>
-{
-public:
- virtual void recordMessage(LLError::ELevel level,
- const std::string& message)
- {
- //FIXME: this is NOT thread safe, and will do bad things when a warning is issued from a non-UI thread
-
- // only log warnings to chat console
- //if (level == LLError::LEVEL_WARN)
- //{
- //LLFloaterChat* chat_floater = LLFloaterReg::findTypedInstance<LLFloaterChat>("chat");
- //if (chat_floater && gSavedSettings.getBOOL("WarningsAsChat"))
- //{
- // LLChat chat;
- // chat.mText = message;
- // chat.mSourceType = CHAT_SOURCE_SYSTEM;
-
- // chat_floater->addChat(chat, FALSE, FALSE);
- //}
- //}
- }
-};
-
-////////////////////////////////////////////////////////////////////////////
-//
-// LLDebugText
-//
-
-class LLDebugText
-{
-private:
- struct Line
- {
- Line(const std::string& in_text, S32 in_x, S32 in_y) : text(in_text), x(in_x), y(in_y) {}
- std::string text;
- S32 x,y;
- };
-
- LLViewerWindow *mWindow;
-
- typedef std::vector<Line> line_list_t;
- line_list_t mLineList;
- LLColor4 mTextColor;
-
- void addText(S32 x, S32 y, const std::string &text)
- {
- mLineList.push_back(Line(text, x, y));
- }
-
- void clearText() { mLineList.clear(); }
-
-public:
- LLDebugText(LLViewerWindow* window) : mWindow(window) {}
-
- void update()
- {
- static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
-
- std::string wind_vel_text;
- std::string wind_vector_text;
- std::string rwind_vel_text;
- std::string rwind_vector_text;
- std::string audio_text;
-
- static const std::string beacon_particle = LLTrans::getString("BeaconParticle");
- static const std::string beacon_physical = LLTrans::getString("BeaconPhysical");
- static const std::string beacon_scripted = LLTrans::getString("BeaconScripted");
- static const std::string beacon_scripted_touch = LLTrans::getString("BeaconScriptedTouch");
- static const std::string beacon_sound = LLTrans::getString("BeaconSound");
- static const std::string beacon_media = LLTrans::getString("BeaconMedia");
- static const std::string particle_hiding = LLTrans::getString("ParticleHiding");
-
- // Draw the statistics in a light gray
- // and in a thin font
- mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f );
-
- // Draw stuff growing up from right lower corner of screen
- U32 xpos = mWindow->getWindowWidthScaled() - 350;
- U32 ypos = 64;
- const U32 y_inc = 20;
-
- clearText();
-
- if (gSavedSettings.getBOOL("DebugShowTime"))
- {
- const U32 y_inc2 = 15;
- for (std::map<S32,LLFrameTimer>::reverse_iterator iter = gDebugTimers.rbegin();
- iter != gDebugTimers.rend(); ++iter)
- {
- S32 idx = iter->first;
- LLFrameTimer& timer = iter->second;
- F32 time = timer.getElapsedTimeF32();
- S32 hours = (S32)(time / (60*60));
- S32 mins = (S32)((time - hours*(60*60)) / 60);
- S32 secs = (S32)((time - hours*(60*60) - mins*60));
- std::string label = gDebugTimerLabel[idx];
- if (label.empty()) label = llformat("Debug: %d", idx);
- addText(xpos, ypos, llformat(" %s: %d:%02d:%02d", label.c_str(), hours,mins,secs)); ypos += y_inc2;
- }
-
- F32 time = gFrameTimeSeconds;
- S32 hours = (S32)(time / (60*60));
- S32 mins = (S32)((time - hours*(60*60)) / 60);
- S32 secs = (S32)((time - hours*(60*60) - mins*60));
- addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
- }
-
-#if LL_WINDOWS
- if (gSavedSettings.getBOOL("DebugShowMemory"))
- {
- addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024));
- ypos += y_inc;
- }
-#endif
-
- if (gDisplayCameraPos)
- {
- std::string camera_view_text;
- std::string camera_center_text;
- std::string agent_view_text;
- std::string agent_left_text;
- std::string agent_center_text;
- std::string agent_root_center_text;
-
- LLVector3d tvector; // Temporary vector to hold data for printing.
-
- // Update camera center, camera view, wind info every other frame
- tvector = gAgent.getPositionGlobal();
- agent_center_text = llformat("AgentCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- if (isAgentAvatarValid())
- {
- tvector = gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot.getWorldPosition());
- agent_root_center_text = llformat("AgentRootCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
- }
- else
- {
- agent_root_center_text = "---";
- }
-
-
- tvector = LLVector4(gAgent.getFrameAgent().getAtAxis());
- agent_view_text = llformat("AgentAtAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis());
- agent_left_text = llformat("AgentLeftAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- tvector = gAgentCamera.getCameraPositionGlobal();
- camera_center_text = llformat("CameraCenter %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- tvector = LLVector4(LLViewerCamera::getInstance()->getAtAxis());
- camera_view_text = llformat("CameraAtAxis %f %f %f",
- (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
-
- addText(xpos, ypos, agent_center_text); ypos += y_inc;
- addText(xpos, ypos, agent_root_center_text); ypos += y_inc;
- addText(xpos, ypos, agent_view_text); ypos += y_inc;
- addText(xpos, ypos, agent_left_text); ypos += y_inc;
- addText(xpos, ypos, camera_center_text); ypos += y_inc;
- addText(xpos, ypos, camera_view_text); ypos += y_inc;
- }
-
- if (gDisplayWindInfo)
- {
- wind_vel_text = llformat("Wind velocity %.2f m/s", gWindVec.magVec());
- wind_vector_text = llformat("Wind vector %.2f %.2f %.2f", gWindVec.mV[0], gWindVec.mV[1], gWindVec.mV[2]);
- rwind_vel_text = llformat("RWind vel %.2f m/s", gRelativeWindVec.magVec());
- rwind_vector_text = llformat("RWind vec %.2f %.2f %.2f", gRelativeWindVec.mV[0], gRelativeWindVec.mV[1], gRelativeWindVec.mV[2]);
-
- addText(xpos, ypos, wind_vel_text); ypos += y_inc;
- addText(xpos, ypos, wind_vector_text); ypos += y_inc;
- addText(xpos, ypos, rwind_vel_text); ypos += y_inc;
- addText(xpos, ypos, rwind_vector_text); ypos += y_inc;
- }
- if (gDisplayWindInfo)
- {
- if (gAudiop)
- {
- audio_text= llformat("Audio for wind: %d", gAudiop->isWindEnabled());
- }
- addText(xpos, ypos, audio_text); ypos += y_inc;
- }
- if (gDisplayFOV)
- {
- addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
- ypos += y_inc;
- }
- if (gDisplayBadge)
- {
- addText(xpos, ypos+(y_inc/2), llformat("Hippos!", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
- ypos += y_inc * 2;
- }
-
- /*if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- addText(xpos + 200, ypos, llformat("Flycam"));
- ypos += y_inc;
- }*/
-
- if (gSavedSettings.getBOOL("DebugShowRenderInfo"))
- {
- if (gPipeline.getUseVertexShaders() == 0)
- {
- addText(xpos, ypos, "Shaders Disabled");
- ypos += y_inc;
- }
- addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024)));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Mapped Buffers", LLVertexBuffer::sMappedCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Vertex Buffer Binds", LLVertexBuffer::sBindCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Vertex Buffer Sets", LLVertexBuffer::sSetCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Render Calls", gPipeline.mBatchCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Matrix Ops", gPipeline.mMatrixOpCount));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%d Texture Matrix Ops", gPipeline.mTextureMatrixOps));
- ypos += y_inc;
-
- gPipeline.mTextureMatrixOps = 0;
- gPipeline.mMatrixOpCount = 0;
-
- if (gPipeline.mBatchCount > 0)
- {
- addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", gPipeline.mMinBatchSize, gPipeline.mMaxBatchSize,
- gPipeline.mTrianglesDrawn/gPipeline.mBatchCount));
-
- gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize;
- gPipeline.mMaxBatchSize = 0;
- gPipeline.mBatchCount = 0;
- }
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("UI Verts/Calls: %d/%d", LLRender::sUIVerts, LLRender::sUICalls));
- LLRender::sUICalls = LLRender::sUIVerts = 0;
- ypos += y_inc;
-
- addText(xpos,ypos, llformat("%d/%d Nodes visible", gPipeline.mNumVisibleNodes, LLSpatialGroup::sNodeCount));
-
- ypos += y_inc;
-
-
- addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars));
-
- ypos += y_inc;
-
- addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount));
-
- ypos += y_inc;
-
- LLVertexBuffer::sBindCount = LLImageGL::sBindCount =
- LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount =
- gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
- }
- if (gSavedSettings.getBOOL("DebugShowRenderMatrices"))
- {
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15]));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[8], gGLProjection[9], gGLProjection[10], gGLProjection[11]));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[4], gGLProjection[5], gGLProjection[6], gGLProjection[7]));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[0], gGLProjection[1], gGLProjection[2], gGLProjection[3]));
- ypos += y_inc;
-
- addText(xpos, ypos, "Projection Matrix");
- ypos += y_inc;
-
-
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[12], gGLModelView[13], gGLModelView[14], gGLModelView[15]));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[8], gGLModelView[9], gGLModelView[10], gGLModelView[11]));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[4], gGLModelView[5], gGLModelView[6], gGLModelView[7]));
- ypos += y_inc;
-
- addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[0], gGLModelView[1], gGLModelView[2], gGLModelView[3]));
- ypos += y_inc;
-
- addText(xpos, ypos, "View Matrix");
- ypos += y_inc;
- }
- if (gSavedSettings.getBOOL("DebugShowColor"))
- {
- U8 color[4];
- LLCoordGL coord = gViewerWindow->getCurrentMouse();
- glReadPixels(coord.mX, coord.mY, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, color);
- addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3]));
- ypos += y_inc;
- }
- // only display these messages if we are actually rendering beacons at this moment
- if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons"))
- {
- if (LLPipeline::getRenderParticleBeacons(NULL))
- {
- addText(xpos, ypos, beacon_particle);
- ypos += y_inc;
- }
- if (LLPipeline::toggleRenderTypeControlNegated((void*)LLPipeline::RENDER_TYPE_PARTICLES))
- {
- addText(xpos, ypos, particle_hiding);
- ypos += y_inc;
- }
- if (LLPipeline::getRenderPhysicalBeacons(NULL))
- {
- addText(xpos, ypos, beacon_physical);
- ypos += y_inc;
- }
- if (LLPipeline::getRenderScriptedBeacons(NULL))
- {
- addText(xpos, ypos, beacon_scripted);
- ypos += y_inc;
- }
- else
- if (LLPipeline::getRenderScriptedTouchBeacons(NULL))
- {
- addText(xpos, ypos, beacon_scripted_touch);
- ypos += y_inc;
- }
- if (LLPipeline::getRenderSoundBeacons(NULL))
- {
- addText(xpos, ypos, beacon_sound);
- ypos += y_inc;
- }
- }
- if(log_texture_traffic)
- {
- U32 old_y = ypos ;
- for(S32 i = LLViewerTexture::BOOST_NONE; i < LLViewerTexture::MAX_GL_IMAGE_CATEGORY; i++)
- {
- if(gTotalTextureBytesPerBoostLevel[i] > 0)
- {
- addText(xpos, ypos, llformat("Boost_Level %d: %.3f MB", i, (F32)gTotalTextureBytesPerBoostLevel[i] / (1024 * 1024)));
- ypos += y_inc;
- }
- }
- if(ypos != old_y)
- {
- addText(xpos, ypos, "Network traffic for textures:");
- ypos += y_inc;
- }
- }
-
- if (gSavedSettings.getBOOL("DebugShowTextureInfo"))
- {
- LLViewerObject* objectp = NULL ;
- //objectp = = gAgentCamera.getFocusObject();
-
- LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode();
- if (nodep)
- {
- objectp = nodep->getObject();
- }
- if (objectp && !objectp->isDead())
- {
- S32 num_faces = objectp->mDrawable->getNumFaces() ;
-
- for(S32 i = 0 ; i < num_faces; i++)
- {
- LLFace* facep = objectp->mDrawable->getFace(i) ;
- if(facep)
- {
- //addText(xpos, ypos, llformat("ts_min: %.3f ts_max: %.3f tt_min: %.3f tt_max: %.3f", facep->mTexExtents[0].mV[0], facep->mTexExtents[1].mV[0],
- // facep->mTexExtents[0].mV[1], facep->mTexExtents[1].mV[1]));
- //ypos += y_inc;
-
- addText(xpos, ypos, llformat("v_size: %.3f: p_size: %.3f", facep->getVirtualSize(), facep->getPixelArea()));
- ypos += y_inc;
-
- //const LLTextureEntry *tep = facep->getTextureEntry();
- //if(tep)
- //{
- // addText(xpos, ypos, llformat("scale_s: %.3f: scale_t: %.3f", tep->mScaleS, tep->mScaleT)) ;
- // ypos += y_inc;
- //}
-
- LLViewerTexture* tex = facep->getTexture() ;
- if(tex)
- {
- addText(xpos, ypos, llformat("ID: %s v_size: %.3f", tex->getID().asString().c_str(), tex->getMaxVirtualSize()));
- ypos += y_inc;
- }
- }
- }
- }
- }
- }
-
- void draw()
- {
- for (line_list_t::iterator iter = mLineList.begin();
- iter != mLineList.end(); ++iter)
- {
- const Line& line = *iter;
- LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor,
- LLFontGL::LEFT, LLFontGL::TOP,
- LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
- }
- mLineList.clear();
- }
-
-};
-
-void LLViewerWindow::updateDebugText()
-{
- mDebugText->update();
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// LLViewerWindow
-//
-
-BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down)
-{
- const char* buttonname = "";
- const char* buttonstatestr = "";
- S32 x = pos.mX;
- S32 y = pos.mY;
- x = llround((F32)x / mDisplayScale.mV[VX]);
- y = llround((F32)y / mDisplayScale.mV[VY]);
-
- // only send mouse clicks to UI if UI is visible
- if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
-
- if (down)
- {
- buttonstatestr = "down" ;
- }
- else
- {
- buttonstatestr = "up" ;
- }
-
- switch (clicktype)
- {
- case LLMouseHandler::CLICK_LEFT:
- mLeftMouseDown = down;
- buttonname = "Left";
- break;
- case LLMouseHandler::CLICK_RIGHT:
- mRightMouseDown = down;
- buttonname = "Right";
- break;
- case LLMouseHandler::CLICK_MIDDLE:
- mMiddleMouseDown = down;
- buttonname = "Middle";
- break;
- case LLMouseHandler::CLICK_DOUBLELEFT:
- mLeftMouseDown = down;
- buttonname = "Left Double Click";
- break;
- }
-
- LLView::sMouseHandlerMessage.clear();
-
- if (gMenuBarView)
- {
- // stop ALT-key access to menu
- gMenuBarView->resetMenuTrigger();
- }
-
- if (gDebugClicks)
- {
- llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << llendl;
- }
-
- // Make sure we get a corresponding mouseup event, even if the mouse leaves the window
- if (down)
- mWindow->captureMouse();
- else
- mWindow->releaseMouse();
-
- // Indicate mouse was active
- LLUI::resetMouseIdleTimer();
-
- // Don't let the user move the mouse out of the window until mouse up.
- if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() )
- {
- mWindow->setMouseClipping(down);
- }
-
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- if( mouse_captor )
- {
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
- if (LLView::sDebugMouseHandling)
- {
- llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl;
- }
- return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
- }
-
- // Topmost view gets a chance before the hierarchy
- //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- //if (top_ctrl)
- //{
- // S32 local_x, local_y;
- // top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
- // if (top_ctrl->pointInView(local_x, local_y))
- // {
- // return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ;
- // }
- // else
- // {
- // if (down)
- // {
- // gFocusMgr.setTopCtrl(NULL);
- // }
- // }
- //}
-
- // Give the UI views a chance to process the click
- if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
- {
- if (LLView::sDebugMouseHandling)
- {
- llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl;
- }
- return TRUE;
- }
- else if (LLView::sDebugMouseHandling)
- {
- llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
- }
- }
-
- // Do not allow tool manager to handle mouseclicks if we have disconnected
- if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
- {
- return TRUE;
- }
-
-
- // If we got this far on a down-click, it wasn't handled.
- // Up-clicks, though, are always handled as far as the OS is concerned.
- BOOL default_rtn = !down;
- return default_rtn;
-}
-
-BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- BOOL down = TRUE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
-}
-
-BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- // try handling as a double-click first, then a single-click if that
- // wasn't handled.
- BOOL down = TRUE;
- if (handleAnyMouseClick(window, pos, mask,
- LLMouseHandler::CLICK_DOUBLELEFT, down))
- {
- return TRUE;
- }
- return handleMouseDown(window, pos, mask);
-}
-
-BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- BOOL down = FALSE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
-}
-
-
-BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- S32 x = pos.mX;
- S32 y = pos.mY;
- x = llround((F32)x / mDisplayScale.mV[VX]);
- y = llround((F32)y / mDisplayScale.mV[VY]);
-
- BOOL down = TRUE;
- BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
- if (handle)
- return handle;
-
- // *HACK: this should be rolled into the composite tool logic, not
- // hardcoded at the top level.
- if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance())
- {
- // If the current tool didn't process the click, we should show
- // the pie menu. This can be done by passing the event to the pie
- // menu tool.
- LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
- // show_context_menu( x, y, mask );
- }
-
- return TRUE;
-}
-
-BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- BOOL down = FALSE;
- return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
-}
-
-BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- BOOL down = TRUE;
- LLVoiceClient::getInstance()->middleMouseState(true);
- handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
-
- // Always handled as far as the OS is concerned.
- return TRUE;
-}
-
-LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data)
-{
- LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE;
-
- const bool prim_media_dnd_enabled = gSavedSettings.getBOOL("PrimMediaDragNDrop");
- const bool slurl_dnd_enabled = gSavedSettings.getBOOL("SLURLDragNDrop");
-
- if ( prim_media_dnd_enabled || slurl_dnd_enabled )
- {
- switch(action)
- {
- // Much of the handling for these two cases is the same.
- case LLWindowCallbacks::DNDA_TRACK:
- case LLWindowCallbacks::DNDA_DROPPED:
- case LLWindowCallbacks::DNDA_START_TRACKING:
- {
- bool drop = (LLWindowCallbacks::DNDA_DROPPED == action);
-
- if (slurl_dnd_enabled)
- {
- LLSLURL dropped_slurl(data);
- if(dropped_slurl.isSpatial())
- {
- if (drop)
- {
- LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), NULL, true );
- return LLWindowCallbacks::DND_MOVE;
- }
- return LLWindowCallbacks::DND_COPY;
- }
- }
-
- if (prim_media_dnd_enabled)
- {
- LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ );
-
- LLUUID object_id = pick_info.getObjectID();
- S32 object_face = pick_info.mObjectFace;
- std::string url = data;
-
- lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl;
-
- LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject()));
-
- if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty())
- {
- LLTextureEntry *te = obj->getTE(object_face);
-
- // can modify URL if we can modify the object or we have navigate permissions
- bool allow_modify_url = obj->permModify() || obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT );
-
- if (te && allow_modify_url )
- {
- if (drop)
- {
- // object does NOT have media already
- if ( ! te->hasMedia() )
- {
- // we are allowed to modify the object
- if ( obj->permModify() )
- {
- // Create new media entry
- LLSD media_data;
- // XXX Should we really do Home URL too?
- media_data[LLMediaEntry::HOME_URL_KEY] = url;
- media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
- media_data[LLMediaEntry::AUTO_PLAY_KEY] = true;
- obj->syncMediaData(object_face, media_data, true, true);
- // XXX This shouldn't be necessary, should it ?!?
- if (obj->getMediaImpl(object_face))
- obj->getMediaImpl(object_face)->navigateReload();
- obj->sendMediaDataUpdate();
-
- result = LLWindowCallbacks::DND_COPY;
- }
- }
- else
- // object HAS media already
- {
- // URL passes the whitelist
- if (te->getMediaData()->checkCandidateUrl( url ) )
- {
- // just navigate to the URL
- if (obj->getMediaImpl(object_face))
- {
- obj->getMediaImpl(object_face)->navigateTo(url);
- }
- else
- {
- // This is very strange. Navigation should
- // happen via the Impl, but we don't have one.
- // This sends it to the server, which /should/
- // trigger us getting it. Hopefully.
- LLSD media_data;
- media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
- obj->syncMediaData(object_face, media_data, true, true);
- obj->sendMediaDataUpdate();
- }
- result = LLWindowCallbacks::DND_LINK;
-
- }
- }
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = NULL;
-
- }
- else
- {
- // Check the whitelist, if there's media (otherwise just show it)
- if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url))
- {
- if ( obj != mDragHoveredObject)
- {
- // Highlight the dragged object
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = obj;
- LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject);
- }
- result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK;
-
- }
- }
- }
- }
- }
- }
- break;
-
- case LLWindowCallbacks::DNDA_STOP_TRACKING:
- // The cleanup case below will make sure things are unhilighted if necessary.
- break;
- }
-
- if (prim_media_dnd_enabled &&
- result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull())
- {
- LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
- mDragHoveredObject = NULL;
- }
- }
-
- return result;
-}
-
-BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- BOOL down = FALSE;
- LLVoiceClient::getInstance()->middleMouseState(false);
- handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
-
- // Always handled as far as the OS is concerned.
- return TRUE;
-}
-
-// WARNING: this is potentially called multiple times per frame
-void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask)
-{
- S32 x = pos.mX;
- S32 y = pos.mY;
-
- x = llround((F32)x / mDisplayScale.mV[VX]);
- y = llround((F32)y / mDisplayScale.mV[VY]);
-
- mMouseInWindow = TRUE;
-
- // Save mouse point for access during idle() and display()
-
- LLCoordGL mouse_point(x, y);
-
- if (mouse_point != mCurrentMousePoint)
- {
- LLUI::resetMouseIdleTimer();
- }
-
- saveLastMouse(mouse_point);
-
- mWindow->showCursorFromMouseMove();
-
- if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
- {
- gAgent.clearAFK();
- }
-}
-
-void LLViewerWindow::handleMouseLeave(LLWindow *window)
-{
- // Note: we won't get this if we have captured the mouse.
- llassert( gFocusMgr.getMouseCapture() == NULL );
- mMouseInWindow = FALSE;
- LLToolTipMgr::instance().blockToolTips();
-}
-
-BOOL LLViewerWindow::handleCloseRequest(LLWindow *window)
-{
- // User has indicated they want to close, but we may need to ask
- // about modified documents.
- LLAppViewer::instance()->userQuit();
- // Don't quit immediately
- return FALSE;
-}
-
-void LLViewerWindow::handleQuit(LLWindow *window)
-{
- LLAppViewer::instance()->forceQuit();
-}
-
-void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height)
-{
- reshape(width, height);
- mResDirty = true;
-}
-
-// The top-level window has gained focus (e.g. via ALT-TAB)
-void LLViewerWindow::handleFocus(LLWindow *window)
-{
- gFocusMgr.setAppHasFocus(TRUE);
- LLModalDialog::onAppFocusGained();
-
- gAgent.onAppFocusGained();
- LLToolMgr::getInstance()->onAppFocusGained();
-
- // See if we're coming in with modifier keys held down
- if (gKeyboard)
- {
- gKeyboard->resetMaskKeys();
- }
-
- // resume foreground running timer
- // since we artifically limit framerate when not frontmost
- gForegroundTime.unpause();
-}
-
-// The top-level window has lost focus (e.g. via ALT-TAB)
-void LLViewerWindow::handleFocusLost(LLWindow *window)
-{
- gFocusMgr.setAppHasFocus(FALSE);
- //LLModalDialog::onAppFocusLost();
- LLToolMgr::getInstance()->onAppFocusLost();
- gFocusMgr.setMouseCapture( NULL );
-
- if (gMenuBarView)
- {
- // stop ALT-key access to menu
- gMenuBarView->resetMenuTrigger();
- }
-
- // restore mouse cursor
- showCursor();
- getWindow()->setMouseClipping(FALSE);
-
- // If losing focus while keys are down, reset them.
- if (gKeyboard)
- {
- gKeyboard->resetKeys();
- }
-
- // pause timer that tracks total foreground running time
- gForegroundTime.pause();
-}
-
-
-BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
-{
- // Let the voice chat code check for its PTT key. Note that this never affects event processing.
- LLVoiceClient::getInstance()->keyDown(key, mask);
-
- if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
- {
- gAgent.clearAFK();
- }
-
- // *NOTE: We want to interpret KEY_RETURN later when it arrives as
- // a Unicode char, not as a keydown. Otherwise when client frame
- // rate is really low, hitting return sends your chat text before
- // it's all entered/processed.
- if (key == KEY_RETURN && mask == MASK_NONE)
- {
- return FALSE;
- }
-
- return gViewerKeyboard.handleKey(key, mask, repeated);
-}
-
-BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
-{
- // Let the voice chat code check for its PTT key. Note that this never affects event processing.
- LLVoiceClient::getInstance()->keyUp(key, mask);
-
- return FALSE;
-}
-
-
-void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
-{
- LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
- return gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
-}
-
-
-
-
-BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated)
-{
- if (activated)
- {
- mActive = TRUE;
- send_agent_resume();
- gAgent.clearAFK();
-
- // Unmute audio
- audio_update_volume();
- }
- else
- {
- mActive = FALSE;
-
- if (gSavedSettings.getS32("AFKTimeout"))
- {
- gAgent.setAFK();
- }
-
- // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues
- if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
- {
- gAgentCamera.changeCameraToDefault();
- }
-
- send_agent_pause();
-
- // Mute audio
- audio_update_volume();
- }
- return TRUE;
-}
-
-BOOL LLViewerWindow::handleActivateApp(LLWindow *window, BOOL activating)
-{
- //if (!activating) gAgentCamera.changeCameraToDefault();
-
- LLViewerJoystick::getInstance()->setNeedsReset(true);
- return FALSE;
-}
-
-
-void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item)
-{
-}
-
-
-BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height)
-{
-#if LL_WINDOWS
- if (gNoRender)
- {
- HWND window_handle = (HWND)window->getPlatformWindow();
- PAINTSTRUCT ps;
- HDC hdc;
-
- RECT wnd_rect;
- wnd_rect.left = 0;
- wnd_rect.top = 0;
- wnd_rect.bottom = 200;
- wnd_rect.right = 500;
-
- hdc = BeginPaint(window_handle, &ps);
- //SetBKColor(hdc, RGB(255, 255, 255));
- FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255)));
-
- std::string temp_str;
- temp_str = llformat( "FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */
- LLViewerStats::getInstance()->mFPSStat.getMeanPerSec(),
- LLViewerStats::getInstance()->mSimPhysicsFPS.getPrev(0),
- LLViewerStats::getInstance()->mSimTimeDilation.getPrev(0));
- S32 len = temp_str.length();
- TextOutA(hdc, 0, 0, temp_str.c_str(), len);
-
-
- LLVector3d pos_global = gAgent.getPositionGlobal();
- temp_str = llformat( "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]);
- len = temp_str.length();
- TextOutA(hdc, 0, 25, temp_str.c_str(), len);
-
- TextOutA(hdc, 0, 50, "Set \"DisableRendering FALSE\" in settings.ini file to reenable", 61);
- EndPaint(window_handle, &ps);
- return TRUE;
- }
-#endif
- return FALSE;
-}
-
-
-void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks)
-{
- handleScrollWheel( clicks );
-}
-
-void LLViewerWindow::handleWindowBlock(LLWindow *window)
-{
- send_agent_pause();
-}
-
-void LLViewerWindow::handleWindowUnblock(LLWindow *window)
-{
- send_agent_resume();
-}
-
-void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
-{
- const S32 SLURL_MESSAGE_TYPE = 0;
- switch (data_type)
- {
- case SLURL_MESSAGE_TYPE:
- // received URL
- std::string url = (const char*)data;
- LLMediaCtrl* web = NULL;
- const bool trusted_browser = false;
- if (LLURLDispatcher::dispatch(url, web, trusted_browser))
- {
- // bring window to foreground, as it has just been "launched" from a URL
- mWindow->bringToFront();
- }
- break;
- }
-}
-
-BOOL LLViewerWindow::handleTimerEvent(LLWindow *window)
-{
- if (LLViewerJoystick::getInstance()->getOverrideCamera())
- {
- LLViewerJoystick::getInstance()->updateStatus();
- return TRUE;
- }
- return FALSE;
-}
-
-BOOL LLViewerWindow::handleDeviceChange(LLWindow *window)
-{
- // give a chance to use a joystick after startup (hot-plugging)
- if (!LLViewerJoystick::getInstance()->isJoystickInitialized() )
- {
- LLViewerJoystick::getInstance()->init(true);
- return TRUE;
- }
- return FALSE;
-}
-
-void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg)
-{
- LLAppViewer::instance()->pingMainloopTimeout(msg);
-}
-
-
-void LLViewerWindow::handleResumeWatchdog(LLWindow *window)
-{
- LLAppViewer::instance()->resumeMainloopTimeout();
-}
-
-void LLViewerWindow::handlePauseWatchdog(LLWindow *window)
-{
- LLAppViewer::instance()->pauseMainloopTimeout();
-}
-
-//virtual
-std::string LLViewerWindow::translateString(const char* tag)
-{
- return LLTrans::getString( std::string(tag) );
-}
-
-//virtual
-std::string LLViewerWindow::translateString(const char* tag,
- const std::map<std::string, std::string>& args)
-{
- // LLTrans uses a special subclass of std::string for format maps,
- // but we must use std::map<> in these callbacks, otherwise we create
- // a dependency between LLWindow and LLFormatMapString. So copy the data.
- LLStringUtil::format_map_t args_copy;
- std::map<std::string,std::string>::const_iterator it = args.begin();
- for ( ; it != args.end(); ++it)
- {
- args_copy[it->first] = it->second;
- }
- return LLTrans::getString( std::string(tag), args_copy);
-}
-
-//
-// Classes
-//
-LLViewerWindow::LLViewerWindow(
- const std::string& title, const std::string& name,
- S32 x, S32 y,
- S32 width, S32 height,
- BOOL fullscreen, BOOL ignore_pixel_depth) // fullscreen is no longer used
- :
- mWindow(NULL),
- mActive(TRUE),
- mWindowRectRaw(0, height, width, 0),
- mWindowRectScaled(0, height, width, 0),
- mWorldViewRectRaw(0, height, width, 0),
- mLeftMouseDown(FALSE),
- mMiddleMouseDown(FALSE),
- mRightMouseDown(FALSE),
- mMouseInWindow( FALSE ),
- mLastMask( MASK_NONE ),
- mToolStored( NULL ),
- mHideCursorPermanent( FALSE ),
- mCursorHidden(FALSE),
- mIgnoreActivate( FALSE ),
- mResDirty(false),
- mStatesDirty(false),
- mCurrResolutionIndex(0),
- mViewerWindowListener(new LLViewerWindowListener(this)),
- mProgressView(NULL)
-{
- LLNotificationChannel::buildChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert"));
- LLNotificationChannel::buildChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal"));
-
- LLNotifications::instance().getChannel("VW_alerts")->connectChanged(&LLViewerWindow::onAlert);
- LLNotifications::instance().getChannel("VW_alertmodal")->connectChanged(&LLViewerWindow::onAlert);
- LLNotifications::instance().setIgnoreAllNotifications(gSavedSettings.getBOOL("IgnoreAllNotifications"));
- llinfos << "NOTE: ALL NOTIFICATIONS THAT OCCUR WILL GET ADDED TO IGNORE LIST FOR LATER RUNS." << llendl;
-
- // Default to application directory.
- LLViewerWindow::sSnapshotBaseName = "Snapshot";
- LLViewerWindow::sMovieBaseName = "SLmovie";
- resetSnapshotLoc();
-
- // create window
- mWindow = LLWindowManager::createWindow(this,
- title, name, x, y, width, height, 0,
- fullscreen,
- gNoRender,
- gSavedSettings.getBOOL("DisableVerticalSync"),
- !gNoRender,
- ignore_pixel_depth,
- gSavedSettings.getBOOL("RenderUseFBO") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled
-
- if (!LLAppViewer::instance()->restoreErrorTrap())
- {
- LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL;
- }
-
- LLCoordScreen scr;
- mWindow->getSize(&scr);
-
- if(fullscreen && ( scr.mX!=width || scr.mY!=height))
- {
- llwarns << "Fullscreen has forced us in to a different resolution now using "<<scr.mX<<" x "<<scr.mY<<llendl;
- gSavedSettings.setS32("FullScreenWidth",scr.mX);
- gSavedSettings.setS32("FullScreenHeight",scr.mY);
- }
-
- if (NULL == mWindow)
- {
- LLSplashScreen::update(LLTrans::getString("ShuttingDown"));
-#if LL_LINUX || LL_SOLARIS
- llwarns << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt or README-solaris.txt for further information."
- << llendl;
-#else
- LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings"
- << LL_ENDL;
-#endif
- LLAppViewer::instance()->fastQuit(1);
- }
-
- // Get the real window rect the window was created with (since there are various OS-dependent reasons why
- // the size of a window or fullscreen context may have been adjusted slightly...)
- F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
-
- mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
- mDisplayScale *= ui_scale_factor;
- LLUI::setScaleFactor(mDisplayScale);
-
- {
- LLCoordWindow size;
- mWindow->getSize(&size);
- mWindowRectRaw.set(0, size.mY, size.mX, 0);
- mWindowRectScaled.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0);
- }
-
- LLFontManager::initClass();
-
- //
- // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
- // stuff like AGP if we think that it'll crash the viewer.
- //
- LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL;
-
- LLFeatureManager::getInstance()->init();
-
- // Initialize OpenGL Renderer
- if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") ||
- !gGLManager.mHasVertexBufferObject)
- {
- gSavedSettings.setBOOL("RenderVBOEnable", FALSE);
- }
- LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable"));
-
- if (LLFeatureManager::getInstance()->isSafe()
- || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
- || (gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass())
- || (gSavedSettings.getBOOL("ProbeHardwareOnStartup")))
- {
- LLFeatureManager::getInstance()->applyRecommendedSettings();
- gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
- }
-
- if (!gGLManager.mHasDepthClamp)
- {
- LL_INFOS("RenderInit") << "Missing feature GL_ARB_depth_clamp. Void water might disappear in rare cases." << LL_ENDL;
- }
-
- // If we crashed while initializng GL stuff last time, disable certain features
- if (gSavedSettings.getBOOL("RenderInitError"))
- {
- mInitAlert = "DisplaySettingsNoShaders";
- LLFeatureManager::getInstance()->setGraphicsLevel(0, false);
- gSavedSettings.setU32("RenderQualityPerformance", 0);
- }
-
- // Init the image list. Must happen after GL is initialized and before the images that
- // LLViewerWindow needs are requested.
- LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ;
- gTextureList.init();
- LLViewerTextureManager::init() ;
- gBumpImageList.init();
-
- // Init font system, but don't actually load the fonts yet
- // because our window isn't onscreen and they take several
- // seconds to parse.
- LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
- mDisplayScale.mV[VX],
- mDisplayScale.mV[VY],
- gDirUtilp->getAppRODataDir(),
- LLUI::getXUIPaths());
-
- // Create container for all sub-views
- LLView::Params rvp;
- rvp.name("root");
- rvp.rect(mWindowRectScaled);
- rvp.mouse_opaque(false);
- rvp.follows.flags(FOLLOWS_NONE);
- mRootView = LLUICtrlFactory::create<LLRootView>(rvp);
- LLUI::setRootView(mRootView);
-
- // Make avatar head look forward at start
- mCurrentMousePoint.mX = getWindowWidthScaled() / 2;
- mCurrentMousePoint.mY = getWindowHeightScaled() / 2;
-
- gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle");
- mOverlayTitle = gSavedSettings.getString("OverlayTitle");
- // Can't have spaces in settings.ini strings, so use underscores instead and convert them.
- LLStringUtil::replaceChar(mOverlayTitle, '_', ' ');
-
- // sync the keyboard's setting with the saved setting
- gSavedSettings.getControl("NumpadControl")->firePropertyChanged();
-
- mDebugText = new LLDebugText(this);
-
- mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
-}
-
-void LLViewerWindow::initGLDefaults()
-{
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
-
- F32 ambient[4] = {0.f,0.f,0.f,0.f };
- F32 diffuse[4] = {1.f,1.f,1.f,1.f };
- glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient);
- glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuse);
-
- glPixelStorei(GL_PACK_ALIGNMENT,1);
- glPixelStorei(GL_UNPACK_ALIGNMENT,1);
-
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-
- // lights for objects
- glShadeModel( GL_SMOOTH );
-
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
-
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- glCullFace(GL_BACK);
-
- // RN: Need this for translation and stretch manip.
- gCone.prerender();
- gBox.prerender();
- gSphere.prerender();
- gCylinder.prerender();
-}
-
-struct MainPanel : public LLPanel
-{
-};
-
-void LLViewerWindow::initBase()
-{
- S32 height = getWindowHeightScaled();
- S32 width = getWindowWidthScaled();
-
- LLRect full_window(0, height, width, 0);
-
- ////////////////////
- //
- // Set the gamma
- //
-
- F32 gamma = gSavedSettings.getF32("RenderGamma");
- if (gamma != 0.0f)
- {
- getWindow()->setGamma(gamma);
- }
-
- // Create global views
-
- // Create the floater view at the start so that other views can add children to it.
- // (But wait to add it as a child of the root view so that it will be in front of the
- // other views.)
- MainPanel* main_view = new MainPanel();
- main_view->buildFromFile("main_view.xml");
- main_view->setShape(full_window);
- getRootView()->addChild(main_view);
-
- // placeholder widget that controls where "world" is rendered
- mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle();
- mNonSideTrayView = main_view->getChildView("non_side_tray_view")->getHandle();
- mFloaterViewHolder = main_view->getChildView("floater_view_holder")->getHandle();
- mPopupView = main_view->getChild<LLPopupView>("popup_holder");
- mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle();
- mLoginPanelHolder = main_view->getChild<LLView>("login_panel_holder")->getHandle();
-
- // Constrain floaters to inside the menu and status bar regions.
- gFloaterView = main_view->getChild<LLFloaterView>("Floater View");
- gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View");
-
-
- // Console
- llassert( !gConsole );
- LLConsole::Params cp;
- cp.name("console");
- cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize"));
- cp.rect(getChatConsoleRect());
- cp.persist_time(gSavedSettings.getF32("ChatPersistTime"));
- cp.font_size_index(gSavedSettings.getS32("ChatFontSize"));
- cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
- gConsole = LLUICtrlFactory::create<LLConsole>(cp);
- getRootView()->addChild(gConsole);
-
- // optionally forward warnings to chat console/chat floater
- // for qa runs and dev builds
-#if !LL_RELEASE_FOR_DOWNLOAD
- LLError::addRecorder(RecordToChatConsole::getInstance());
-#else
- if(gSavedSettings.getBOOL("QAMode"))
- {
- LLError::addRecorder(RecordToChatConsole::getInstance());
- }
-#endif
-
- gDebugView = getRootView()->getChild<LLDebugView>("DebugView");
- gDebugView->init();
- gToolTipView = getRootView()->getChild<LLToolTipView>("tooltip view");
-
- // Initialize busy response message when logged in
- LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLFloaterPreference::initBusyResponse));
-
- // Add the progress bar view (startup view), which overrides everything
- mProgressView = getRootView()->findChild<LLProgressView>("progress_view");
- setShowProgress(FALSE);
- setProgressCancelButtonVisible(FALSE);
-
- gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder");
-
- LLMenuGL::sMenuContainer = gMenuHolder;
-
-}
-
-void LLViewerWindow::initWorldUI()
-{
- S32 height = mRootView->getRect().getHeight();
- S32 width = mRootView->getRect().getWidth();
- LLRect full_window(0, height, width, 0);
-
-
- gIMMgr = LLIMMgr::getInstance();
-
- //getRootView()->sendChildToFront(gFloaterView);
- //getRootView()->sendChildToFront(gSnapshotFloaterView);
-
- // new bottom panel
- LLPanel* bottom_tray_container = getRootView()->getChild<LLPanel>("bottom_tray_container");
- LLBottomTray* bottom_tray = LLBottomTray::getInstance();
- bottom_tray->setShape(bottom_tray_container->getLocalRect());
- bottom_tray->setFollowsAll();
- bottom_tray_container->addChild(bottom_tray);
- bottom_tray_container->setVisible(TRUE);
-
- LLRect morph_view_rect = full_window;
- morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
- morph_view_rect.mTop = full_window.mTop - 32;
- LLMorphView::Params mvp;
- mvp.name("MorphView");
- mvp.rect(morph_view_rect);
- mvp.visible(false);
- gMorphView = LLUICtrlFactory::create<LLMorphView>(mvp);
- getRootView()->addChild(gMorphView);
-
- LLWorldMapView::initClass();
-
- // Force gFloaterWorldMap to initialize
- LLFloaterReg::getInstance("world_map");
-
- // Force gFloaterTools to initialize
- LLFloaterReg::getInstance("build");
- LLFloaterReg::hideInstance("build");
-
- // Status bar
- LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
- gStatusBar = new LLStatusBar(status_bar_container->getLocalRect());
- gStatusBar->setFollowsAll();
- gStatusBar->setShape(status_bar_container->getLocalRect());
- // sync bg color with menu bar
- gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor().get() );
- status_bar_container->addChild(gStatusBar);
- status_bar_container->setVisible(TRUE);
-
- // Navigation bar
- LLPanel* nav_bar_container = getRootView()->getChild<LLPanel>("nav_bar_container");
-
- LLNavigationBar* navbar = LLNavigationBar::getInstance();
- navbar->setShape(nav_bar_container->getLocalRect());
- navbar->setBackgroundColor(gMenuBarView->getBackgroundColor().get());
- nav_bar_container->addChild(navbar);
- nav_bar_container->setVisible(TRUE);
-
- if (!gSavedSettings.getBOOL("ShowNavbarNavigationPanel"))
- {
- navbar->showNavigationPanel(FALSE);
- }
-
- if (!gSavedSettings.getBOOL("ShowNavbarFavoritesPanel"))
- {
- navbar->showFavoritesPanel(FALSE);
- }
-
- // Top Info bar
- LLPanel* topinfo_bar_container = getRootView()->getChild<LLPanel>("topinfo_bar_container");
- LLPanelTopInfoBar* topinfo_bar = LLPanelTopInfoBar::getInstance();
-
- topinfo_bar->setShape(topinfo_bar_container->getLocalRect());
-
- topinfo_bar_container->addChild(topinfo_bar);
- topinfo_bar_container->setVisible(TRUE);
-
- if (!gSavedSettings.getBOOL("ShowMiniLocationPanel"))
- {
- topinfo_bar->setVisible(FALSE);
- }
-
- if ( gHUDView == NULL )
- {
- LLRect hud_rect = full_window;
- hud_rect.mBottom += 50;
- if (gMenuBarView && gMenuBarView->isInVisibleChain())
- {
- hud_rect.mTop -= gMenuBarView->getRect().getHeight();
- }
- gHUDView = new LLHUDView(hud_rect);
- // put behind everything else in the UI
- getRootView()->addChildInBack(gHUDView);
- }
-
- LLPanel* panel_ssf_container = getRootView()->getChild<LLPanel>("stand_stop_flying_container");
- LLPanelStandStopFlying* panel_stand_stop_flying = LLPanelStandStopFlying::getInstance();
- panel_ssf_container->addChild(panel_stand_stop_flying);
- panel_ssf_container->setVisible(TRUE);
-
- // put sidetray in container
- LLPanel* side_tray_container = getRootView()->getChild<LLPanel>("side_tray_container");
- LLSideTray* sidetrayp = LLSideTray::getInstance();
- sidetrayp->setShape(side_tray_container->getLocalRect());
- // don't follow right edge to avoid spurious resizes, since we are using a fixed width layout
- sidetrayp->setFollows(FOLLOWS_LEFT|FOLLOWS_TOP|FOLLOWS_BOTTOM);
- side_tray_container->addChild(sidetrayp);
- side_tray_container->setVisible(FALSE);
-
- // put sidetray buttons in their own panel
- LLPanel* buttons_panel = sidetrayp->getButtonsPanel();
- LLPanel* buttons_panel_container = getRootView()->getChild<LLPanel>("side_bar_tabs");
- buttons_panel->setShape(buttons_panel_container->getLocalRect());
- buttons_panel->setFollowsAll();
- buttons_panel_container->addChild(buttons_panel);
-
- LLView* avatar_picker_destination_guide_container = gViewerWindow->getRootView()->getChild<LLView>("avatar_picker_and_destination_guide_container");
- LLMediaCtrl* destinations = avatar_picker_destination_guide_container->findChild<LLMediaCtrl>("destination_guide_contents");
- LLMediaCtrl* avatar_picker = avatar_picker_destination_guide_container->findChild<LLMediaCtrl>("avatar_picker_contents");
- if (destinations)
- {
- destinations->navigateTo(gSavedSettings.getString("DestinationGuideURL"), "text/html");
- }
-
- if (avatar_picker)
- {
- avatar_picker->navigateTo(gSavedSettings.getString("AvatarPickerURL"), "text/html");
- }
-
-}
-
-// Destroy the UI
-void LLViewerWindow::shutdownViews()
-{
- // clean up warning logger
- LLError::removeRecorder(RecordToChatConsole::getInstance());
-
- delete mDebugText;
- mDebugText = NULL;
-
- // Cleanup global views
- if (gMorphView)
- {
- gMorphView->setVisible(FALSE);
- }
-
- // DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open
- // will crump with LL_ERRS.
- LLModalDialog::shutdownModals();
-
- // destroy the nav bar, not currently part of gViewerWindow
- // *TODO: Make LLNavigationBar part of gViewerWindow
- delete LLNavigationBar::getInstance();
-
- // destroy menus after instantiating navbar above, as it needs
- // access to gMenuHolder
- cleanup_menus();
-
- // Delete all child views.
- delete mRootView;
- mRootView = NULL;
-
- // Automatically deleted as children of mRootView. Fix the globals.
- gStatusBar = NULL;
- gIMMgr = NULL;
- gToolTipView = NULL;
-
- gFloaterView = NULL;
- gMorphView = NULL;
-
- gHUDView = NULL;
-}
-
-void LLViewerWindow::shutdownGL()
-{
- //--------------------------------------------------------
- // Shutdown GL cleanly. Order is very important here.
- //--------------------------------------------------------
- LLFontGL::destroyDefaultFonts();
- LLFontManager::cleanupClass();
- stop_glerror();
-
- gSky.cleanup();
- stop_glerror();
-
- LLWearableList::instance().cleanup() ;
-
- gTextureList.shutdown();
- stop_glerror();
-
- gBumpImageList.shutdown();
- stop_glerror();
-
- LLWorldMapView::cleanupTextures();
-
- llinfos << "Cleaning up pipeline" << llendl;
- gPipeline.cleanup();
- stop_glerror();
-
- LLViewerTextureManager::cleanup() ;
- LLImageGL::cleanupClass() ;
-
- llinfos << "All textures and llimagegl images are destroyed!" << llendl ;
-
- llinfos << "Cleaning up select manager" << llendl;
- LLSelectMgr::getInstance()->cleanup();
-
- LLVertexBuffer::cleanupClass();
-
- llinfos << "Stopping GL during shutdown" << llendl;
- if (!gNoRender)
- {
- stopGL(FALSE);
- stop_glerror();
- }
-
- gGL.shutdown();
-}
-
-// shutdownViews() and shutdownGL() need to be called first
-LLViewerWindow::~LLViewerWindow()
-{
- llinfos << "Destroying Window" << llendl;
- destroyWindow();
-
- delete mDebugText;
- mDebugText = NULL;
-}
-
-
-void LLViewerWindow::setCursor( ECursorType c )
-{
- mWindow->setCursor( c );
-}
-
-void LLViewerWindow::showCursor()
-{
- mWindow->showCursor();
-
- mCursorHidden = FALSE;
-}
-
-void LLViewerWindow::hideCursor()
-{
- // And hide the cursor
- mWindow->hideCursor();
-
- mCursorHidden = TRUE;
-}
-
-void LLViewerWindow::sendShapeToSim()
-{
- LLMessageSystem* msg = gMessageSystem;
- if(!msg) return;
- msg->newMessageFast(_PREHASH_AgentHeightWidth);
- msg->nextBlockFast(_PREHASH_AgentData);
- msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
- msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
- msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
- msg->nextBlockFast(_PREHASH_HeightWidthBlock);
- msg->addU32Fast(_PREHASH_GenCounter, 0);
- U16 height16 = (U16) mWorldViewRectRaw.getHeight();
- U16 width16 = (U16) mWorldViewRectRaw.getWidth();
- msg->addU16Fast(_PREHASH_Height, height16);
- msg->addU16Fast(_PREHASH_Width, width16);
- gAgent.sendReliableMessage();
-}
-
-// Must be called after window is created to set up agent
-// camera variables and UI variables.
-void LLViewerWindow::reshape(S32 width, S32 height)
-{
- // Destroying the window at quit time generates spurious
- // reshape messages. We don't care about these, and we
- // don't want to send messages because the message system
- // may have been destructed.
- if (!LLApp::isExiting())
- {
- if (gNoRender)
- {
- return;
- }
-
- gWindowResized = TRUE;
-
- // update our window rectangle
- mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width;
- mWindowRectRaw.mTop = mWindowRectRaw.mBottom + height;
-
- //glViewport(0, 0, width, height );
-
- if (height > 0)
- {
- LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
- LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
- }
-
- calcDisplayScale();
-
- BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor;
- LLUI::setScaleFactor(mDisplayScale);
-
- // update our window rectangle
- mWindowRectScaled.mRight = mWindowRectScaled.mLeft + llround((F32)width / mDisplayScale.mV[VX]);
- mWindowRectScaled.mTop = mWindowRectScaled.mBottom + llround((F32)height / mDisplayScale.mV[VY]);
-
- setup2DViewport();
-
- // Inform lower views of the change
- // round up when converting coordinates to make sure there are no gaps at edge of window
- LLView::sForceReshape = display_scale_changed;
- mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY]));
- LLView::sForceReshape = FALSE;
-
- // clear font width caches
- if (display_scale_changed)
- {
- LLHUDObject::reshapeAll();
- }
-
- sendShapeToSim();
-
- // store new settings for the mode we are in, regardless
- // Only save size if not maximized
- BOOL maximized = mWindow->getMaximized();
- gSavedSettings.setBOOL("WindowMaximized", maximized);
-
- LLCoordScreen window_size;
- if (!maximized
- && mWindow->getSize(&window_size))
- {
- gSavedSettings.setS32("WindowWidth", window_size.mX);
- gSavedSettings.setS32("WindowHeight", window_size.mY);
- }
-
- LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width);
- LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height);
- }
-}
-
-
-// Hide normal UI when a logon fails
-void LLViewerWindow::setNormalControlsVisible( BOOL visible )
-{
- if(LLBottomTray::instanceExists())
- {
- LLBottomTray::getInstance()->setVisible(visible);
- LLBottomTray::getInstance()->setEnabled(visible);
- }
-
- if ( gMenuBarView )
- {
- gMenuBarView->setVisible( visible );
- gMenuBarView->setEnabled( visible );
-
- // ...and set the menu color appropriately.
- setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT,
- LLGridManager::getInstance()->isInProductionGrid());
- }
-
- if ( gStatusBar )
- {
- gStatusBar->setVisible( visible );
- gStatusBar->setEnabled( visible );
- }
-
- LLNavigationBar* navbarp = LLUI::getRootView()->findChild<LLNavigationBar>("navigation_bar");
- if (navbarp)
- {
- navbarp->setVisible( visible );
- }
-}
-
-void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
-{
- LLSD args;
- LLColor4 new_bg_color;
-
- // no l10n problem because channel is always an english string
- std::string channel = LLVersionInfo::getChannel();
- bool isProject = (channel.find("Project") != std::string::npos);
-
- // god more important than project, proj more important than grid
- if(god_mode && LLGridManager::getInstance()->isInProductionGrid())
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" );
- }
- else if(god_mode && !LLGridManager::getInstance()->isInProductionGrid())
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" );
- }
- else if (!god_mode && isProject)
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarProjectBgColor" );
- }
- else if(!god_mode && !LLGridManager::getInstance()->isInProductionGrid())
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
- }
- else
- {
- new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
- }
-
- if(gMenuBarView)
- {
- gMenuBarView->setBackgroundColor( new_bg_color );
- }
-
- if(gStatusBar)
- {
- gStatusBar->setBackgroundColor( new_bg_color );
- }
-}
-
-void LLViewerWindow::drawDebugText()
-{
- gGL.color4f(1,1,1,1);
- gGL.pushMatrix();
- gGL.pushUIMatrix();
- {
- // scale view by UI global scale factor and aspect ratio correction factor
- gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
- mDebugText->draw();
- }
- gGL.popUIMatrix();
- gGL.popMatrix();
-
- gGL.flush();
-}
-
-void LLViewerWindow::draw()
-{
-
-//#if LL_DEBUG
- LLView::sIsDrawing = TRUE;
-//#endif
- stop_glerror();
-
- LLUI::setLineWidth(1.f);
-
- LLUI::setLineWidth(1.f);
- // Reset any left-over transforms
- glMatrixMode(GL_MODELVIEW);
-
- glLoadIdentity();
-
- //S32 screen_x, screen_y;
-
- if (!gSavedSettings.getBOOL("RenderUIBuffer"))
- {
- LLUI::sDirtyRect = getWindowRectScaled();
- }
-
- // HACK for timecode debugging
- if (gSavedSettings.getBOOL("DisplayTimecode"))
- {
- // draw timecode block
- std::string text;
-
- glLoadIdentity();
-
- microsecondsToTimecodeString(gFrameTime,text);
- const LLFontGL* font = LLFontGL::getFontSansSerif();
- font->renderUTF8(text, 0,
- llround((getWindowWidthScaled()/2)-100.f),
- llround((getWindowHeightScaled()-60.f)),
- LLColor4( 1.f, 1.f, 1.f, 1.f ),
- LLFontGL::LEFT, LLFontGL::TOP);
- }
-
- // Draw all nested UI views.
- // No translation needed, this view is glued to 0,0
-
- gGL.pushMatrix();
- LLUI::pushMatrix();
- {
-
- // scale view by UI global scale factor and aspect ratio correction factor
- gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
-
- LLVector2 old_scale_factor = LLUI::sGLScaleFactor;
- // apply camera zoom transform (for high res screenshots)
- F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
- S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
- if (zoom_factor > 1.f)
- {
- //decompose subregion number to x and y values
- int pos_y = sub_region / llceil(zoom_factor);
- int pos_x = sub_region - (pos_y*llceil(zoom_factor));
- // offset for this tile
- glTranslatef((F32)getWindowWidthScaled() * -(F32)pos_x,
- (F32)getWindowHeightScaled() * -(F32)pos_y,
- 0.f);
- glScalef(zoom_factor, zoom_factor, 1.f);
- LLUI::sGLScaleFactor *= zoom_factor;
- }
-
- // Draw tool specific overlay on world
- LLToolMgr::getInstance()->getCurrentTool()->draw();
-
- if( gAgentCamera.cameraMouselook() || LLFloaterCamera::inFreeCameraMode() )
- {
- drawMouselookInstructions();
- stop_glerror();
- }
-
- // Draw all nested UI views.
- // No translation needed, this view is glued to 0,0
- mRootView->draw();
-
- if (LLView::sDebugRects)
- {
- gToolTipView->drawStickyRect();
- }
-
- // Draw optional on-top-of-everyone view
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- if (top_ctrl && top_ctrl->getVisible())
- {
- S32 screen_x, screen_y;
- top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y);
-
- glMatrixMode(GL_MODELVIEW);
- LLUI::pushMatrix();
- LLUI::translate( (F32) screen_x, (F32) screen_y, 0.f);
- top_ctrl->draw();
- LLUI::popMatrix();
- }
-
-
- if( gShowOverlayTitle && !mOverlayTitle.empty() )
- {
- // Used for special titles such as "Second Life - Special E3 2003 Beta"
- const S32 DIST_FROM_TOP = 20;
- LLFontGL::getFontSansSerifBig()->renderUTF8(
- mOverlayTitle, 0,
- llround( getWindowWidthScaled() * 0.5f),
- getWindowHeightScaled() - DIST_FROM_TOP,
- LLColor4(1, 1, 1, 0.4f),
- LLFontGL::HCENTER, LLFontGL::TOP);
- }
-
- LLUI::sGLScaleFactor = old_scale_factor;
- }
- LLUI::popMatrix();
- gGL.popMatrix();
-
-//#if LL_DEBUG
- LLView::sIsDrawing = FALSE;
-//#endif
-}
-
-// Takes a single keydown event, usually when UI is visible
-BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
-{
- // hide tooltips on keypress
- LLToolTipMgr::instance().blockToolTips();
-
- if (gFocusMgr.getKeyboardFocus()
- && !(mask & (MASK_CONTROL | MASK_ALT))
- && !gFocusMgr.getKeystrokesOnly())
- {
- // We have keyboard focus, and it's not an accelerator
- if (key < 0x80)
- {
- // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
- return (gFocusMgr.getKeyboardFocus() != NULL);
- }
- }
-
- // let menus handle navigation keys for navigation
- if ((gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE))
- ||(gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE))
- ||(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE)))
- {
- return TRUE;
- }
-
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
-
- // give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus
- // as long as focus isn't locked
- if (mask & (MASK_CONTROL | MASK_ALT) && !gFocusMgr.focusLocked())
- {
- // Check the current floater's menu first, if it has one.
- if (gFocusMgr.keyboardFocusHasAccelerators()
- && keyboard_focus
- && keyboard_focus->handleKey(key,mask,FALSE))
- {
- return TRUE;
- }
-
- if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
- ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
- {
- return TRUE;
- }
- }
-
- // give floaters first chance to handle TAB key
- // so frontmost floater gets focus
- // if nothing has focus, go to first or last UI element as appropriate
- if (key == KEY_TAB && (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL))
- {
- if (gMenuHolder) gMenuHolder->hideMenus();
-
- // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
- gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0);
-
- // do CTRL-TAB and CTRL-SHIFT-TAB logic
- if (mask & MASK_SHIFT)
- {
- mRootView->focusPrevRoot();
- }
- else
- {
- mRootView->focusNextRoot();
- }
- return TRUE;
- }
- // hidden edit menu for cut/copy/paste
- if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
- {
- return TRUE;
- }
-
- // Traverses up the hierarchy
- if( keyboard_focus )
- {
- LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL;
- // arrow keys move avatar while chatting hack
- if (chat_editor && chat_editor->hasFocus())
- {
- // If text field is empty, there's no point in trying to move
- // cursor with arrow keys, so allow movement
- if (chat_editor->getText().empty()
- || gSavedSettings.getBOOL("ArrowKeysAlwaysMove"))
- {
- // let Control-Up and Control-Down through for chat line history,
- if (!(key == KEY_UP && mask == MASK_CONTROL)
- && !(key == KEY_DOWN && mask == MASK_CONTROL))
- {
- switch(key)
- {
- case KEY_LEFT:
- case KEY_RIGHT:
- case KEY_UP:
- case KEY_DOWN:
- case KEY_PAGE_UP:
- case KEY_PAGE_DOWN:
- case KEY_HOME:
- // when chatbar is empty or ArrowKeysAlwaysMove set,
- // pass arrow keys on to avatar...
- return FALSE;
- default:
- break;
- }
- }
- }
- }
-
- if (keyboard_focus->handleKey(key, mask, FALSE))
- {
- return TRUE;
- }
- }
-
- if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) )
- {
- return TRUE;
- }
-
- // Try for a new-format gesture
- if (LLGestureMgr::instance().triggerGesture(key, mask))
- {
- return TRUE;
- }
-
- // See if this is a gesture trigger. If so, eat the key and
- // don't pass it down to the menus.
- if (gGestureList.trigger(key, mask))
- {
- return TRUE;
- }
-
- // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook,
- // no view has keyboard focus, this is a printable character key (and no modifier key is
- // pressed except shift), then give focus to nearby chat (STORM-560)
- if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() &&
- !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
- {
- LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL;
- if (chat_editor)
- {
- // passing NULL here, character will be added later when it is handled by character handler.
- LLBottomTray::getInstance()->getNearbyChatBar()->startChat(NULL);
- return TRUE;
- }
- }
-
- // give menus a chance to handle unmodified accelerator keys
- if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
- ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
- {
- return TRUE;
- }
-
- // don't pass keys on to world when something in ui has focus
- return gFocusMgr.childHasKeyboardFocus(mRootView)
- || LLMenuGL::getKeyboardMode()
- || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
-}
-
-
-BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
-{
- // HACK: We delay processing of return keys until they arrive as a Unicode char,
- // so that if you're typing chat text at low frame rate, we don't send the chat
- // until all keystrokes have been entered. JC
- // HACK: Numeric keypad <enter> on Mac is Unicode 3
- // HACK: Control-M on Windows is Unicode 13
- if ((uni_char == 13 && mask != MASK_CONTROL)
- || (uni_char == 3 && mask == MASK_NONE))
- {
- return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
- }
-
- // let menus handle navigation (jump) keys
- if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, TRUE))
- {
- return TRUE;
- }
-
- // Traverses up the hierarchy
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
- if( keyboard_focus )
- {
- if (keyboard_focus->handleUnicodeChar(uni_char, FALSE))
- {
- return TRUE;
- }
-
- //// Topmost view gets a chance before the hierarchy
- //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- //if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) )
- //{
- // return TRUE;
- //}
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-
-void LLViewerWindow::handleScrollWheel(S32 clicks)
-{
- LLView::sMouseHandlerMessage.clear();
-
- LLUI::resetMouseIdleTimer();
-
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- if( mouse_captor )
- {
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
- mouse_captor->handleScrollWheel(local_x, local_y, clicks);
- if (LLView::sDebugMouseHandling)
- {
- llinfos << "Scroll Wheel handled by captor " << mouse_captor->getName() << llendl;
- }
- return;
- }
-
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- if (top_ctrl)
- {
- S32 local_x;
- S32 local_y;
- top_ctrl->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
- if (top_ctrl->handleScrollWheel(local_x, local_y, clicks)) return;
- }
-
- if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) )
- {
- if (LLView::sDebugMouseHandling)
- {
- llinfos << "Scroll Wheel" << LLView::sMouseHandlerMessage << llendl;
- }
- return;
- }
- else if (LLView::sDebugMouseHandling)
- {
- llinfos << "Scroll Wheel not handled by view" << llendl;
- }
-
- // Zoom the camera in and out behavior
-
- if(top_ctrl == 0
- && getWorldViewRectScaled().pointInRect(mCurrentMousePoint.mX, mCurrentMousePoint.mY)
- && gAgentCamera.isInitialized())
- gAgentCamera.handleScrollWheel(clicks);
-
- return;
-}
-
-void LLViewerWindow::addPopup(LLView* popup)
-{
- if (mPopupView)
- {
- mPopupView->addPopup(popup);
- }
-}
-
-void LLViewerWindow::removePopup(LLView* popup)
-{
- if (mPopupView)
- {
- mPopupView->removePopup(popup);
- }
-}
-
-void LLViewerWindow::clearPopups()
-{
- if (mPopupView)
- {
- mPopupView->clearPopups();
- }
-}
-
-void LLViewerWindow::moveCursorToCenter()
-{
- if (! gSavedSettings.getBOOL("DisableMouseWarp"))
- {
- S32 x = getWorldViewWidthScaled() / 2;
- S32 y = getWorldViewHeightScaled() / 2;
-
- //on a forced move, all deltas get zeroed out to prevent jumping
- mCurrentMousePoint.set(x,y);
- mLastMousePoint.set(x,y);
- mCurrentMouseDelta.set(0,0);
-
- LLUI::setMousePositionScreen(x, y);
- }
-}
-
-
-//////////////////////////////////////////////////////////////////////
-//
-// Hover handlers
-//
-
-void append_xui_tooltip(LLView* viewp, LLToolTip::Params& params)
-{
- if (viewp)
- {
- if (!params.styled_message.empty())
- {
- params.styled_message.add().text("\n---------\n");
- }
- LLView::root_to_view_iterator_t end_tooltip_it = viewp->endRootToView();
- // NOTE: we skip "root" since it is assumed
- for (LLView::root_to_view_iterator_t tooltip_it = ++viewp->beginRootToView();
- tooltip_it != end_tooltip_it;
- ++tooltip_it)
- {
- LLView* viewp = *tooltip_it;
-
- params.styled_message.add().text(viewp->getName());
-
- LLPanel* panelp = dynamic_cast<LLPanel*>(viewp);
- if (panelp && !panelp->getXMLFilename().empty())
- {
- params.styled_message.add()
- .text("(" + panelp->getXMLFilename() + ")")
- .style.color(LLColor4(0.7f, 0.7f, 1.f, 1.f));
- }
- params.styled_message.add().text("/");
- }
- }
-}
-
-// Update UI based on stored mouse position from mouse-move
-// event processing.
-void LLViewerWindow::updateUI()
-{
- static LLFastTimer::DeclareTimer ftm("Update UI");
- LLFastTimer t(ftm);
-
- static std::string last_handle_msg;
-
- if (gLoggedInTime.getStarted())
- {
- if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("DestinationGuideHintTimeout"))
- {
- LLFirstUse::notUsingDestinationGuide();
- }
- if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("AvatarPickerHintTimeout"))
- {
- LLFirstUse::notUsingAvatarPicker();
- }
- if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("SidePanelHintTimeout"))
- {
- LLFirstUse::notUsingSidePanel();
- }
- }
-
- LLConsole::updateClass();
-
- // animate layout stacks so we have up to date rect for world view
- LLLayoutStack::updateClass();
-
- // use full window for world view when not rendering UI
- bool world_view_uses_full_window = gAgentCamera.cameraMouselook() || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
- updateWorldViewRect(world_view_uses_full_window);
-
- LLView::sMouseHandlerMessage.clear();
-
- S32 x = mCurrentMousePoint.mX;
- S32 y = mCurrentMousePoint.mY;
- MASK mask = gKeyboard->currentMask(TRUE);
-
- if (gNoRender)
- {
- return;
- }
-
- if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
- {
- gDebugRaycastFaceHit = -1;
- gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
- &gDebugRaycastFaceHit,
- &gDebugRaycastIntersection,
- &gDebugRaycastTexCoord,
- &gDebugRaycastNormal,
- &gDebugRaycastBinormal);
- }
-
- updateMouseDelta();
- updateKeyboardFocus();
-
- BOOL handled = FALSE;
-
- BOOL handled_by_top_ctrl = FALSE;
- LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
- LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
- LLView* captor_view = dynamic_cast<LLView*>(mouse_captor);
-
- //FIXME: only include captor and captor's ancestors if mouse is truly over them --RN
-
- //build set of views containing mouse cursor by traversing UI hierarchy and testing
- //screen rect against mouse cursor
- view_handle_set_t mouse_hover_set;
-
- // constraint mouse enter events to children of mouse captor
- LLView* root_view = captor_view;
-
- // if mouse captor doesn't exist or isn't a LLView
- // then allow mouse enter events on entire UI hierarchy
- if (!root_view)
- {
- root_view = mRootView;
- }
-
- // only update mouse hover set when UI is visible (since we shouldn't send hover events to invisible UI
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- // include all ancestors of captor_view as automatically having mouse
- if (captor_view)
- {
- LLView* captor_parent_view = captor_view->getParent();
- while(captor_parent_view)
- {
- mouse_hover_set.insert(captor_parent_view->getHandle());
- captor_parent_view = captor_parent_view->getParent();
- }
- }
-
- // aggregate visible views that contain mouse cursor in display order
- LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups();
-
- for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it)
- {
- LLView* popup = popup_it->get();
- if (popup && popup->calcScreenBoundingRect().pointInRect(x, y))
- {
- // iterator over contents of top_ctrl, and throw into mouse_hover_set
- for (LLView::tree_iterator_t it = popup->beginTreeDFS();
- it != popup->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- }
-
- // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
- if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))
- {
- // iterator over contents of top_ctrl, and throw into mouse_hover_set
- for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS();
- it != top_ctrl->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- else
- {
- // walk UI tree in depth-first order
- for (LLView::tree_iterator_t it = root_view->beginTreeDFS();
- it != root_view->endTreeDFS();
- ++it)
- {
- LLView* viewp = *it;
- // calculating the screen rect involves traversing the parent, so this is less than optimal
- if (viewp->getVisible()
- && viewp->calcScreenBoundingRect().pointInRect(x, y))
- {
-
- // if this view is mouse opaque, nothing behind it should be in mouse_hover_set
- if (viewp->getMouseOpaque())
- {
- // constrain further iteration to children of this widget
- it = viewp->beginTreeDFS();
- }
-
- // we have a view that contains the mouse, add it to the set
- mouse_hover_set.insert(viewp->getHandle());
- }
- else
- {
- // skip this view and all of its children
- it.skipDescendants();
- }
- }
- }
- }
-
- typedef std::vector<LLHandle<LLView> > view_handle_list_t;
-
- // call onMouseEnter() on all views which contain the mouse cursor but did not before
- view_handle_list_t mouse_enter_views;
- std::set_difference(mouse_hover_set.begin(), mouse_hover_set.end(),
- mMouseHoverViews.begin(), mMouseHoverViews.end(),
- std::back_inserter(mouse_enter_views));
- for (view_handle_list_t::iterator it = mouse_enter_views.begin();
- it != mouse_enter_views.end();
- ++it)
- {
- LLView* viewp = it->get();
- if (viewp)
- {
- LLRect view_screen_rect = viewp->calcScreenRect();
- viewp->onMouseEnter(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
- }
- }
-
- // call onMouseLeave() on all views which no longer contain the mouse cursor
- view_handle_list_t mouse_leave_views;
- std::set_difference(mMouseHoverViews.begin(), mMouseHoverViews.end(),
- mouse_hover_set.begin(), mouse_hover_set.end(),
- std::back_inserter(mouse_leave_views));
- for (view_handle_list_t::iterator it = mouse_leave_views.begin();
- it != mouse_leave_views.end();
- ++it)
- {
- LLView* viewp = it->get();
- if (viewp)
- {
- LLRect view_screen_rect = viewp->calcScreenRect();
- viewp->onMouseLeave(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
- }
- }
-
- // store resulting hover set for next frame
- swap(mMouseHoverViews, mouse_hover_set);
-
- // only handle hover events when UI is enabled
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
-
- if( mouse_captor )
- {
- // Pass hover events to object capturing mouse events.
- S32 local_x;
- S32 local_y;
- mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
- handled = mouse_captor->handleHover(local_x, local_y, mask);
- if (LLView::sDebugMouseHandling)
- {
- llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl;
- }
-
- if( !handled )
- {
- lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl;
- }
- }
- else
- {
- if (top_ctrl)
- {
- S32 local_x, local_y;
- top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
- handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask);
- handled_by_top_ctrl = TRUE;
- }
-
- if ( !handled )
- {
- // x and y are from last time mouse was in window
- // mMouseInWindow tracks *actual* mouse location
- if (mMouseInWindow && mRootView->handleHover(x, y, mask) )
- {
- if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg)
- {
- last_handle_msg = LLView::sMouseHandlerMessage;
- llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl;
- }
- handled = TRUE;
- }
- else if (LLView::sDebugMouseHandling)
- {
- if (last_handle_msg != LLStringUtil::null)
- {
- last_handle_msg.clear();
- llinfos << "Hover not handled by view" << llendl;
- }
- }
- }
-
- if (!handled)
- {
- LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
-
- if(mMouseInWindow && tool)
- {
- handled = tool->handleHover(x, y, mask);
- }
- }
- }
-
- // Show a new tool tip (or update one that is already shown)
- BOOL tool_tip_handled = FALSE;
- std::string tool_tip_msg;
- if( handled
- && !mWindow->isCursorHidden())
- {
- LLRect screen_sticky_rect = mRootView->getLocalRect();
- S32 local_x, local_y;
-
- if (gSavedSettings.getBOOL("DebugShowXUINames"))
- {
- LLToolTip::Params params;
-
- LLView* tooltip_view = mRootView;
- LLView::tree_iterator_t end_it = mRootView->endTreeDFS();
- for (LLView::tree_iterator_t it = mRootView->beginTreeDFS(); it != end_it; ++it)
- {
- LLView* viewp = *it;
- LLRect screen_rect;
- viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect);
- if (!(viewp->getVisible()
- && screen_rect.pointInRect(x, y)))
- {
- it.skipDescendants();
- }
- // only report xui names for LLUICtrls,
- // and blacklist the various containers we don't care about
- else if (dynamic_cast<LLUICtrl*>(viewp)
- && viewp != gMenuHolder
- && viewp != gFloaterView
- && viewp != gConsole)
- {
- if (dynamic_cast<LLFloater*>(viewp))
- {
- // constrain search to descendants of this (frontmost) floater
- // by resetting iterator
- it = viewp->beginTreeDFS();
- }
-
- // if we are in a new part of the tree (not a descendent of current tooltip_view)
- // then push the results for tooltip_view and start with a new potential view
- // NOTE: this emulates visiting only the leaf nodes that meet our criteria
- if (!viewp->hasAncestor(tooltip_view))
- {
- append_xui_tooltip(tooltip_view, params);
- screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
- }
- tooltip_view = viewp;
- }
- }
-
- append_xui_tooltip(tooltip_view, params);
- screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
-
- params.sticky_rect = screen_sticky_rect;
- params.max_width = 400;
-
- LLToolTipMgr::instance().show(params);
- }
- // if there is a mouse captor, nothing else gets a tooltip
- else if (mouse_captor)
- {
- mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask);
- }
- else
- {
- // next is top_ctrl
- if (!tool_tip_handled && top_ctrl)
- {
- top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask );
- }
-
- if (!tool_tip_handled)
- {
- local_x = x; local_y = y;
- tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask );
- }
-
- LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool();
- if (!tool_tip_handled && current_tool)
- {
- current_tool->screenPointToLocal(x, y, &local_x, &local_y);
- tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask );
- }
- }
- }
- }
- else
- { // just have tools handle hover when UI is turned off
- LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
-
- if(mMouseInWindow && tool)
- {
- handled = tool->handleHover(x, y, mask);
- }
- }
-
- updateLayout();
-
- mLastMousePoint = mCurrentMousePoint;
-
- // cleanup unused selections when no modal dialogs are open
- if (LLModalDialog::activeCount() == 0)
- {
- LLViewerParcelMgr::getInstance()->deselectUnused();
- }
-
- if (LLModalDialog::activeCount() == 0)
- {
- LLSelectMgr::getInstance()->deselectUnused();
- }
-}
-
-
-void LLViewerWindow::updateLayout()
-{
- LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
- if (gFloaterTools != NULL
- && tool != NULL
- && tool != gToolNull
- && tool != LLToolCompInspect::getInstance()
- && tool != LLToolDragAndDrop::getInstance()
- && !gSavedSettings.getBOOL("FreezeTime"))
- {
- // Suppress the toolbox view if our source tool was the pie tool,
- // and we've overridden to something else.
- bool suppress_toolbox =
- (LLToolMgr::getInstance()->getBaseTool() == LLToolPie::getInstance()) &&
- (LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance());
-
- LLMouseHandler *captor = gFocusMgr.getMouseCapture();
- // With the null, inspect, or drag and drop tool, don't muck
- // with visibility.
-
- if (gFloaterTools->isMinimized()
- || (tool != LLToolPie::getInstance() // not default tool
- && tool != LLToolCompGun::getInstance() // not coming out of mouselook
- && !suppress_toolbox // not override in third person
- && LLToolMgr::getInstance()->getCurrentToolset() != gFaceEditToolset // not special mode
- && LLToolMgr::getInstance()->getCurrentToolset() != gMouselookToolset
- && (!captor || dynamic_cast<LLView*>(captor) != NULL))) // not dragging
- {
- // Force floater tools to be visible (unless minimized)
- if (!gFloaterTools->getVisible())
- {
- gFloaterTools->openFloater();
- }
- // Update the location of the blue box tool popup
- LLCoordGL select_center_screen;
- gFloaterTools->updatePopup( select_center_screen, gKeyboard->currentMask(TRUE) );
- }
- else
- {
- gFloaterTools->setVisible(FALSE);
- }
- //gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible());
- }
-
- // Always update console
- if(gConsole)
- {
- LLRect console_rect = getChatConsoleRect();
- gConsole->reshape(console_rect.getWidth(), console_rect.getHeight());
- gConsole->setRect(console_rect);
- }
-}
-
-void LLViewerWindow::updateMouseDelta()
-{
- S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]);
- S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]);
-
- //RN: fix for asynchronous notification of mouse leaving window not working
- LLCoordWindow mouse_pos;
- mWindow->getCursorPosition(&mouse_pos);
- if (mouse_pos.mX < 0 ||
- mouse_pos.mY < 0 ||
- mouse_pos.mX > mWindowRectRaw.getWidth() ||
- mouse_pos.mY > mWindowRectRaw.getHeight())
- {
- mMouseInWindow = FALSE;
- }
- else
- {
- mMouseInWindow = TRUE;
- }
-
- LLVector2 mouse_vel;
-
- if (gSavedSettings.getBOOL("MouseSmooth"))
- {
- static F32 fdx = 0.f;
- static F32 fdy = 0.f;
-
- F32 amount = 16.f;
- fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f);
- fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f);
-
- mCurrentMouseDelta.set(llround(fdx), llround(fdy));
- mouse_vel.setVec(fdx,fdy);
- }
- else
- {
- mCurrentMouseDelta.set(dx, dy);
- mouse_vel.setVec((F32) dx, (F32) dy);
- }
-
- mMouseVelocityStat.addValue(mouse_vel.magVec());
-}
-
-void LLViewerWindow::updateKeyboardFocus()
-{
- if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- gFocusMgr.setKeyboardFocus(NULL);
- }
-
- // clean up current focus
- LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
- if (cur_focus)
- {
- if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain())
- {
- // don't release focus, just reassign so that if being given
- // to a sibling won't call onFocusLost on all the ancestors
- // gFocusMgr.releaseFocusIfNeeded(cur_focus);
-
- LLUICtrl* parent = cur_focus->getParentUICtrl();
- const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
- bool new_focus_found = false;
- while(parent)
- {
- if (parent->isCtrl()
- && (parent->hasTabStop() || parent == focus_root)
- && !parent->getIsChrome()
- && parent->isInVisibleChain()
- && parent->isInEnabledChain())
- {
- if (!parent->focusFirstItem())
- {
- parent->setFocus(TRUE);
- }
- new_focus_found = true;
- break;
- }
- parent = parent->getParentUICtrl();
- }
-
- // if we didn't find a better place to put focus, just release it
- // hasFocus() will return true if and only if we didn't touch focus since we
- // are only moving focus higher in the hierarchy
- if (!new_focus_found)
- {
- cur_focus->setFocus(FALSE);
- }
- }
- else if (cur_focus->isFocusRoot())
- {
- // focus roots keep trying to delegate focus to their first valid descendant
- // this assumes that focus roots are not valid focus holders on their own
- cur_focus->focusFirstItem();
- }
- }
-
- // last ditch force of edit menu to selection manager
- if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
- {
- LLEditMenuHandler::gEditMenuHandler = LLSelectMgr::getInstance();
- }
-
- if (gFloaterView->getCycleMode())
- {
- // sync all floaters with their focus state
- gFloaterView->highlightFocusedFloater();
- gSnapshotFloaterView->highlightFocusedFloater();
- if ((gKeyboard->currentMask(TRUE) & MASK_CONTROL) == 0)
- {
- // control key no longer held down, finish cycle mode
- gFloaterView->setCycleMode(FALSE);
-
- gFloaterView->syncFloaterTabOrder();
- }
- else
- {
- // user holding down CTRL, don't update tab order of floaters
- }
- }
- else
- {
- // update focused floater
- gFloaterView->highlightFocusedFloater();
- gSnapshotFloaterView->highlightFocusedFloater();
- // make sure floater visible order is in sync with tab order
- gFloaterView->syncFloaterTabOrder();
- }
-
- if(LLSideTray::instanceCreated())//just getInstance will create sidetray. we don't want this
- LLSideTray::getInstance()->highlightFocused();
-}
-
-static LLFastTimer::DeclareTimer FTM_UPDATE_WORLD_VIEW("Update World View");
-void LLViewerWindow::updateWorldViewRect(bool use_full_window)
-{
- LLFastTimer ft(FTM_UPDATE_WORLD_VIEW);
-
- // start off using whole window to render world
- LLRect new_world_rect = mWindowRectRaw;
-
- if (use_full_window == false && mWorldViewPlaceholder.get())
- {
- new_world_rect = mWorldViewPlaceholder.get()->calcScreenRect();
- // clamp to at least a 1x1 rect so we don't try to allocate zero width gl buffers
- new_world_rect.mTop = llmax(new_world_rect.mTop, new_world_rect.mBottom + 1);
- new_world_rect.mRight = llmax(new_world_rect.mRight, new_world_rect.mLeft + 1);
-
- new_world_rect.mLeft = llround((F32)new_world_rect.mLeft * mDisplayScale.mV[VX]);
- new_world_rect.mRight = llround((F32)new_world_rect.mRight * mDisplayScale.mV[VX]);
- new_world_rect.mBottom = llround((F32)new_world_rect.mBottom * mDisplayScale.mV[VY]);
- new_world_rect.mTop = llround((F32)new_world_rect.mTop * mDisplayScale.mV[VY]);
- }
-
- if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE)
- {
- // use right edge of window, ignoring sidebar
- new_world_rect.mRight = mWindowRectRaw.mRight;
- }
-
- if (mWorldViewRectRaw != new_world_rect)
- {
- mWorldViewRectRaw = new_world_rect;
- gResizeScreenTexture = TRUE;
- LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
- LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
-
- LLRect old_world_rect_scaled = mWorldViewRectScaled;
- mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
-
- // sending a signal with a new WorldView rect
- mOnWorldViewRectUpdated(old_world_rect_scaled, mWorldViewRectScaled);
- }
-}
-
-void LLViewerWindow::saveLastMouse(const LLCoordGL &point)
-{
- // Store last mouse location.
- // If mouse leaves window, pretend last point was on edge of window
- if (point.mX < 0)
- {
- mCurrentMousePoint.mX = 0;
- }
- else if (point.mX > getWindowWidthScaled())
- {
- mCurrentMousePoint.mX = getWindowWidthScaled();
- }
- else
- {
- mCurrentMousePoint.mX = point.mX;
- }
-
- if (point.mY < 0)
- {
- mCurrentMousePoint.mY = 0;
- }
- else if (point.mY > getWindowHeightScaled() )
- {
- mCurrentMousePoint.mY = getWindowHeightScaled();
- }
- else
- {
- mCurrentMousePoint.mY = point.mY;
- }
-}
-
-
-// Draws the selection outlines for the currently selected objects
-// Must be called after displayObjects is called, which sets the mGLName parameter
-// NOTE: This function gets called 3 times:
-// render_ui_3d: FALSE, FALSE, TRUE
-// render_hud_elements: FALSE, FALSE, FALSE
-void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL for_hud )
-{
- LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
-
- if (!for_hud && !for_gl_pick)
- {
- // Call this once and only once
- LLSelectMgr::getInstance()->updateSilhouettes();
- }
-
- // Draw fence around land selections
- if (for_gl_pick)
- {
- if (pick_parcel_walls)
- {
- LLViewerParcelMgr::getInstance()->renderParcelCollision();
- }
- }
- else if (( for_hud && selection->getSelectType() == SELECT_TYPE_HUD) ||
- (!for_hud && selection->getSelectType() != SELECT_TYPE_HUD))
- {
- LLSelectMgr::getInstance()->renderSilhouettes(for_hud);
-
- stop_glerror();
-
- // setup HUD render
- if (selection->getSelectType() == SELECT_TYPE_HUD && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
- {
- LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
-
- // set up transform to encompass bounding box of HUD
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
- glOrtho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth);
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- glLoadMatrixf(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame
- glTranslatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f);
- }
-
- // Render light for editing
- if (LLSelectMgr::sRenderLightRadius && LLToolMgr::getInstance()->inEdit())
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLEnable gls_blend(GL_BLEND);
- LLGLEnable gls_cull(GL_CULL_FACE);
- LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- if (selection->getSelectType() == SELECT_TYPE_HUD)
- {
- F32 zoom = gAgentCamera.mHUDCurZoom;
- glScalef(zoom, zoom, zoom);
- }
-
- struct f : public LLSelectedObjectFunctor
- {
- virtual bool apply(LLViewerObject* object)
- {
- LLDrawable* drawable = object->mDrawable;
- if (drawable && drawable->isLight())
- {
- LLVOVolume* vovolume = drawable->getVOVolume();
- glPushMatrix();
-
- LLVector3 center = drawable->getPositionAgent();
- glTranslatef(center[0], center[1], center[2]);
- F32 scale = vovolume->getLightRadius();
- glScalef(scale, scale, scale);
-
- LLColor4 color(vovolume->getLightColor(), .5f);
- glColor4fv(color.mV);
-
- F32 pixel_area = 100000.f;
- // Render Outside
- gSphere.render(pixel_area);
-
- // Render Inside
- glCullFace(GL_FRONT);
- gSphere.render(pixel_area);
- glCullFace(GL_BACK);
-
- glPopMatrix();
- }
- return true;
- }
- } func;
- LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func);
-
- glPopMatrix();
- }
-
- // NOTE: The average position for the axis arrows of the selected objects should
- // not be recalculated at this time. If they are, then group rotations will break.
-
- // Draw arrows at average center of all selected objects
- LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
- if (tool)
- {
- if(tool->isAlwaysRendered())
- {
- tool->render();
- }
- else
- {
- if( !LLSelectMgr::getInstance()->getSelection()->isEmpty() )
- {
- BOOL moveable_object_selected = FALSE;
- BOOL all_selected_objects_move = TRUE;
- BOOL all_selected_objects_modify = TRUE;
- BOOL selecting_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
-
- for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin();
- iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++)
- {
- LLSelectNode* nodep = *iter;
- LLViewerObject* object = nodep->getObject();
- BOOL this_object_movable = FALSE;
- if (object->permMove() && (object->permModify() || selecting_linked_set))
- {
- moveable_object_selected = TRUE;
- this_object_movable = TRUE;
- }
- all_selected_objects_move = all_selected_objects_move && this_object_movable;
- all_selected_objects_modify = all_selected_objects_modify && object->permModify();
- }
-
- BOOL draw_handles = TRUE;
-
- if (tool == LLToolCompTranslate::getInstance() && (!moveable_object_selected || !all_selected_objects_move))
- {
- draw_handles = FALSE;
- }
-
- if (tool == LLToolCompRotate::getInstance() && (!moveable_object_selected || !all_selected_objects_move))
- {
- draw_handles = FALSE;
- }
-
- if ( !all_selected_objects_modify && tool == LLToolCompScale::getInstance() )
- {
- draw_handles = FALSE;
- }
-
- if( draw_handles )
- {
- tool->render();
- }
- }
- }
- if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount())
- {
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
-
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- stop_glerror();
- }
- }
- }
-}
-
-// Return a point near the clicked object representative of the place the object was clicked.
-LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLViewerObject* clicked_object) const
-{
- // create a normalized vector pointing from the camera center into the
- // world at the location of the mouse click
- LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot );
-
- LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgentCamera.getCameraPositionGlobal();
-
- // make mouse vector as long as object vector, so it touchs a point near
- // where the user clicked on the object
- mouse_direction_global *= (F32) relative_object.magVec();
-
- LLVector3d new_pos;
- new_pos.setVec(mouse_direction_global);
- // transform mouse vector back to world coords
- new_pos += gAgentCamera.getCameraPositionGlobal();
-
- return new_pos;
-}
-
-
-BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const
-{
- BOOL intersect = FALSE;
-
-// U8 shape = objectp->mPrimitiveCode & LL_PCODE_BASE_MASK;
- if (!intersect)
- {
- point_global = clickPointInWorldGlobal(x, y, objectp);
- llinfos << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << llendl;
- }
- else
- {
- llinfos << "good intersection at " << (objectp->getPositionGlobal() - point_global) << llendl;
- }
-
- return intersect;
-}
-
-void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent)
-{
- if (gNoRender)
- {
- return;
- }
-
- BOOL in_build_mode = LLFloaterReg::instanceVisible("build");
- if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
- {
- // build mode allows interaction with all transparent objects
- // "Show Debug Alpha" means no object actually transparent
- pick_transparent = TRUE;
- }
-
- LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, TRUE, callback);
- schedulePick(pick_info);
-}
-
-void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
-{
- if (mPicks.size() >= 1024 || mWindow->getMinimized())
- { //something went wrong, picks are being scheduled but not processed
-
- if (pick_info.mPickCallback)
- {
- pick_info.mPickCallback(pick_info);
- }
-
- return;
- }
- mPicks.push_back(pick_info);
-
- // delay further event processing until we receive results of pick
- // only do this for async picks so that handleMouseUp won't be called
- // until the pick triggered in handleMouseDown has been processed, for example
- mWindow->delayInputProcessing();
-}
-
-
-void LLViewerWindow::performPick()
-{
- if (gNoRender)
- {
- return;
- }
-
- if (!mPicks.empty())
- {
- std::vector<LLPickInfo>::iterator pick_it;
- for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
- {
- pick_it->fetchResults();
- }
-
- mLastPick = mPicks.back();
- mPicks.clear();
- }
-}
-
-void LLViewerWindow::returnEmptyPicks()
-{
- std::vector<LLPickInfo>::iterator pick_it;
- for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
- {
- mLastPick = *pick_it;
- // just trigger callback with empty results
- if (pick_it->mPickCallback)
- {
- pick_it->mPickCallback(*pick_it);
- }
- }
- mPicks.clear();
-}
-
-// Performs the GL object/land pick.
-LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent)
-{
- if (gNoRender)
- {
- return LLPickInfo();
- }
-
- BOOL in_build_mode = LLFloaterReg::instanceVisible("build");
- if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
- {
- // build mode allows interaction with all transparent objects
- // "Show Debug Alpha" means no object actually transparent
- pick_transparent = TRUE;
- }
-
- // shortcut queueing in mPicks and just update mLastPick in place
- mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), gKeyboard->currentMask(TRUE), pick_transparent, TRUE, NULL);
- mLastPick.fetchResults();
-
- return mLastPick;
-}
-
-LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth,
- LLVector3* intersection)
-{
- S32 x = mouse_x;
- S32 y = mouse_y;
-
- if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
- {
- x = getCurrentMouseX();
- y = getCurrentMouseY();
- }
-
- // world coordinates of mouse
- LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
- LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
- LLVector3 mouse_world_start = mouse_point_global;
- LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
-
- return LLHUDIcon::lineSegmentIntersectAll(mouse_world_start, mouse_world_end, intersection);
-
-
-}
-
-LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 depth,
- LLViewerObject *this_object,
- S32 this_face,
- BOOL pick_transparent,
- S32* face_hit,
- LLVector3 *intersection,
- LLVector2 *uv,
- LLVector3 *normal,
- LLVector3 *binormal)
-{
- S32 x = mouse_x;
- S32 y = mouse_y;
-
- if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
- {
- x = getCurrentMouseX();
- y = getCurrentMouseY();
- }
-
- // HUD coordinates of mouse
- LLVector3 mouse_point_hud = mousePointHUD(x, y);
- LLVector3 mouse_hud_start = mouse_point_hud - LLVector3(depth, 0, 0);
- LLVector3 mouse_hud_end = mouse_point_hud + LLVector3(depth, 0, 0);
-
- // world coordinates of mouse
- LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
- LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
-
- //get near clip plane
- LLVector3 n = LLViewerCamera::getInstance()->getAtAxis();
- LLVector3 p = mouse_point_global + n * LLViewerCamera::getInstance()->getNear();
-
- //project mouse point onto plane
- LLVector3 pos;
- line_plane(mouse_point_global, mouse_direction_global, p, n, pos);
- mouse_point_global = pos;
-
- LLVector3 mouse_world_start = mouse_point_global;
- LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
-
-
- LLViewerObject* found = NULL;
-
- if (this_object) // check only this object
- {
- if (this_object->isHUDAttachment()) // is a HUD object?
- {
- if (this_object->lineSegmentIntersect(mouse_hud_start, mouse_hud_end, this_face, pick_transparent,
- face_hit, intersection, uv, normal, binormal))
- {
- found = this_object;
- }
- }
-
- else // is a world object
- {
- if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face, pick_transparent,
- face_hit, intersection, uv, normal, binormal))
- {
- found = this_object;
- }
- }
- }
-
- else // check ALL objects
- {
- found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end, pick_transparent,
- face_hit, intersection, uv, normal, binormal);
-
- if (!found) // if not found in HUD, look in world:
-
- {
- found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent,
- face_hit, intersection, uv, normal, binormal);
- }
-
- }
-
- return found;
-}
-
-// Returns unit vector relative to camera
-// indicating direction of point on screen x,y
-LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const
-{
- // find vertical field of view
- F32 fov = LLViewerCamera::getInstance()->getView();
-
- // find world view center in scaled ui coordinates
- F32 center_x = getWorldViewRectScaled().getCenterX();
- F32 center_y = getWorldViewRectScaled().getCenterY();
-
- // calculate pixel distance to screen
- F32 distance = ((F32)getWorldViewHeightScaled() * 0.5f) / (tan(fov / 2.f));
-
- // calculate click point relative to middle of screen
- F32 click_x = x - center_x;
- F32 click_y = y - center_y;
-
- // compute mouse vector
- LLVector3 mouse_vector = distance * LLViewerCamera::getInstance()->getAtAxis()
- - click_x * LLViewerCamera::getInstance()->getLeftAxis()
- + click_y * LLViewerCamera::getInstance()->getUpAxis();
-
- mouse_vector.normVec();
-
- return mouse_vector;
-}
-
-LLVector3 LLViewerWindow::mousePointHUD(const S32 x, const S32 y) const
-{
- // find screen resolution
- S32 height = getWorldViewHeightScaled();
-
- // find world view center
- F32 center_x = getWorldViewRectScaled().getCenterX();
- F32 center_y = getWorldViewRectScaled().getCenterY();
-
- // remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5
- F32 hud_x = -((F32)x - center_x) / height;
- F32 hud_y = ((F32)y - center_y) / height;
-
- return LLVector3(0.f, hud_x/gAgentCamera.mHUDCurZoom, hud_y/gAgentCamera.mHUDCurZoom);
-}
-
-// Returns unit vector relative to camera in camera space
-// indicating direction of point on screen x,y
-LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const
-{
- // find vertical field of view
- F32 fov_height = LLViewerCamera::getInstance()->getView();
- F32 fov_width = fov_height * LLViewerCamera::getInstance()->getAspect();
-
- // find screen resolution
- S32 height = getWorldViewHeightScaled();
- S32 width = getWorldViewWidthScaled();
-
- // find world view center
- F32 center_x = getWorldViewRectScaled().getCenterX();
- F32 center_y = getWorldViewRectScaled().getCenterY();
-
- // calculate click point relative to middle of screen
- F32 click_x = (((F32)x - center_x) / (F32)width) * fov_width * -1.f;
- F32 click_y = (((F32)y - center_y) / (F32)height) * fov_height;
-
- // compute mouse vector
- LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f);
- LLQuaternion mouse_rotate;
- mouse_rotate.setQuat(click_y, click_x, 0.f);
-
- mouse_vector = mouse_vector * mouse_rotate;
- // project to z = -1 plane;
- mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]);
-
- return mouse_vector;
-}
-
-
-
-BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y,
- const LLVector3d &plane_point_global,
- const LLVector3 &plane_normal_global)
-{
- LLVector3d mouse_direction_global_d;
-
- mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y));
- LLVector3d plane_normal_global_d;
- plane_normal_global_d.setVec(plane_normal_global);
- F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d);
- LLVector3d plane_origin_camera_rel = plane_point_global - gAgentCamera.getCameraPositionGlobal();
- F64 mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel)
- / plane_mouse_dot;
- if (llabs(plane_mouse_dot) < 0.00001)
- {
- // if mouse is parallel to plane, return closest point on line through plane origin
- // that is parallel to camera plane by scaling mouse direction vector
- // by distance to plane origin, modulated by deviation of mouse direction from plane origin
- LLVector3d plane_origin_dir = plane_origin_camera_rel;
- plane_origin_dir.normVec();
-
- mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d);
- }
-
- point = gAgentCamera.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d;
-
- return mouse_look_at_scale > 0.0;
-}
-
-
-// Returns global position
-BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global)
-{
- LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
- F32 mouse_dir_scale;
- BOOL hit_land = FALSE;
- LLViewerRegion *regionp;
- F32 land_z;
- const F32 FIRST_PASS_STEP = 1.0f; // meters
- const F32 SECOND_PASS_STEP = 0.1f; // meters
- LLVector3d camera_pos_global;
-
- camera_pos_global = gAgentCamera.getCameraPositionGlobal();
- LLVector3d probe_point_global;
- LLVector3 probe_point_region;
-
- // walk forwards to find the point
- for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < gAgentCamera.mDrawDistance; mouse_dir_scale += FIRST_PASS_STEP)
- {
- LLVector3d mouse_direction_global_d;
- mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
- probe_point_global = camera_pos_global + mouse_direction_global_d;
-
- regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
-
- if (!regionp)
- {
- // ...we're outside the world somehow
- continue;
- }
-
- S32 i = (S32) (probe_point_region.mV[VX]/regionp->getLand().getMetersPerGrid());
- S32 j = (S32) (probe_point_region.mV[VY]/regionp->getLand().getMetersPerGrid());
- S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge;
- if ((i >= grids_per_edge) || (j >= grids_per_edge))
- {
- //llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
- continue;
- }
-
- land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
-
- //llinfos << "mousePointOnLand initial z " << land_z << llendl;
-
- if (probe_point_region.mV[VZ] < land_z)
- {
- // ...just went under land
-
- // cout << "under land at " << probe_point << " scale " << mouse_vec_scale << endl;
-
- hit_land = TRUE;
- break;
- }
- }
-
-
- if (hit_land)
- {
- // Don't go more than one step beyond where we stopped above.
- // This can't just be "mouse_vec_scale" because floating point error
- // will stop the loop before the last increment.... X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X
- F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP;
-
- // take a step backwards, then walk forwards again to refine position
- for ( mouse_dir_scale -= FIRST_PASS_STEP; mouse_dir_scale <= stop_mouse_dir_scale; mouse_dir_scale += SECOND_PASS_STEP)
- {
- LLVector3d mouse_direction_global_d;
- mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
- probe_point_global = camera_pos_global + mouse_direction_global_d;
-
- regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
-
- if (!regionp)
- {
- // ...we're outside the world somehow
- continue;
- }
-
- /*
- i = (S32) (local_probe_point.mV[VX]/regionp->getLand().getMetersPerGrid());
- j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid());
- if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge))
- {
- // llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
- continue;
- }
- land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ];
- */
-
- land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
-
- //llinfos << "mousePointOnLand refine z " << land_z << llendl;
-
- if (probe_point_region.mV[VZ] < land_z)
- {
- // ...just went under land again
-
- *land_position_global = probe_point_global;
- return TRUE;
- }
- }
- }
-
- return FALSE;
-}
-
-// Saves an image to the harddrive as "SnapshotX" where X >= 1.
-BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image)
-{
- if (!image)
- {
- return FALSE;
- }
-
- LLFilePicker::ESaveFilter pick_type;
- std::string extension("." + image->getExtension());
- if (extension == ".j2c")
- pick_type = LLFilePicker::FFSAVE_J2C;
- else if (extension == ".bmp")
- pick_type = LLFilePicker::FFSAVE_BMP;
- else if (extension == ".jpg")
- pick_type = LLFilePicker::FFSAVE_JPEG;
- else if (extension == ".png")
- pick_type = LLFilePicker::FFSAVE_PNG;
- else if (extension == ".tga")
- pick_type = LLFilePicker::FFSAVE_TGA;
- else
- pick_type = LLFilePicker::FFSAVE_ALL; // ???
-
- // Get a base file location if needed.
- if ( ! isSnapshotLocSet())
- {
- std::string proposed_name( sSnapshotBaseName );
-
- // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in.
-
- // pick a directory in which to save
- LLFilePicker& picker = LLFilePicker::instance();
- if (!picker.getSaveFile(pick_type, proposed_name))
- {
- // Clicked cancel
- return FALSE;
- }
-
- // Copy the directory + file name
- std::string filepath = picker.getFirstFile();
-
- LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true);
- LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath);
- }
-
- // Look for an unused file name
- std::string filepath;
- S32 i = 1;
- S32 err = 0;
-
- do
- {
- filepath = sSnapshotDir;
- filepath += gDirUtilp->getDirDelimiter();
- filepath += sSnapshotBaseName;
- filepath += llformat("_%.3d",i);
- filepath += extension;
-
- llstat stat_info;
- err = LLFile::stat( filepath, &stat_info );
- i++;
- }
- while( -1 != err ); // search until the file is not found (i.e., stat() gives an error).
-
- return image->save(filepath);
-}
-
-void LLViewerWindow::resetSnapshotLoc()
-{
- sSnapshotDir.clear();
-}
-
-static S32 BORDERHEIGHT = 0;
-static S32 BORDERWIDTH = 0;
-
-// static
-void LLViewerWindow::movieSize(S32 new_width, S32 new_height)
-{
- LLCoordScreen size;
- gViewerWindow->mWindow->getSize(&size);
- if ( (size.mX != new_width + BORDERWIDTH)
- ||(size.mY != new_height + BORDERHEIGHT))
- {
- // use actual display dimensions, not virtual UI dimensions
- S32 x = gViewerWindow->getWindowWidthRaw();
- S32 y = gViewerWindow->getWindowHeightRaw();
- BORDERWIDTH = size.mX - x;
- BORDERHEIGHT = size.mY- y;
- LLCoordScreen new_size(new_width + BORDERWIDTH,
- new_height + BORDERHEIGHT);
- gViewerWindow->mWindow->setSize(new_size);
- }
-}
-
-BOOL LLViewerWindow::saveSnapshot( const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
-{
- llinfos << "Saving snapshot to: " << filepath << llendl;
-
- LLPointer<LLImageRaw> raw = new LLImageRaw;
- BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild);
-
- if (success)
- {
- LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
- success = bmp_image->encode(raw, 0.0f);
- if( success )
- {
- success = bmp_image->save(filepath);
- }
- else
- {
- llwarns << "Unable to encode bmp snapshot" << llendl;
- }
- }
- else
- {
- llwarns << "Unable to capture raw snapshot" << llendl;
- }
-
- return success;
-}
-
-
-void LLViewerWindow::playSnapshotAnimAndSound()
-{
- if (gSavedSettings.getBOOL("QuietSnapshotsToDisk"))
- {
- return;
- }
- gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START);
- send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f);
-}
-
-BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
-{
- return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type);
-}
-
-// Saves the image from the screen to the specified filename and path.
-BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height,
- BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size)
-{
- if (!raw)
- {
- return FALSE;
- }
-
- // PRE SNAPSHOT
- gDisplaySwapBuffers = FALSE;
-
- glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
- setCursor(UI_CURSOR_WAIT);
-
- // Hide all the UI widgets first and draw a frame
- BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE;
-
- show_ui = show_ui ? TRUE : FALSE;
-
- if ( prev_draw_ui != show_ui)
- {
- LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
-
- BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments;
- if (hide_hud)
- {
- LLPipeline::sShowHUDAttachments = FALSE;
- }
-
- // if not showing ui, use full window to render world view
- updateWorldViewRect(!show_ui);
-
- // Copy screen to a buffer
- // crop sides or top and bottom, if taking a snapshot of different aspect ratio
- // from window
- LLRect window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw();
-
- S32 snapshot_width = window_rect.getWidth();
- S32 snapshot_height = window_rect.getHeight();
- // SNAPSHOT
- S32 window_width = snapshot_width;
- S32 window_height = snapshot_height;
-
- if (show_ui)
- {
- image_width = llmin(image_width, window_width);
- image_height = llmin(image_height, window_height);
- }
-
- F32 scale_factor = 1.0f ;
- if(!keep_window_aspect) //image cropping
- {
- F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
- snapshot_width = (S32)(ratio * image_width) ;
- snapshot_height = (S32)(ratio * image_height) ;
- scale_factor = llmax(1.0f, 1.0f / ratio) ;
- }
- else //the scene(window) proportion needs to be maintained.
- {
- if(image_width > window_width || image_height > window_height) //need to enlarge the scene
- {
- F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
- snapshot_width = (S32)(ratio * image_width) ;
- snapshot_height = (S32)(ratio * image_height) ;
- scale_factor = llmax(1.0f, 1.0f / ratio) ;
- }
- }
-
- if (show_ui && scale_factor > 1.f)
- {
- llwarns << "over scaling UI not supported." << llendl;
- }
-
- S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
- S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
-
- S32 image_buffer_x = llfloor(snapshot_width*scale_factor) ;
- S32 image_buffer_y = llfloor(snapshot_height *scale_factor) ;
-
- if(image_buffer_x > max_size || image_buffer_y > max_size) //boundary check to avoid memory overflow
- {
- scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ;
- image_buffer_x = llfloor(snapshot_width*scale_factor) ;
- image_buffer_y = llfloor(snapshot_height *scale_factor) ;
- }
- if(image_buffer_x > 0 && image_buffer_y > 0)
- {
- raw->resize(image_buffer_x, image_buffer_y, 3);
- }
- else
- {
- return FALSE ;
- }
- if(raw->isBufferInvalid())
- {
- return FALSE ;
- }
-
- BOOL high_res = scale_factor >= 2.f; // Font scaling is slow, only do so if rez is much higher
- if (high_res && show_ui)
- {
- llwarns << "High res UI snapshot not supported. " << llendl;
- /*send_agent_pause();
- //rescale fonts
- initFonts(scale_factor);
- LLHUDObject::reshapeAll();*/
- }
-
- S32 output_buffer_offset_y = 0;
-
- F32 depth_conversion_factor_1 = (LLViewerCamera::getInstance()->getFar() + LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
- F32 depth_conversion_factor_2 = (LLViewerCamera::getInstance()->getFar() - LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
-
- gObjectList.generatePickList(*LLViewerCamera::getInstance());
-
- for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
- {
- S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);;
- // handle fractional columns
- U32 read_height = llmax(0, (window_height - subimage_y_offset) -
- llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight())));
-
- S32 output_buffer_offset_x = 0;
- for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x)
- {
- gDisplaySwapBuffers = FALSE;
- gDepthDirty = TRUE;
-
- const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor));
-
- if (LLPipeline::sRenderDeferred)
- {
- display(do_rebuild, scale_factor, subfield, TRUE);
- }
- else
- {
- display(do_rebuild, scale_factor, subfield, TRUE);
- // Required for showing the GUI in snapshots and performing bloom composite overlay
- // Call even if show_ui is FALSE
- render_ui(scale_factor, subfield);
- }
-
- S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
- // handle fractional rows
- U32 read_width = llmax(0, (window_width - subimage_x_offset) -
- llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth())));
- for(U32 out_y = 0; out_y < read_height ; out_y++)
- {
- S32 output_buffer_offset = (
- (out_y * (raw->getWidth())) // ...plus iterated y...
- + (window_width * subimage_x) // ...plus subimage start in x...
- + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
- - output_buffer_offset_x // ...minus buffer padding x...
- - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y...
- ) * raw->getComponents();
-
- // Ping the wathdog thread every 100 lines to keep us alive (arbitrary number, feel free to change)
- if (out_y % 100 == 0)
- {
- LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot");
- }
-
- if (type == SNAPSHOT_TYPE_COLOR)
- {
- glReadPixels(
- subimage_x_offset, out_y + subimage_y_offset,
- read_width, 1,
- GL_RGB, GL_UNSIGNED_BYTE,
- raw->getData() + output_buffer_offset
- );
- }
- else // SNAPSHOT_TYPE_DEPTH
- {
- LLPointer<LLImageRaw> depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values
- glReadPixels(
- subimage_x_offset, out_y + subimage_y_offset,
- read_width, 1,
- GL_DEPTH_COMPONENT, GL_FLOAT,
- depth_line_buffer->getData()// current output pixel is beginning of buffer...
- );
-
- for (S32 i = 0; i < (S32)read_width; i++)
- {
- F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32)));
-
- F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2));
- U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar());
- //write converted scanline out to result image
- for(S32 j = 0; j < raw->getComponents(); j++)
- {
- *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte;
- }
- }
- }
- }
- output_buffer_offset_x += subimage_x_offset;
- stop_glerror();
- }
- output_buffer_offset_y += subimage_y_offset;
- }
-
- gDisplaySwapBuffers = FALSE;
- gDepthDirty = TRUE;
-
- // POST SNAPSHOT
- if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
- }
-
- if (hide_hud)
- {
- LLPipeline::sShowHUDAttachments = TRUE;
- }
-
- /*if (high_res)
- {
- initFonts(1.f);
- LLHUDObject::reshapeAll();
- }*/
-
- // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
- // Note: this formula depends on the number of components being 3. Not obvious, but it's correct.
- image_width += (image_width * 3) % 4;
-
- BOOL ret = TRUE ;
- // Resize image
- if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4)
- {
- ret = raw->scale( image_width, image_height );
- }
- else if(image_width != image_buffer_x || image_height != image_buffer_y)
- {
- ret = raw->scale( image_width, image_height, FALSE );
- }
-
-
- setCursor(UI_CURSOR_ARROW);
-
- if (do_rebuild)
- {
- // If we had to do a rebuild, that means that the lists of drawables to be rendered
- // was empty before we started.
- // Need to reset these, otherwise we call state sort on it again when render gets called the next time
- // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of
- // objects on them.
- gPipeline.resetDrawOrders();
- }
-
- if (high_res)
- {
- send_agent_resume();
- }
-
- return ret;
-}
-
-void LLViewerWindow::destroyWindow()
-{
- if (mWindow)
- {
- LLWindowManager::destroyWindow(mWindow);
- }
- mWindow = NULL;
-}
-
-
-void LLViewerWindow::drawMouselookInstructions()
-{
- // Draw instructions for mouselook ("Press ESC to return to World View" partially transparent at the bottom of the screen.)
- const std::string instructions = LLTrans::getString("LeaveMouselook");
- const LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Large", LLFontGL::BOLD));
-
- //to be on top of Bottom bar when it is opened
- const S32 INSTRUCTIONS_PAD = 50;
-
- font->renderUTF8(
- instructions, 0,
- getWorldViewRectScaled().getCenterX(),
- getWorldViewRectScaled().mBottom + INSTRUCTIONS_PAD,
- LLColor4( 1.0f, 1.0f, 1.0f, 0.5f ),
- LLFontGL::HCENTER, LLFontGL::TOP,
- LLFontGL::NORMAL,LLFontGL::DROP_SHADOW);
-}
-
-void* LLViewerWindow::getPlatformWindow() const
-{
- return mWindow->getPlatformWindow();
-}
-
-void* LLViewerWindow::getMediaWindow() const
-{
- return mWindow->getMediaWindow();
-}
-
-void LLViewerWindow::focusClient() const
-{
- return mWindow->focusClient();
-}
-
-LLRootView* LLViewerWindow::getRootView() const
-{
- return mRootView;
-}
-
-LLRect LLViewerWindow::getWorldViewRectScaled() const
-{
- return mWorldViewRectScaled;
-}
-
-S32 LLViewerWindow::getWorldViewHeightScaled() const
-{
- return mWorldViewRectScaled.getHeight();
-}
-
-S32 LLViewerWindow::getWorldViewWidthScaled() const
-{
- return mWorldViewRectScaled.getWidth();
-}
-
-
-S32 LLViewerWindow::getWorldViewHeightRaw() const
-{
- return mWorldViewRectRaw.getHeight();
-}
-
-S32 LLViewerWindow::getWorldViewWidthRaw() const
-{
- return mWorldViewRectRaw.getWidth();
-}
-
-S32 LLViewerWindow::getWindowHeightScaled() const
-{
- return mWindowRectScaled.getHeight();
-}
-
-S32 LLViewerWindow::getWindowWidthScaled() const
-{
- return mWindowRectScaled.getWidth();
-}
-
-S32 LLViewerWindow::getWindowHeightRaw() const
-{
- return mWindowRectRaw.getHeight();
-}
-
-S32 LLViewerWindow::getWindowWidthRaw() const
-{
- return mWindowRectRaw.getWidth();
-}
-
-void LLViewerWindow::setup2DRender()
-{
- // setup ortho camera
- gl_state_for_2d(mWindowRectRaw.getWidth(), mWindowRectRaw.getHeight());
- setup2DViewport();
-}
-
-void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset)
-{
- gGLViewport[0] = mWindowRectRaw.mLeft + x_offset;
- gGLViewport[1] = mWindowRectRaw.mBottom + y_offset;
- gGLViewport[2] = mWindowRectRaw.getWidth();
- gGLViewport[3] = mWindowRectRaw.getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-}
-
-
-void LLViewerWindow::setup3DRender()
-{
- // setup perspective camera
- LLViewerCamera::getInstance()->setPerspective(NOT_FOR_SELECTION, mWorldViewRectRaw.mLeft, mWorldViewRectRaw.mBottom, mWorldViewRectRaw.getWidth(), mWorldViewRectRaw.getHeight(), FALSE, LLViewerCamera::getInstance()->getNear(), MAX_FAR_CLIP*2.f);
- setup3DViewport();
-}
-
-void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
-{
- gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
- gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
- gGLViewport[2] = mWorldViewRectRaw.getWidth();
- gGLViewport[3] = mWorldViewRectRaw.getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-}
-
-void LLViewerWindow::setShowProgress(const BOOL show)
-{
- if (mProgressView)
- {
- mProgressView->setVisible(show);
- }
-}
-
-BOOL LLViewerWindow::getShowProgress() const
-{
- return (mProgressView && mProgressView->getVisible());
-}
-
-void LLViewerWindow::setProgressString(const std::string& string)
-{
- if (mProgressView)
- {
- mProgressView->setText(string);
- }
-}
-
-void LLViewerWindow::setProgressMessage(const std::string& msg)
-{
- if(mProgressView)
- {
- mProgressView->setMessage(msg);
- }
-}
-
-void LLViewerWindow::setProgressPercent(const F32 percent)
-{
- if (mProgressView)
- {
- mProgressView->setPercent(percent);
- }
-}
-
-void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string& label )
-{
- if (mProgressView)
- {
- mProgressView->setCancelButtonVisible( b, label );
- }
-}
-
-
-LLProgressView *LLViewerWindow::getProgressView() const
-{
- return mProgressView;
-}
-
-void LLViewerWindow::dumpState()
-{
- llinfos << "LLViewerWindow Active " << S32(mActive) << llendl;
- llinfos << "mWindow visible " << S32(mWindow->getVisible())
- << " minimized " << S32(mWindow->getMinimized())
- << llendl;
-}
-
-void LLViewerWindow::stopGL(BOOL save_state)
-{
- //Note: --bao
- //if not necessary, do not change the order of the function calls in this function.
- //if change something, make sure it will not break anything.
- //especially be careful to put anything behind gTextureList.destroyGL(save_state);
- if (!gGLManager.mIsDisabled)
- {
- llinfos << "Shutting down GL..." << llendl;
-
- // Pause texture decode threads (will get unpaused during main loop)
- LLAppViewer::getTextureCache()->pause();
- LLAppViewer::getImageDecodeThread()->pause();
- LLAppViewer::getTextureFetch()->pause();
-
- gSky.destroyGL();
- stop_glerror();
-
- LLManipTranslate::destroyGL() ;
- stop_glerror();
-
- gBumpImageList.destroyGL();
- stop_glerror();
-
- LLFontGL::destroyAllGL();
- stop_glerror();
-
- LLVOAvatar::destroyGL();
- stop_glerror();
-
- LLViewerDynamicTexture::destroyGL();
- stop_glerror();
-
- if (gPipeline.isInit())
- {
- gPipeline.destroyGL();
- }
-
- gCone.cleanupGL();
- gBox.cleanupGL();
- gSphere.cleanupGL();
- gCylinder.cleanupGL();
-
- if(gPostProcess)
- {
- gPostProcess->invalidate();
- }
-
- gTextureList.destroyGL(save_state);
- stop_glerror();
-
- gGLManager.mIsDisabled = TRUE;
- stop_glerror();
-
- llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemoryInBytes << " bytes" << llendl;
- }
-}
-
-void LLViewerWindow::restoreGL(const std::string& progress_message)
-{
- //Note: --bao
- //if not necessary, do not change the order of the function calls in this function.
- //if change something, make sure it will not break anything.
- //especially, be careful to put something before gTextureList.restoreGL();
- if (gGLManager.mIsDisabled)
- {
- llinfos << "Restoring GL..." << llendl;
- gGLManager.mIsDisabled = FALSE;
-
- initGLDefaults();
- LLGLState::restoreGL();
-
- gTextureList.restoreGL();
-
- // for future support of non-square pixels, and fonts that are properly stretched
- //LLFontGL::destroyDefaultFonts();
- initFonts();
-
- gSky.restoreGL();
- gPipeline.restoreGL();
- LLDrawPoolWater::restoreGL();
- LLManipTranslate::restoreGL();
-
- gBumpImageList.restoreGL();
- LLViewerDynamicTexture::restoreGL();
- LLVOAvatar::restoreGL();
-
- gResizeScreenTexture = TRUE;
- gWindowResized = TRUE;
-
- if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures())
- {
- LLVisualParamHint::requestHintUpdates();
- }
-
- if (!progress_message.empty())
- {
- gRestoreGLTimer.reset();
- gRestoreGL = TRUE;
- setShowProgress(TRUE);
- setProgressString(progress_message);
- }
- llinfos << "...Restoring GL done" << llendl;
- if(!LLAppViewer::instance()->restoreErrorTrap())
- {
- llwarns << " Someone took over my signal/exception handler (post restoreGL)!" << llendl;
- }
-
- }
-}
-
-void LLViewerWindow::initFonts(F32 zoom_factor)
-{
- LLFontGL::destroyAllGL();
- // Initialize with possibly different zoom factor
- LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
- mDisplayScale.mV[VX] * zoom_factor,
- mDisplayScale.mV[VY] * zoom_factor,
- gDirUtilp->getAppRODataDir(),
- LLUI::getXUIPaths());
- // Force font reloads, which can be very slow
- LLFontGL::loadDefaultFonts();
-}
-
-void LLViewerWindow::requestResolutionUpdate()
-{
- mResDirty = true;
-}
-
-void LLViewerWindow::checkSettings()
-{
- if (mStatesDirty)
- {
- gGL.refreshState();
- LLViewerShaderMgr::instance()->setShaders();
- mStatesDirty = false;
- }
-
- // We want to update the resolution AFTER the states getting refreshed not before.
- if (mResDirty)
- {
- reshape(getWindowWidthRaw(), getWindowHeightRaw());
- mResDirty = false;
- }
-}
-
-void LLViewerWindow::restartDisplay(BOOL show_progress_bar)
-{
- llinfos << "Restaring GL" << llendl;
- stopGL();
- if (show_progress_bar)
- {
- restoreGL(LLTrans::getString("ProgressChangingResolution"));
- }
- else
- {
- restoreGL();
- }
-}
-
-BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar)
-{
- //BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized");
-
- //gResizeScreenTexture = TRUE;
-
- //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
- //U32 old_fsaa = mWindow->getFSAASamples();
-
- // if not maximized, use the request size
- if (!mWindow->getMaximized())
- {
- mWindow->setSize(size);
- }
-
- //if (fsaa == old_fsaa)
- {
- return TRUE;
- }
-
-/*
-
- // Close floaters that don't handle settings change
- LLFloaterReg::hideInstance("snapshot");
-
- BOOL result_first_try = FALSE;
- BOOL result_second_try = FALSE;
-
- LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
- send_agent_pause();
- llinfos << "Stopping GL during changeDisplaySettings" << llendl;
- stopGL();
- mIgnoreActivate = TRUE;
- LLCoordScreen old_size;
- LLCoordScreen old_pos;
- mWindow->getSize(&old_size);
-
- //mWindow->setFSAASamples(fsaa);
-
- result_first_try = mWindow->switchContext(false, size, disable_vsync);
- if (!result_first_try)
- {
- // try to switch back
- //mWindow->setFSAASamples(old_fsaa);
- result_second_try = mWindow->switchContext(false, old_size, disable_vsync);
-
- if (!result_second_try)
- {
- // we are stuck...try once again with a minimal resolution?
- send_agent_resume();
- mIgnoreActivate = FALSE;
- return FALSE;
- }
- }
- send_agent_resume();
-
- llinfos << "Restoring GL during resolution change" << llendl;
- if (show_progress_bar)
- {
- restoreGL(LLTrans::getString("ProgressChangingResolution"));
- }
- else
- {
- restoreGL();
- }
-
- if (!result_first_try)
- {
- LLSD args;
- args["RESX"] = llformat("%d",size.mX);
- args["RESY"] = llformat("%d",size.mY);
- LLNotificationsUtil::add("ResolutionSwitchFail", args);
- size = old_size; // for reshape below
- }
-
- BOOL success = result_first_try || result_second_try;
-
- if (success)
- {
- // maximize window if was maximized, else reposition
- if (was_maximized)
- {
- mWindow->maximize();
- }
- else
- {
- S32 windowX = gSavedSettings.getS32("WindowX");
- S32 windowY = gSavedSettings.getS32("WindowY");
-
- mWindow->setPosition(LLCoordScreen ( windowX, windowY ) );
- }
- }
-
- mIgnoreActivate = FALSE;
- gFocusMgr.setKeyboardFocus(keyboard_focus);
-
- return success;
-
- */
-}
-
-F32 LLViewerWindow::getWorldViewAspectRatio() const
-{
- F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight();
- return world_aspect;
-}
-
-void LLViewerWindow::calcDisplayScale()
-{
- F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
- LLVector2 display_scale;
- display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
- display_scale *= ui_scale_factor;
-
- // limit minimum display scale
- if (display_scale.mV[VX] < MIN_DISPLAY_SCALE || display_scale.mV[VY] < MIN_DISPLAY_SCALE)
- {
- display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX], display_scale.mV[VY]);
- }
-
- if (display_scale != mDisplayScale)
- {
- llinfos << "Setting display scale to " << display_scale << llendl;
-
- mDisplayScale = display_scale;
- // Init default fonts
- initFonts();
- }
-}
-
-//static
-LLRect LLViewerWindow::calcScaledRect(const LLRect & rect, const LLVector2& display_scale)
-{
- LLRect res = rect;
- res.mLeft = llround((F32)res.mLeft / display_scale.mV[VX]);
- res.mRight = llround((F32)res.mRight / display_scale.mV[VX]);
- res.mBottom = llround((F32)res.mBottom / display_scale.mV[VY]);
- res.mTop = llround((F32)res.mTop / display_scale.mV[VY]);
-
- return res;
-}
-
-S32 LLViewerWindow::getChatConsoleBottomPad()
-{
- S32 offset = 0;
-
- if(LLBottomTray::instanceExists())
- offset += LLBottomTray::getInstance()->getRect().getHeight();
-
- return offset;
-}
-
-LLRect LLViewerWindow::getChatConsoleRect()
-{
- LLRect full_window(0, getWindowHeightScaled(), getWindowWidthScaled(), 0);
- LLRect console_rect = full_window;
-
- const S32 CONSOLE_PADDING_TOP = 24;
- const S32 CONSOLE_PADDING_LEFT = 24;
- const S32 CONSOLE_PADDING_RIGHT = 10;
-
- console_rect.mTop -= CONSOLE_PADDING_TOP;
- console_rect.mBottom += getChatConsoleBottomPad();
-
- console_rect.mLeft += CONSOLE_PADDING_LEFT;
-
- static const BOOL CHAT_FULL_WIDTH = gSavedSettings.getBOOL("ChatFullWidth");
-
- if (CHAT_FULL_WIDTH)
- {
- console_rect.mRight -= CONSOLE_PADDING_RIGHT;
- }
- else
- {
- // Make console rect somewhat narrow so having inventory open is
- // less of a problem.
- console_rect.mRight = console_rect.mLeft + 2 * getWindowWidthScaled() / 3;
- }
-
- return console_rect;
-}
-//----------------------------------------------------------------------------
-
-
-//static
-bool LLViewerWindow::onAlert(const LLSD& notify)
-{
- LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
-
- if (gNoRender)
- {
- llinfos << "Alert: " << notification->getName() << llendl;
- notification->respond(LLSD::emptyMap());
- LLNotifications::instance().cancel(notification);
- return false;
- }
-
- // If we're in mouselook, the mouse is hidden and so the user can't click
- // the dialog buttons. In that case, change to First Person instead.
- if( gAgentCamera.cameraMouselook() )
- {
- gAgentCamera.changeCameraToDefault();
- }
- return false;
-}
-
-////////////////////////////////////////////////////////////////////////////
-//
-// LLPickInfo
-//
-LLPickInfo::LLPickInfo()
- : mKeyMask(MASK_NONE),
- mPickCallback(NULL),
- mPickType(PICK_INVALID),
- mWantSurfaceInfo(FALSE),
- mObjectFace(-1),
- mUVCoords(-1.f, -1.f),
- mSTCoords(-1.f, -1.f),
- mXYCoords(-1, -1),
- mIntersection(),
- mNormal(),
- mBinormal(),
- mHUDIcon(NULL),
- mPickTransparent(FALSE)
-{
-}
-
-LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
- MASK keyboard_mask,
- BOOL pick_transparent,
- BOOL pick_uv_coords,
- void (*pick_callback)(const LLPickInfo& pick_info))
- : mMousePt(mouse_pos),
- mKeyMask(keyboard_mask),
- mPickCallback(pick_callback),
- mPickType(PICK_INVALID),
- mWantSurfaceInfo(pick_uv_coords),
- mObjectFace(-1),
- mUVCoords(-1.f, -1.f),
- mSTCoords(-1.f, -1.f),
- mXYCoords(-1, -1),
- mNormal(),
- mBinormal(),
- mHUDIcon(NULL),
- mPickTransparent(pick_transparent)
-{
-}
-
-void LLPickInfo::fetchResults()
-{
-
- S32 face_hit = -1;
- LLVector3 intersection, normal, binormal;
- LLVector2 uv;
-
- LLHUDIcon* hit_icon = gViewerWindow->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f, &intersection);
-
- F32 icon_dist = 0.f;
- if (hit_icon)
- {
- icon_dist = (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec();
- }
- LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f,
- NULL, -1, mPickTransparent, &face_hit,
- &intersection, &uv, &normal, &binormal);
-
- mPickPt = mMousePt;
-
- U32 te_offset = face_hit > -1 ? face_hit : 0;
-
- //unproject relative clicked coordinate from window coordinate using GL
-
- LLViewerObject* objectp = hit_object;
-
- if (hit_icon &&
- (!objectp ||
- icon_dist < (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec()))
- {
- // was this name referring to a hud icon?
- mHUDIcon = hit_icon;
- mPickType = PICK_ICON;
- mPosGlobal = mHUDIcon->getPositionGlobal();
- }
- else if (objectp)
- {
- if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH )
- {
- // Hit land
- mPickType = PICK_LAND;
- mObjectID.setNull(); // land has no id
-
- // put global position into land_pos
- LLVector3d land_pos;
- if (!gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos))
- {
- // The selected point is beyond the draw distance or is otherwise
- // not selectable. Return before calling mPickCallback().
- return;
- }
-
- // Fudge the land focus a little bit above ground.
- mPosGlobal = land_pos + LLVector3d::z_axis * 0.1f;
- }
- else
- {
- if(isFlora(objectp))
- {
- mPickType = PICK_FLORA;
- }
- else
- {
- mPickType = PICK_OBJECT;
- }
- mObjectOffset = gAgentCamera.calcFocusOffset(objectp, intersection, mPickPt.mX, mPickPt.mY);
- mObjectID = objectp->mID;
- mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset;
-
- mPosGlobal = gAgent.getPosGlobalFromAgent(intersection);
-
- if (mWantSurfaceInfo)
- {
- getSurfaceInfo();
- }
- }
- }
-
- if (mPickCallback)
- {
- mPickCallback(*this);
- }
-}
-
-LLPointer<LLViewerObject> LLPickInfo::getObject() const
-{
- return gObjectList.findObject( mObjectID );
-}
-
-void LLPickInfo::updateXYCoords()
-{
- if (mObjectFace > -1)
- {
- const LLTextureEntry* tep = getObject()->getTE(mObjectFace);
- LLPointer<LLViewerTexture> imagep = LLViewerTextureManager::getFetchedTexture(tep->getID());
- if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull())
- {
- mXYCoords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth());
- mXYCoords.mY = llround((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight());
- }
- }
-}
-
-void LLPickInfo::getSurfaceInfo()
-{
- // set values to uninitialized - this is what we return if no intersection is found
- mObjectFace = -1;
- mUVCoords = LLVector2(-1, -1);
- mSTCoords = LLVector2(-1, -1);
- mXYCoords = LLCoordScreen(-1, -1);
- mIntersection = LLVector3(0,0,0);
- mNormal = LLVector3(0,0,0);
- mBinormal = LLVector3(0,0,0);
-
- LLViewerObject* objectp = getObject();
-
- if (objectp)
- {
- if (gViewerWindow->cursorIntersect(llround((F32)mMousePt.mX), llround((F32)mMousePt.mY), 1024.f,
- objectp, -1, mPickTransparent,
- &mObjectFace,
- &mIntersection,
- &mSTCoords,
- &mNormal,
- &mBinormal))
- {
- // if we succeeded with the intersect above, compute the texture coordinates:
-
- if (objectp->mDrawable.notNull() && mObjectFace > -1)
- {
- LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
-
- mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal);
- }
-
- // and XY coords:
- updateXYCoords();
-
- }
- }
-}
-
-
-/* code to get UV via a special UV render - removed in lieu of raycast method
-LLVector2 LLPickInfo::pickUV()
-{
- LLVector2 result(-1.f, -1.f);
-
- LLViewerObject* objectp = getObject();
- if (!objectp)
- {
- return result;
- }
-
- if (mObjectFace > -1 &&
- objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME &&
- mObjectFace < objectp->mDrawable->getNumFaces())
- {
- S32 scaled_x = llround((F32)mPickPt.mX * gViewerWindow->getDisplayScale().mV[VX]);
- S32 scaled_y = llround((F32)mPickPt.mY * gViewerWindow->getDisplayScale().mV[VY]);
- const S32 UV_PICK_WIDTH = 5;
- const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2;
- U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4];
- LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
- if (facep)
- {
- LLGLState scissor_state(GL_SCISSOR_TEST);
- scissor_state.enable();
- LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE);
- //glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
- glScissor(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
-
- glClear(GL_DEPTH_BUFFER_BIT);
-
- facep->renderSelectedUV();
-
- glReadPixels(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, GL_RGBA, GL_UNSIGNED_BYTE, uv_pick_buffer);
- U8* center_pixel = &uv_pick_buffer[4 * ((UV_PICK_WIDTH * UV_PICK_HALF_WIDTH) + UV_PICK_HALF_WIDTH + 1)];
-
- result.mV[VX] = (F32)((center_pixel[VGREEN] & 0xf) + (16.f * center_pixel[VRED])) / 4095.f;
- result.mV[VY] = (F32)((center_pixel[VGREEN] >> 4) + (16.f * center_pixel[VBLUE])) / 4095.f;
- }
- }
-
- return result;
-} */
-
-
-//static
-bool LLPickInfo::isFlora(LLViewerObject* object)
-{
- if (!object) return false;
-
- LLPCode pcode = object->getPCode();
-
- if( (LL_PCODE_LEGACY_GRASS == pcode)
- || (LL_PCODE_LEGACY_TREE == pcode)
- || (LL_PCODE_TREE_NEW == pcode))
- {
- return true;
- }
- return false;
-}
+/**
+ * @file llviewerwindow.cpp
+ * @brief Implementation of the LLViewerWindow class.
+ *
+ * $LicenseInfo:firstyear=2001&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "llviewerwindow.h"
+
+#if LL_WINDOWS
+#pragma warning (disable : 4355) // 'this' used in initializer list: yes, intentionally
+#endif
+
+// system library includes
+#include <stdio.h>
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "llfloaterreg.h"
+#include "llpanellogin.h"
+#include "llviewerkeyboard.h"
+#include "llviewermenu.h"
+
+#include "llviewquery.h"
+#include "llxmltree.h"
+#include "llslurl.h"
+//#include "llviewercamera.h"
+#include "llrender.h"
+
+#include "llvoiceclient.h" // for push-to-talk button handling
+
+//
+// TODO: Many of these includes are unnecessary. Remove them.
+//
+
+// linden library includes
+#include "llaudioengine.h" // mute on minimize
+#include "indra_constants.h"
+#include "llassetstorage.h"
+#include "llerrorcontrol.h"
+#include "llfontgl.h"
+#include "llmousehandler.h"
+#include "llrect.h"
+#include "llsky.h"
+#include "llstring.h"
+#include "llui.h"
+#include "lluuid.h"
+#include "llview.h"
+#include "llxfermanager.h"
+#include "message.h"
+#include "object_flags.h"
+#include "lltimer.h"
+#include "timing.h"
+#include "llviewermenu.h"
+#include "lltooltip.h"
+#include "llmediaentry.h"
+#include "llurldispatcher.h"
+
+// newview includes
+#include "llagent.h"
+#include "llbox.h"
+#include "llconsole.h"
+#include "llviewercontrol.h"
+#include "llcylinder.h"
+#include "lldebugview.h"
+#include "lldir.h"
+#include "lldrawable.h"
+#include "lldrawpoolalpha.h"
+#include "lldrawpoolbump.h"
+#include "lldrawpoolwater.h"
+#include "llmaniptranslate.h"
+#include "llface.h"
+#include "llfeaturemanager.h"
+#include "llfilepicker.h"
+#include "llfirstuse.h"
+#include "llfloater.h"
+#include "llfloaterbuildoptions.h"
+#include "llfloaterbuyland.h"
+#include "llfloatercamera.h"
+#include "llfloaterland.h"
+#include "llfloaterinspect.h"
+#include "llfloatermap.h"
+#include "llfloaternamedesc.h"
+#include "llfloaterpreference.h"
+#include "llfloatersnapshot.h"
+#include "llfloatertools.h"
+#include "llfloaterworldmap.h"
+#include "llfocusmgr.h"
+#include "llfontfreetype.h"
+#include "llgesturemgr.h"
+#include "llglheaders.h"
+#include "lltooltip.h"
+#include "llhudmanager.h"
+#include "llhudobject.h"
+#include "llhudview.h"
+#include "llimagebmp.h"
+#include "llimagej2c.h"
+#include "llimageworker.h"
+#include "llkeyboard.h"
+#include "lllineeditor.h"
+#include "llmenugl.h"
+#include "llmodaldialog.h"
+#include "llmorphview.h"
+#include "llmoveview.h"
+#include "llnavigationbar.h"
+#include "llpopupview.h"
+#include "llpreviewtexture.h"
+#include "llprogressview.h"
+#include "llresmgr.h"
+#include "llsidetray.h"
+#include "llselectmgr.h"
+#include "llrootview.h"
+#include "llrendersphere.h"
+#include "llstartup.h"
+#include "llstatusbar.h"
+#include "llstatview.h"
+#include "llsurface.h"
+#include "llsurfacepatch.h"
+#include "lltexlayer.h"
+#include "lltextbox.h"
+#include "lltexturecache.h"
+#include "lltexturefetch.h"
+#include "lltextureview.h"
+#include "lltool.h"
+#include "lltoolcomp.h"
+#include "lltooldraganddrop.h"
+#include "lltoolface.h"
+#include "lltoolfocus.h"
+#include "lltoolgrab.h"
+#include "lltoolmgr.h"
+#include "lltoolmorph.h"
+#include "lltoolpie.h"
+#include "lltoolselectland.h"
+#include "lltrans.h"
+#include "lluictrlfactory.h"
+#include "llurldispatcher.h" // SLURL from other app instance
+#include "llversioninfo.h"
+#include "llvieweraudio.h"
+#include "llviewercamera.h"
+#include "llviewergesture.h"
+#include "llviewertexturelist.h"
+#include "llviewerinventory.h"
+#include "llviewerkeyboard.h"
+#include "llviewermedia.h"
+#include "llviewermediafocus.h"
+#include "llviewermenu.h"
+#include "llviewermessage.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h"
+#include "llviewershadermgr.h"
+#include "llviewerstats.h"
+#include "llvoavatarself.h"
+#include "llvovolume.h"
+#include "llworld.h"
+#include "llworldmapview.h"
+#include "pipeline.h"
+#include "llappviewer.h"
+#include "llviewerdisplay.h"
+#include "llspatialpartition.h"
+#include "llviewerjoystick.h"
+#include "llviewernetwork.h"
+#include "llpostprocess.h"
+#include "llbottomtray.h"
+#include "llnearbychatbar.h"
+#include "llagentui.h"
+#include "llwearablelist.h"
+
+#include "llnotifications.h"
+#include "llnotificationsutil.h"
+#include "llnotificationmanager.h"
+
+#include "llfloaternotificationsconsole.h"
+
+#include "llnearbychat.h"
+#include "llviewerwindowlistener.h"
+#include "llpaneltopinfobar.h"
+
+#if LL_WINDOWS
+#include <tchar.h> // For Unicode conversion methods
+#endif
+
+//
+// Globals
+//
+void render_ui(F32 zoom_factor = 1.f, int subfield = 0);
+
+extern BOOL gDebugClicks;
+extern BOOL gDisplaySwapBuffers;
+extern BOOL gDepthDirty;
+extern BOOL gResizeScreenTexture;
+
+LLViewerWindow *gViewerWindow = NULL;
+
+LLFrameTimer gAwayTimer;
+LLFrameTimer gAwayTriggerTimer;
+
+BOOL gShowOverlayTitle = FALSE;
+
+LLViewerObject* gDebugRaycastObject = NULL;
+LLVector3 gDebugRaycastIntersection;
+LLVector2 gDebugRaycastTexCoord;
+LLVector3 gDebugRaycastNormal;
+LLVector3 gDebugRaycastBinormal;
+S32 gDebugRaycastFaceHit;
+
+// HUD display lines in lower right
+BOOL gDisplayWindInfo = FALSE;
+BOOL gDisplayCameraPos = FALSE;
+BOOL gDisplayFOV = FALSE;
+BOOL gDisplayBadge = FALSE;
+
+S32 CHAT_BAR_HEIGHT = 28;
+S32 OVERLAY_BAR_HEIGHT = 20;
+
+const U8 NO_FACE = 255;
+BOOL gQuietSnapshot = FALSE;
+
+const F32 MIN_AFK_TIME = 2.f; // minimum time after setting away state before coming back
+const F32 MAX_FAST_FRAME_TIME = 0.5f;
+const F32 FAST_FRAME_INCREMENT = 0.1f;
+
+const F32 MIN_DISPLAY_SCALE = 0.75f;
+
+std::string LLViewerWindow::sSnapshotBaseName;
+std::string LLViewerWindow::sSnapshotDir;
+
+std::string LLViewerWindow::sMovieBaseName;
+
+class RecordToChatConsole : public LLError::Recorder, public LLSingleton<RecordToChatConsole>
+{
+public:
+ virtual void recordMessage(LLError::ELevel level,
+ const std::string& message)
+ {
+ //FIXME: this is NOT thread safe, and will do bad things when a warning is issued from a non-UI thread
+
+ // only log warnings to chat console
+ //if (level == LLError::LEVEL_WARN)
+ //{
+ //LLFloaterChat* chat_floater = LLFloaterReg::findTypedInstance<LLFloaterChat>("chat");
+ //if (chat_floater && gSavedSettings.getBOOL("WarningsAsChat"))
+ //{
+ // LLChat chat;
+ // chat.mText = message;
+ // chat.mSourceType = CHAT_SOURCE_SYSTEM;
+
+ // chat_floater->addChat(chat, FALSE, FALSE);
+ //}
+ //}
+ }
+};
+
+////////////////////////////////////////////////////////////////////////////
+//
+// LLDebugText
+//
+
+class LLDebugText
+{
+private:
+ struct Line
+ {
+ Line(const std::string& in_text, S32 in_x, S32 in_y) : text(in_text), x(in_x), y(in_y) {}
+ std::string text;
+ S32 x,y;
+ };
+
+ LLViewerWindow *mWindow;
+
+ typedef std::vector<Line> line_list_t;
+ line_list_t mLineList;
+ LLColor4 mTextColor;
+
+ void addText(S32 x, S32 y, const std::string &text)
+ {
+ mLineList.push_back(Line(text, x, y));
+ }
+
+ void clearText() { mLineList.clear(); }
+
+public:
+ LLDebugText(LLViewerWindow* window) : mWindow(window) {}
+
+ void update()
+ {
+ static LLCachedControl<bool> log_texture_traffic(gSavedSettings,"LogTextureNetworkTraffic") ;
+
+ std::string wind_vel_text;
+ std::string wind_vector_text;
+ std::string rwind_vel_text;
+ std::string rwind_vector_text;
+ std::string audio_text;
+
+ static const std::string beacon_particle = LLTrans::getString("BeaconParticle");
+ static const std::string beacon_physical = LLTrans::getString("BeaconPhysical");
+ static const std::string beacon_scripted = LLTrans::getString("BeaconScripted");
+ static const std::string beacon_scripted_touch = LLTrans::getString("BeaconScriptedTouch");
+ static const std::string beacon_sound = LLTrans::getString("BeaconSound");
+ static const std::string beacon_media = LLTrans::getString("BeaconMedia");
+ static const std::string particle_hiding = LLTrans::getString("ParticleHiding");
+
+ // Draw the statistics in a light gray
+ // and in a thin font
+ mTextColor = LLColor4( 0.86f, 0.86f, 0.86f, 1.f );
+
+ // Draw stuff growing up from right lower corner of screen
+ U32 xpos = mWindow->getWindowWidthScaled() - 350;
+ U32 ypos = 64;
+ const U32 y_inc = 20;
+
+ clearText();
+
+ if (gSavedSettings.getBOOL("DebugShowTime"))
+ {
+ const U32 y_inc2 = 15;
+ for (std::map<S32,LLFrameTimer>::reverse_iterator iter = gDebugTimers.rbegin();
+ iter != gDebugTimers.rend(); ++iter)
+ {
+ S32 idx = iter->first;
+ LLFrameTimer& timer = iter->second;
+ F32 time = timer.getElapsedTimeF32();
+ S32 hours = (S32)(time / (60*60));
+ S32 mins = (S32)((time - hours*(60*60)) / 60);
+ S32 secs = (S32)((time - hours*(60*60) - mins*60));
+ std::string label = gDebugTimerLabel[idx];
+ if (label.empty()) label = llformat("Debug: %d", idx);
+ addText(xpos, ypos, llformat(" %s: %d:%02d:%02d", label.c_str(), hours,mins,secs)); ypos += y_inc2;
+ }
+
+ F32 time = gFrameTimeSeconds;
+ S32 hours = (S32)(time / (60*60));
+ S32 mins = (S32)((time - hours*(60*60)) / 60);
+ S32 secs = (S32)((time - hours*(60*60) - mins*60));
+ addText(xpos, ypos, llformat("Time: %d:%02d:%02d", hours,mins,secs)); ypos += y_inc;
+ }
+
+#if LL_WINDOWS
+ if (gSavedSettings.getBOOL("DebugShowMemory"))
+ {
+ addText(xpos, ypos, llformat("Memory: %d (KB)", LLMemory::getWorkingSetSize() / 1024));
+ ypos += y_inc;
+ }
+#endif
+
+ if (gDisplayCameraPos)
+ {
+ std::string camera_view_text;
+ std::string camera_center_text;
+ std::string agent_view_text;
+ std::string agent_left_text;
+ std::string agent_center_text;
+ std::string agent_root_center_text;
+
+ LLVector3d tvector; // Temporary vector to hold data for printing.
+
+ // Update camera center, camera view, wind info every other frame
+ tvector = gAgent.getPositionGlobal();
+ agent_center_text = llformat("AgentCenter %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ if (isAgentAvatarValid())
+ {
+ tvector = gAgent.getPosGlobalFromAgent(gAgentAvatarp->mRoot.getWorldPosition());
+ agent_root_center_text = llformat("AgentRootCenter %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+ }
+ else
+ {
+ agent_root_center_text = "---";
+ }
+
+
+ tvector = LLVector4(gAgent.getFrameAgent().getAtAxis());
+ agent_view_text = llformat("AgentAtAxis %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ tvector = LLVector4(gAgent.getFrameAgent().getLeftAxis());
+ agent_left_text = llformat("AgentLeftAxis %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ tvector = gAgentCamera.getCameraPositionGlobal();
+ camera_center_text = llformat("CameraCenter %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ tvector = LLVector4(LLViewerCamera::getInstance()->getAtAxis());
+ camera_view_text = llformat("CameraAtAxis %f %f %f",
+ (F32)(tvector.mdV[VX]), (F32)(tvector.mdV[VY]), (F32)(tvector.mdV[VZ]));
+
+ addText(xpos, ypos, agent_center_text); ypos += y_inc;
+ addText(xpos, ypos, agent_root_center_text); ypos += y_inc;
+ addText(xpos, ypos, agent_view_text); ypos += y_inc;
+ addText(xpos, ypos, agent_left_text); ypos += y_inc;
+ addText(xpos, ypos, camera_center_text); ypos += y_inc;
+ addText(xpos, ypos, camera_view_text); ypos += y_inc;
+ }
+
+ if (gDisplayWindInfo)
+ {
+ wind_vel_text = llformat("Wind velocity %.2f m/s", gWindVec.magVec());
+ wind_vector_text = llformat("Wind vector %.2f %.2f %.2f", gWindVec.mV[0], gWindVec.mV[1], gWindVec.mV[2]);
+ rwind_vel_text = llformat("RWind vel %.2f m/s", gRelativeWindVec.magVec());
+ rwind_vector_text = llformat("RWind vec %.2f %.2f %.2f", gRelativeWindVec.mV[0], gRelativeWindVec.mV[1], gRelativeWindVec.mV[2]);
+
+ addText(xpos, ypos, wind_vel_text); ypos += y_inc;
+ addText(xpos, ypos, wind_vector_text); ypos += y_inc;
+ addText(xpos, ypos, rwind_vel_text); ypos += y_inc;
+ addText(xpos, ypos, rwind_vector_text); ypos += y_inc;
+ }
+ if (gDisplayWindInfo)
+ {
+ if (gAudiop)
+ {
+ audio_text= llformat("Audio for wind: %d", gAudiop->isWindEnabled());
+ }
+ addText(xpos, ypos, audio_text); ypos += y_inc;
+ }
+ if (gDisplayFOV)
+ {
+ addText(xpos, ypos, llformat("FOV: %2.1f deg", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
+ ypos += y_inc;
+ }
+ if (gDisplayBadge)
+ {
+ addText(xpos, ypos+(y_inc/2), llformat("Hippos!", RAD_TO_DEG * LLViewerCamera::getInstance()->getView()));
+ ypos += y_inc * 2;
+ }
+
+ /*if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ addText(xpos + 200, ypos, llformat("Flycam"));
+ ypos += y_inc;
+ }*/
+
+ if (gSavedSettings.getBOOL("DebugShowRenderInfo"))
+ {
+ if (gPipeline.getUseVertexShaders() == 0)
+ {
+ addText(xpos, ypos, "Shaders Disabled");
+ ypos += y_inc;
+ }
+ addText(xpos, ypos, llformat("%d MB Vertex Data", LLVertexBuffer::sAllocatedBytes/(1024*1024)));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Vertex Buffers", LLVertexBuffer::sGLCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Mapped Buffers", LLVertexBuffer::sMappedCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Vertex Buffer Binds", LLVertexBuffer::sBindCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Vertex Buffer Sets", LLVertexBuffer::sSetCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Texture Binds", LLImageGL::sBindCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Unique Textures", LLImageGL::sUniqueCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Render Calls", gPipeline.mBatchCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Matrix Ops", gPipeline.mMatrixOpCount));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%d Texture Matrix Ops", gPipeline.mTextureMatrixOps));
+ ypos += y_inc;
+
+ gPipeline.mTextureMatrixOps = 0;
+ gPipeline.mMatrixOpCount = 0;
+
+ if (gPipeline.mBatchCount > 0)
+ {
+ addText(xpos, ypos, llformat("Batch min/max/mean: %d/%d/%d", gPipeline.mMinBatchSize, gPipeline.mMaxBatchSize,
+ gPipeline.mTrianglesDrawn/gPipeline.mBatchCount));
+
+ gPipeline.mMinBatchSize = gPipeline.mMaxBatchSize;
+ gPipeline.mMaxBatchSize = 0;
+ gPipeline.mBatchCount = 0;
+ }
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("UI Verts/Calls: %d/%d", LLRender::sUIVerts, LLRender::sUICalls));
+ LLRender::sUICalls = LLRender::sUIVerts = 0;
+ ypos += y_inc;
+
+ addText(xpos,ypos, llformat("%d/%d Nodes visible", gPipeline.mNumVisibleNodes, LLSpatialGroup::sNodeCount));
+
+ ypos += y_inc;
+
+
+ addText(xpos,ypos, llformat("%d Avatars visible", LLVOAvatar::sNumVisibleAvatars));
+
+ ypos += y_inc;
+
+ addText(xpos,ypos, llformat("%d Lights visible", LLPipeline::sVisibleLightCount));
+
+ ypos += y_inc;
+
+ LLVertexBuffer::sBindCount = LLImageGL::sBindCount =
+ LLVertexBuffer::sSetCount = LLImageGL::sUniqueCount =
+ gPipeline.mNumVisibleNodes = LLPipeline::sVisibleLightCount = 0;
+ }
+ if (gSavedSettings.getBOOL("DebugShowRenderMatrices"))
+ {
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[12], gGLProjection[13], gGLProjection[14], gGLProjection[15]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[8], gGLProjection[9], gGLProjection[10], gGLProjection[11]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[4], gGLProjection[5], gGLProjection[6], gGLProjection[7]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLProjection[0], gGLProjection[1], gGLProjection[2], gGLProjection[3]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, "Projection Matrix");
+ ypos += y_inc;
+
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[12], gGLModelView[13], gGLModelView[14], gGLModelView[15]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[8], gGLModelView[9], gGLModelView[10], gGLModelView[11]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[4], gGLModelView[5], gGLModelView[6], gGLModelView[7]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, llformat("%.4f .%4f %.4f %.4f", gGLModelView[0], gGLModelView[1], gGLModelView[2], gGLModelView[3]));
+ ypos += y_inc;
+
+ addText(xpos, ypos, "View Matrix");
+ ypos += y_inc;
+ }
+ if (gSavedSettings.getBOOL("DebugShowColor"))
+ {
+ U8 color[4];
+ LLCoordGL coord = gViewerWindow->getCurrentMouse();
+ glReadPixels(coord.mX, coord.mY, 1,1,GL_RGBA, GL_UNSIGNED_BYTE, color);
+ addText(xpos, ypos, llformat("%d %d %d %d", color[0], color[1], color[2], color[3]));
+ ypos += y_inc;
+ }
+ // only display these messages if we are actually rendering beacons at this moment
+ if (LLPipeline::getRenderBeacons(NULL) && LLFloaterReg::instanceVisible("beacons"))
+ {
+ if (LLPipeline::getRenderParticleBeacons(NULL))
+ {
+ addText(xpos, ypos, beacon_particle);
+ ypos += y_inc;
+ }
+ if (LLPipeline::toggleRenderTypeControlNegated((void*)LLPipeline::RENDER_TYPE_PARTICLES))
+ {
+ addText(xpos, ypos, particle_hiding);
+ ypos += y_inc;
+ }
+ if (LLPipeline::getRenderPhysicalBeacons(NULL))
+ {
+ addText(xpos, ypos, beacon_physical);
+ ypos += y_inc;
+ }
+ if (LLPipeline::getRenderScriptedBeacons(NULL))
+ {
+ addText(xpos, ypos, beacon_scripted);
+ ypos += y_inc;
+ }
+ else
+ if (LLPipeline::getRenderScriptedTouchBeacons(NULL))
+ {
+ addText(xpos, ypos, beacon_scripted_touch);
+ ypos += y_inc;
+ }
+ if (LLPipeline::getRenderSoundBeacons(NULL))
+ {
+ addText(xpos, ypos, beacon_sound);
+ ypos += y_inc;
+ }
+ }
+ if(log_texture_traffic)
+ {
+ U32 old_y = ypos ;
+ for(S32 i = LLViewerTexture::BOOST_NONE; i < LLViewerTexture::MAX_GL_IMAGE_CATEGORY; i++)
+ {
+ if(gTotalTextureBytesPerBoostLevel[i] > 0)
+ {
+ addText(xpos, ypos, llformat("Boost_Level %d: %.3f MB", i, (F32)gTotalTextureBytesPerBoostLevel[i] / (1024 * 1024)));
+ ypos += y_inc;
+ }
+ }
+ if(ypos != old_y)
+ {
+ addText(xpos, ypos, "Network traffic for textures:");
+ ypos += y_inc;
+ }
+ }
+
+ if (gSavedSettings.getBOOL("DebugShowTextureInfo"))
+ {
+ LLViewerObject* objectp = NULL ;
+ //objectp = = gAgentCamera.getFocusObject();
+
+ LLSelectNode* nodep = LLSelectMgr::instance().getHoverNode();
+ if (nodep)
+ {
+ objectp = nodep->getObject();
+ }
+ if (objectp && !objectp->isDead())
+ {
+ S32 num_faces = objectp->mDrawable->getNumFaces() ;
+
+ for(S32 i = 0 ; i < num_faces; i++)
+ {
+ LLFace* facep = objectp->mDrawable->getFace(i) ;
+ if(facep)
+ {
+ //addText(xpos, ypos, llformat("ts_min: %.3f ts_max: %.3f tt_min: %.3f tt_max: %.3f", facep->mTexExtents[0].mV[0], facep->mTexExtents[1].mV[0],
+ // facep->mTexExtents[0].mV[1], facep->mTexExtents[1].mV[1]));
+ //ypos += y_inc;
+
+ addText(xpos, ypos, llformat("v_size: %.3f: p_size: %.3f", facep->getVirtualSize(), facep->getPixelArea()));
+ ypos += y_inc;
+
+ //const LLTextureEntry *tep = facep->getTextureEntry();
+ //if(tep)
+ //{
+ // addText(xpos, ypos, llformat("scale_s: %.3f: scale_t: %.3f", tep->mScaleS, tep->mScaleT)) ;
+ // ypos += y_inc;
+ //}
+
+ LLViewerTexture* tex = facep->getTexture() ;
+ if(tex)
+ {
+ addText(xpos, ypos, llformat("ID: %s v_size: %.3f", tex->getID().asString().c_str(), tex->getMaxVirtualSize()));
+ ypos += y_inc;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ void draw()
+ {
+ for (line_list_t::iterator iter = mLineList.begin();
+ iter != mLineList.end(); ++iter)
+ {
+ const Line& line = *iter;
+ LLFontGL::getFontMonospace()->renderUTF8(line.text, 0, (F32)line.x, (F32)line.y, mTextColor,
+ LLFontGL::LEFT, LLFontGL::TOP,
+ LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, NULL, FALSE);
+ }
+ mLineList.clear();
+ }
+
+};
+
+void LLViewerWindow::updateDebugText()
+{
+ mDebugText->update();
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// LLViewerWindow
+//
+
+BOOL LLViewerWindow::handleAnyMouseClick(LLWindow *window, LLCoordGL pos, MASK mask, LLMouseHandler::EClickType clicktype, BOOL down)
+{
+ const char* buttonname = "";
+ const char* buttonstatestr = "";
+ S32 x = pos.mX;
+ S32 y = pos.mY;
+ x = llround((F32)x / mDisplayScale.mV[VX]);
+ y = llround((F32)y / mDisplayScale.mV[VY]);
+
+ // only send mouse clicks to UI if UI is visible
+ if(gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+
+ if (down)
+ {
+ buttonstatestr = "down" ;
+ }
+ else
+ {
+ buttonstatestr = "up" ;
+ }
+
+ switch (clicktype)
+ {
+ case LLMouseHandler::CLICK_LEFT:
+ mLeftMouseDown = down;
+ buttonname = "Left";
+ break;
+ case LLMouseHandler::CLICK_RIGHT:
+ mRightMouseDown = down;
+ buttonname = "Right";
+ break;
+ case LLMouseHandler::CLICK_MIDDLE:
+ mMiddleMouseDown = down;
+ buttonname = "Middle";
+ break;
+ case LLMouseHandler::CLICK_DOUBLELEFT:
+ mLeftMouseDown = down;
+ buttonname = "Left Double Click";
+ break;
+ }
+
+ LLView::sMouseHandlerMessage.clear();
+
+ if (gMenuBarView)
+ {
+ // stop ALT-key access to menu
+ gMenuBarView->resetMenuTrigger();
+ }
+
+ if (gDebugClicks)
+ {
+ llinfos << "ViewerWindow " << buttonname << " mouse " << buttonstatestr << " at " << x << "," << y << llendl;
+ }
+
+ // Make sure we get a corresponding mouseup event, even if the mouse leaves the window
+ if (down)
+ mWindow->captureMouse();
+ else
+ mWindow->releaseMouse();
+
+ // Indicate mouse was active
+ LLUI::resetMouseIdleTimer();
+
+ // Don't let the user move the mouse out of the window until mouse up.
+ if( LLToolMgr::getInstance()->getCurrentTool()->clipMouseWhenDown() )
+ {
+ mWindow->setMouseClipping(down);
+ }
+
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ if( mouse_captor )
+ {
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << buttonname << " Mouse " << buttonstatestr << " handled by captor " << mouse_captor->getName() << llendl;
+ }
+ return mouse_captor->handleAnyMouseClick(local_x, local_y, mask, clicktype, down);
+ }
+
+ // Topmost view gets a chance before the hierarchy
+ //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ //if (top_ctrl)
+ //{
+ // S32 local_x, local_y;
+ // top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
+ // if (top_ctrl->pointInView(local_x, local_y))
+ // {
+ // return top_ctrl->handleAnyMouseClick(local_x, local_y, mask, clicktype, down) ;
+ // }
+ // else
+ // {
+ // if (down)
+ // {
+ // gFocusMgr.setTopCtrl(NULL);
+ // }
+ // }
+ //}
+
+ // Give the UI views a chance to process the click
+ if( mRootView->handleAnyMouseClick(x, y, mask, clicktype, down) )
+ {
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << buttonname << " Mouse " << buttonstatestr << " " << LLView::sMouseHandlerMessage << llendl;
+ }
+ return TRUE;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ llinfos << buttonname << " Mouse " << buttonstatestr << " not handled by view" << llendl;
+ }
+ }
+
+ // Do not allow tool manager to handle mouseclicks if we have disconnected
+ if(!gDisconnected && LLToolMgr::getInstance()->getCurrentTool()->handleAnyMouseClick( x, y, mask, clicktype, down ) )
+ {
+ return TRUE;
+ }
+
+
+ // If we got this far on a down-click, it wasn't handled.
+ // Up-clicks, though, are always handled as far as the OS is concerned.
+ BOOL default_rtn = !down;
+ return default_rtn;
+}
+
+BOOL LLViewerWindow::handleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ BOOL down = TRUE;
+ return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
+}
+
+BOOL LLViewerWindow::handleDoubleClick(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ // try handling as a double-click first, then a single-click if that
+ // wasn't handled.
+ BOOL down = TRUE;
+ if (handleAnyMouseClick(window, pos, mask,
+ LLMouseHandler::CLICK_DOUBLELEFT, down))
+ {
+ return TRUE;
+ }
+ return handleMouseDown(window, pos, mask);
+}
+
+BOOL LLViewerWindow::handleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ BOOL down = FALSE;
+ return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_LEFT,down);
+}
+
+
+BOOL LLViewerWindow::handleRightMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ S32 x = pos.mX;
+ S32 y = pos.mY;
+ x = llround((F32)x / mDisplayScale.mV[VX]);
+ y = llround((F32)y / mDisplayScale.mV[VY]);
+
+ BOOL down = TRUE;
+ BOOL handle = handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
+ if (handle)
+ return handle;
+
+ // *HACK: this should be rolled into the composite tool logic, not
+ // hardcoded at the top level.
+ if (CAMERA_MODE_CUSTOMIZE_AVATAR != gAgentCamera.getCameraMode() && LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance())
+ {
+ // If the current tool didn't process the click, we should show
+ // the pie menu. This can be done by passing the event to the pie
+ // menu tool.
+ LLToolPie::getInstance()->handleRightMouseDown(x, y, mask);
+ // show_context_menu( x, y, mask );
+ }
+
+ return TRUE;
+}
+
+BOOL LLViewerWindow::handleRightMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ BOOL down = FALSE;
+ return handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_RIGHT,down);
+}
+
+BOOL LLViewerWindow::handleMiddleMouseDown(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ BOOL down = TRUE;
+ LLVoiceClient::getInstance()->middleMouseState(true);
+ handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
+
+ // Always handled as far as the OS is concerned.
+ return TRUE;
+}
+
+LLWindowCallbacks::DragNDropResult LLViewerWindow::handleDragNDrop( LLWindow *window, LLCoordGL pos, MASK mask, LLWindowCallbacks::DragNDropAction action, std::string data)
+{
+ LLWindowCallbacks::DragNDropResult result = LLWindowCallbacks::DND_NONE;
+
+ const bool prim_media_dnd_enabled = gSavedSettings.getBOOL("PrimMediaDragNDrop");
+ const bool slurl_dnd_enabled = gSavedSettings.getBOOL("SLURLDragNDrop");
+
+ if ( prim_media_dnd_enabled || slurl_dnd_enabled )
+ {
+ switch(action)
+ {
+ // Much of the handling for these two cases is the same.
+ case LLWindowCallbacks::DNDA_TRACK:
+ case LLWindowCallbacks::DNDA_DROPPED:
+ case LLWindowCallbacks::DNDA_START_TRACKING:
+ {
+ bool drop = (LLWindowCallbacks::DNDA_DROPPED == action);
+
+ if (slurl_dnd_enabled)
+ {
+ LLSLURL dropped_slurl(data);
+ if(dropped_slurl.isSpatial())
+ {
+ if (drop)
+ {
+ LLURLDispatcher::dispatch( dropped_slurl.getSLURLString(), NULL, true );
+ return LLWindowCallbacks::DND_MOVE;
+ }
+ return LLWindowCallbacks::DND_COPY;
+ }
+ }
+
+ if (prim_media_dnd_enabled)
+ {
+ LLPickInfo pick_info = pickImmediate( pos.mX, pos.mY, TRUE /*BOOL pick_transparent*/ );
+
+ LLUUID object_id = pick_info.getObjectID();
+ S32 object_face = pick_info.mObjectFace;
+ std::string url = data;
+
+ lldebugs << "Object: picked at " << pos.mX << ", " << pos.mY << " - face = " << object_face << " - URL = " << url << llendl;
+
+ LLVOVolume *obj = dynamic_cast<LLVOVolume*>(static_cast<LLViewerObject*>(pick_info.getObject()));
+
+ if (obj && !obj->getRegion()->getCapability("ObjectMedia").empty())
+ {
+ LLTextureEntry *te = obj->getTE(object_face);
+
+ // can modify URL if we can modify the object or we have navigate permissions
+ bool allow_modify_url = obj->permModify() || obj->hasMediaPermission( te->getMediaData(), LLVOVolume::MEDIA_PERM_INTERACT );
+
+ if (te && allow_modify_url )
+ {
+ if (drop)
+ {
+ // object does NOT have media already
+ if ( ! te->hasMedia() )
+ {
+ // we are allowed to modify the object
+ if ( obj->permModify() )
+ {
+ // Create new media entry
+ LLSD media_data;
+ // XXX Should we really do Home URL too?
+ media_data[LLMediaEntry::HOME_URL_KEY] = url;
+ media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
+ media_data[LLMediaEntry::AUTO_PLAY_KEY] = true;
+ obj->syncMediaData(object_face, media_data, true, true);
+ // XXX This shouldn't be necessary, should it ?!?
+ if (obj->getMediaImpl(object_face))
+ obj->getMediaImpl(object_face)->navigateReload();
+ obj->sendMediaDataUpdate();
+
+ result = LLWindowCallbacks::DND_COPY;
+ }
+ }
+ else
+ // object HAS media already
+ {
+ // URL passes the whitelist
+ if (te->getMediaData()->checkCandidateUrl( url ) )
+ {
+ // just navigate to the URL
+ if (obj->getMediaImpl(object_face))
+ {
+ obj->getMediaImpl(object_face)->navigateTo(url);
+ }
+ else
+ {
+ // This is very strange. Navigation should
+ // happen via the Impl, but we don't have one.
+ // This sends it to the server, which /should/
+ // trigger us getting it. Hopefully.
+ LLSD media_data;
+ media_data[LLMediaEntry::CURRENT_URL_KEY] = url;
+ obj->syncMediaData(object_face, media_data, true, true);
+ obj->sendMediaDataUpdate();
+ }
+ result = LLWindowCallbacks::DND_LINK;
+
+ }
+ }
+ LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
+ mDragHoveredObject = NULL;
+
+ }
+ else
+ {
+ // Check the whitelist, if there's media (otherwise just show it)
+ if (te->getMediaData() == NULL || te->getMediaData()->checkCandidateUrl(url))
+ {
+ if ( obj != mDragHoveredObject)
+ {
+ // Highlight the dragged object
+ LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
+ mDragHoveredObject = obj;
+ LLSelectMgr::getInstance()->highlightObjectOnly(mDragHoveredObject);
+ }
+ result = (! te->hasMedia()) ? LLWindowCallbacks::DND_COPY : LLWindowCallbacks::DND_LINK;
+
+ }
+ }
+ }
+ }
+ }
+ }
+ break;
+
+ case LLWindowCallbacks::DNDA_STOP_TRACKING:
+ // The cleanup case below will make sure things are unhilighted if necessary.
+ break;
+ }
+
+ if (prim_media_dnd_enabled &&
+ result == LLWindowCallbacks::DND_NONE && !mDragHoveredObject.isNull())
+ {
+ LLSelectMgr::getInstance()->unhighlightObjectOnly(mDragHoveredObject);
+ mDragHoveredObject = NULL;
+ }
+ }
+
+ return result;
+}
+
+BOOL LLViewerWindow::handleMiddleMouseUp(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ BOOL down = FALSE;
+ LLVoiceClient::getInstance()->middleMouseState(false);
+ handleAnyMouseClick(window,pos,mask,LLMouseHandler::CLICK_MIDDLE,down);
+
+ // Always handled as far as the OS is concerned.
+ return TRUE;
+}
+
+// WARNING: this is potentially called multiple times per frame
+void LLViewerWindow::handleMouseMove(LLWindow *window, LLCoordGL pos, MASK mask)
+{
+ S32 x = pos.mX;
+ S32 y = pos.mY;
+
+ x = llround((F32)x / mDisplayScale.mV[VX]);
+ y = llround((F32)y / mDisplayScale.mV[VY]);
+
+ mMouseInWindow = TRUE;
+
+ // Save mouse point for access during idle() and display()
+
+ LLCoordGL mouse_point(x, y);
+
+ if (mouse_point != mCurrentMousePoint)
+ {
+ LLUI::resetMouseIdleTimer();
+ }
+
+ saveLastMouse(mouse_point);
+
+ mWindow->showCursorFromMouseMove();
+
+ if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
+ {
+ gAgent.clearAFK();
+ }
+}
+
+void LLViewerWindow::handleMouseLeave(LLWindow *window)
+{
+ // Note: we won't get this if we have captured the mouse.
+ llassert( gFocusMgr.getMouseCapture() == NULL );
+ mMouseInWindow = FALSE;
+ LLToolTipMgr::instance().blockToolTips();
+}
+
+BOOL LLViewerWindow::handleCloseRequest(LLWindow *window)
+{
+ // User has indicated they want to close, but we may need to ask
+ // about modified documents.
+ LLAppViewer::instance()->userQuit();
+ // Don't quit immediately
+ return FALSE;
+}
+
+void LLViewerWindow::handleQuit(LLWindow *window)
+{
+ LLAppViewer::instance()->forceQuit();
+}
+
+void LLViewerWindow::handleResize(LLWindow *window, S32 width, S32 height)
+{
+ reshape(width, height);
+ mResDirty = true;
+}
+
+// The top-level window has gained focus (e.g. via ALT-TAB)
+void LLViewerWindow::handleFocus(LLWindow *window)
+{
+ gFocusMgr.setAppHasFocus(TRUE);
+ LLModalDialog::onAppFocusGained();
+
+ gAgent.onAppFocusGained();
+ LLToolMgr::getInstance()->onAppFocusGained();
+
+ // See if we're coming in with modifier keys held down
+ if (gKeyboard)
+ {
+ gKeyboard->resetMaskKeys();
+ }
+
+ // resume foreground running timer
+ // since we artifically limit framerate when not frontmost
+ gForegroundTime.unpause();
+}
+
+// The top-level window has lost focus (e.g. via ALT-TAB)
+void LLViewerWindow::handleFocusLost(LLWindow *window)
+{
+ gFocusMgr.setAppHasFocus(FALSE);
+ //LLModalDialog::onAppFocusLost();
+ LLToolMgr::getInstance()->onAppFocusLost();
+ gFocusMgr.setMouseCapture( NULL );
+
+ if (gMenuBarView)
+ {
+ // stop ALT-key access to menu
+ gMenuBarView->resetMenuTrigger();
+ }
+
+ // restore mouse cursor
+ showCursor();
+ getWindow()->setMouseClipping(FALSE);
+
+ // If losing focus while keys are down, reset them.
+ if (gKeyboard)
+ {
+ gKeyboard->resetKeys();
+ }
+
+ // pause timer that tracks total foreground running time
+ gForegroundTime.pause();
+}
+
+
+BOOL LLViewerWindow::handleTranslatedKeyDown(KEY key, MASK mask, BOOL repeated)
+{
+ // Let the voice chat code check for its PTT key. Note that this never affects event processing.
+ LLVoiceClient::getInstance()->keyDown(key, mask);
+
+ if (gAwayTimer.getElapsedTimeF32() > MIN_AFK_TIME)
+ {
+ gAgent.clearAFK();
+ }
+
+ // *NOTE: We want to interpret KEY_RETURN later when it arrives as
+ // a Unicode char, not as a keydown. Otherwise when client frame
+ // rate is really low, hitting return sends your chat text before
+ // it's all entered/processed.
+ if (key == KEY_RETURN && mask == MASK_NONE)
+ {
+ return FALSE;
+ }
+
+ return gViewerKeyboard.handleKey(key, mask, repeated);
+}
+
+BOOL LLViewerWindow::handleTranslatedKeyUp(KEY key, MASK mask)
+{
+ // Let the voice chat code check for its PTT key. Note that this never affects event processing.
+ LLVoiceClient::getInstance()->keyUp(key, mask);
+
+ return FALSE;
+}
+
+
+void LLViewerWindow::handleScanKey(KEY key, BOOL key_down, BOOL key_up, BOOL key_level)
+{
+ LLViewerJoystick::getInstance()->setCameraNeedsUpdate(true);
+ return gViewerKeyboard.scanKey(key, key_down, key_up, key_level);
+}
+
+
+
+
+BOOL LLViewerWindow::handleActivate(LLWindow *window, BOOL activated)
+{
+ if (activated)
+ {
+ mActive = TRUE;
+ send_agent_resume();
+ gAgent.clearAFK();
+
+ // Unmute audio
+ audio_update_volume();
+ }
+ else
+ {
+ mActive = FALSE;
+
+ if (gSavedSettings.getS32("AFKTimeout"))
+ {
+ gAgent.setAFK();
+ }
+
+ // SL-53351: Make sure we're not in mouselook when minimised, to prevent control issues
+ if (gAgentCamera.getCameraMode() == CAMERA_MODE_MOUSELOOK)
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+
+ send_agent_pause();
+
+ // Mute audio
+ audio_update_volume();
+ }
+ return TRUE;
+}
+
+BOOL LLViewerWindow::handleActivateApp(LLWindow *window, BOOL activating)
+{
+ //if (!activating) gAgentCamera.changeCameraToDefault();
+
+ LLViewerJoystick::getInstance()->setNeedsReset(true);
+ return FALSE;
+}
+
+
+void LLViewerWindow::handleMenuSelect(LLWindow *window, S32 menu_item)
+{
+}
+
+
+BOOL LLViewerWindow::handlePaint(LLWindow *window, S32 x, S32 y, S32 width, S32 height)
+{
+#if LL_WINDOWS
+ if (gNoRender)
+ {
+ HWND window_handle = (HWND)window->getPlatformWindow();
+ PAINTSTRUCT ps;
+ HDC hdc;
+
+ RECT wnd_rect;
+ wnd_rect.left = 0;
+ wnd_rect.top = 0;
+ wnd_rect.bottom = 200;
+ wnd_rect.right = 500;
+
+ hdc = BeginPaint(window_handle, &ps);
+ //SetBKColor(hdc, RGB(255, 255, 255));
+ FillRect(hdc, &wnd_rect, CreateSolidBrush(RGB(255, 255, 255)));
+
+ std::string temp_str;
+ temp_str = llformat( "FPS %3.1f Phy FPS %2.1f Time Dil %1.3f", /* Flawfinder: ignore */
+ LLViewerStats::getInstance()->mFPSStat.getMeanPerSec(),
+ LLViewerStats::getInstance()->mSimPhysicsFPS.getPrev(0),
+ LLViewerStats::getInstance()->mSimTimeDilation.getPrev(0));
+ S32 len = temp_str.length();
+ TextOutA(hdc, 0, 0, temp_str.c_str(), len);
+
+
+ LLVector3d pos_global = gAgent.getPositionGlobal();
+ temp_str = llformat( "Avatar pos %6.1lf %6.1lf %6.1lf", pos_global.mdV[0], pos_global.mdV[1], pos_global.mdV[2]);
+ len = temp_str.length();
+ TextOutA(hdc, 0, 25, temp_str.c_str(), len);
+
+ TextOutA(hdc, 0, 50, "Set \"DisableRendering FALSE\" in settings.ini file to reenable", 61);
+ EndPaint(window_handle, &ps);
+ return TRUE;
+ }
+#endif
+ return FALSE;
+}
+
+
+void LLViewerWindow::handleScrollWheel(LLWindow *window, S32 clicks)
+{
+ handleScrollWheel( clicks );
+}
+
+void LLViewerWindow::handleWindowBlock(LLWindow *window)
+{
+ send_agent_pause();
+}
+
+void LLViewerWindow::handleWindowUnblock(LLWindow *window)
+{
+ send_agent_resume();
+}
+
+void LLViewerWindow::handleDataCopy(LLWindow *window, S32 data_type, void *data)
+{
+ const S32 SLURL_MESSAGE_TYPE = 0;
+ switch (data_type)
+ {
+ case SLURL_MESSAGE_TYPE:
+ // received URL
+ std::string url = (const char*)data;
+ LLMediaCtrl* web = NULL;
+ const bool trusted_browser = false;
+ if (LLURLDispatcher::dispatch(url, web, trusted_browser))
+ {
+ // bring window to foreground, as it has just been "launched" from a URL
+ mWindow->bringToFront();
+ }
+ break;
+ }
+}
+
+BOOL LLViewerWindow::handleTimerEvent(LLWindow *window)
+{
+ if (LLViewerJoystick::getInstance()->getOverrideCamera())
+ {
+ LLViewerJoystick::getInstance()->updateStatus();
+ return TRUE;
+ }
+ return FALSE;
+}
+
+BOOL LLViewerWindow::handleDeviceChange(LLWindow *window)
+{
+ // give a chance to use a joystick after startup (hot-plugging)
+ if (!LLViewerJoystick::getInstance()->isJoystickInitialized() )
+ {
+ LLViewerJoystick::getInstance()->init(true);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+void LLViewerWindow::handlePingWatchdog(LLWindow *window, const char * msg)
+{
+ LLAppViewer::instance()->pingMainloopTimeout(msg);
+}
+
+
+void LLViewerWindow::handleResumeWatchdog(LLWindow *window)
+{
+ LLAppViewer::instance()->resumeMainloopTimeout();
+}
+
+void LLViewerWindow::handlePauseWatchdog(LLWindow *window)
+{
+ LLAppViewer::instance()->pauseMainloopTimeout();
+}
+
+//virtual
+std::string LLViewerWindow::translateString(const char* tag)
+{
+ return LLTrans::getString( std::string(tag) );
+}
+
+//virtual
+std::string LLViewerWindow::translateString(const char* tag,
+ const std::map<std::string, std::string>& args)
+{
+ // LLTrans uses a special subclass of std::string for format maps,
+ // but we must use std::map<> in these callbacks, otherwise we create
+ // a dependency between LLWindow and LLFormatMapString. So copy the data.
+ LLStringUtil::format_map_t args_copy;
+ std::map<std::string,std::string>::const_iterator it = args.begin();
+ for ( ; it != args.end(); ++it)
+ {
+ args_copy[it->first] = it->second;
+ }
+ return LLTrans::getString( std::string(tag), args_copy);
+}
+
+//
+// Classes
+//
+LLViewerWindow::LLViewerWindow(
+ const std::string& title, const std::string& name,
+ S32 x, S32 y,
+ S32 width, S32 height,
+ BOOL fullscreen, BOOL ignore_pixel_depth) // fullscreen is no longer used
+ :
+ mWindow(NULL),
+ mActive(TRUE),
+ mWindowRectRaw(0, height, width, 0),
+ mWindowRectScaled(0, height, width, 0),
+ mWorldViewRectRaw(0, height, width, 0),
+ mLeftMouseDown(FALSE),
+ mMiddleMouseDown(FALSE),
+ mRightMouseDown(FALSE),
+ mMouseInWindow( FALSE ),
+ mLastMask( MASK_NONE ),
+ mToolStored( NULL ),
+ mHideCursorPermanent( FALSE ),
+ mCursorHidden(FALSE),
+ mIgnoreActivate( FALSE ),
+ mResDirty(false),
+ mStatesDirty(false),
+ mCurrResolutionIndex(0),
+ mViewerWindowListener(new LLViewerWindowListener(this)),
+ mProgressView(NULL)
+{
+ LLNotificationChannel::buildChannel("VW_alerts", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alert"));
+ LLNotificationChannel::buildChannel("VW_alertmodal", "Visible", LLNotificationFilters::filterBy<std::string>(&LLNotification::getType, "alertmodal"));
+
+ LLNotifications::instance().getChannel("VW_alerts")->connectChanged(&LLViewerWindow::onAlert);
+ LLNotifications::instance().getChannel("VW_alertmodal")->connectChanged(&LLViewerWindow::onAlert);
+ LLNotifications::instance().setIgnoreAllNotifications(gSavedSettings.getBOOL("IgnoreAllNotifications"));
+ llinfos << "NOTE: ALL NOTIFICATIONS THAT OCCUR WILL GET ADDED TO IGNORE LIST FOR LATER RUNS." << llendl;
+
+ // Default to application directory.
+ LLViewerWindow::sSnapshotBaseName = "Snapshot";
+ LLViewerWindow::sMovieBaseName = "SLmovie";
+ resetSnapshotLoc();
+
+ // create window
+ mWindow = LLWindowManager::createWindow(this,
+ title, name, x, y, width, height, 0,
+ fullscreen,
+ gNoRender,
+ gSavedSettings.getBOOL("DisableVerticalSync"),
+ !gNoRender,
+ ignore_pixel_depth,
+ gSavedSettings.getBOOL("RenderUseFBO") ? 0 : gSavedSettings.getU32("RenderFSAASamples")); //don't use window level anti-aliasing if FBOs are enabled
+
+ if (!LLAppViewer::instance()->restoreErrorTrap())
+ {
+ LL_WARNS("Window") << " Someone took over my signal/exception handler (post createWindow)!" << LL_ENDL;
+ }
+
+ LLCoordScreen scr;
+ mWindow->getSize(&scr);
+
+ if(fullscreen && ( scr.mX!=width || scr.mY!=height))
+ {
+ llwarns << "Fullscreen has forced us in to a different resolution now using "<<scr.mX<<" x "<<scr.mY<<llendl;
+ gSavedSettings.setS32("FullScreenWidth",scr.mX);
+ gSavedSettings.setS32("FullScreenHeight",scr.mY);
+ }
+
+ if (NULL == mWindow)
+ {
+ LLSplashScreen::update(LLTrans::getString("ShuttingDown"));
+#if LL_LINUX || LL_SOLARIS
+ llwarns << "Unable to create window, be sure screen is set at 32-bit color and your graphics driver is configured correctly. See README-linux.txt or README-solaris.txt for further information."
+ << llendl;
+#else
+ LL_WARNS("Window") << "Unable to create window, be sure screen is set at 32-bit color in Control Panels->Display->Settings"
+ << LL_ENDL;
+#endif
+ LLAppViewer::instance()->fastQuit(1);
+ }
+
+ // Get the real window rect the window was created with (since there are various OS-dependent reasons why
+ // the size of a window or fullscreen context may have been adjusted slightly...)
+ F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
+
+ mDisplayScale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
+ mDisplayScale *= ui_scale_factor;
+ LLUI::setScaleFactor(mDisplayScale);
+
+ {
+ LLCoordWindow size;
+ mWindow->getSize(&size);
+ mWindowRectRaw.set(0, size.mY, size.mX, 0);
+ mWindowRectScaled.set(0, llround((F32)size.mY / mDisplayScale.mV[VY]), llround((F32)size.mX / mDisplayScale.mV[VX]), 0);
+ }
+
+ LLFontManager::initClass();
+
+ //
+ // We want to set this stuff up BEFORE we initialize the pipeline, so we can turn off
+ // stuff like AGP if we think that it'll crash the viewer.
+ //
+ LL_DEBUGS("Window") << "Loading feature tables." << LL_ENDL;
+
+ LLFeatureManager::getInstance()->init();
+
+ // Initialize OpenGL Renderer
+ if (!LLFeatureManager::getInstance()->isFeatureAvailable("RenderVBOEnable") ||
+ !gGLManager.mHasVertexBufferObject)
+ {
+ gSavedSettings.setBOOL("RenderVBOEnable", FALSE);
+ }
+ LLVertexBuffer::initClass(gSavedSettings.getBOOL("RenderVBOEnable"), gSavedSettings.getBOOL("RenderVBOMappingDisable"));
+
+ if (LLFeatureManager::getInstance()->isSafe()
+ || (gSavedSettings.getS32("LastFeatureVersion") != LLFeatureManager::getInstance()->getVersion())
+ || (gSavedSettings.getS32("LastGPUClass") != LLFeatureManager::getInstance()->getGPUClass())
+ || (gSavedSettings.getBOOL("ProbeHardwareOnStartup")))
+ {
+ LLFeatureManager::getInstance()->applyRecommendedSettings();
+ gSavedSettings.setBOOL("ProbeHardwareOnStartup", FALSE);
+ }
+
+ if (!gGLManager.mHasDepthClamp)
+ {
+ LL_INFOS("RenderInit") << "Missing feature GL_ARB_depth_clamp. Void water might disappear in rare cases." << LL_ENDL;
+ }
+
+ // If we crashed while initializng GL stuff last time, disable certain features
+ if (gSavedSettings.getBOOL("RenderInitError"))
+ {
+ mInitAlert = "DisplaySettingsNoShaders";
+ LLFeatureManager::getInstance()->setGraphicsLevel(0, false);
+ gSavedSettings.setU32("RenderQualityPerformance", 0);
+ }
+
+ // Init the image list. Must happen after GL is initialized and before the images that
+ // LLViewerWindow needs are requested.
+ LLImageGL::initClass(LLViewerTexture::MAX_GL_IMAGE_CATEGORY) ;
+ gTextureList.init();
+ LLViewerTextureManager::init() ;
+ gBumpImageList.init();
+
+ // Init font system, but don't actually load the fonts yet
+ // because our window isn't onscreen and they take several
+ // seconds to parse.
+ LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
+ mDisplayScale.mV[VX],
+ mDisplayScale.mV[VY],
+ gDirUtilp->getAppRODataDir(),
+ LLUI::getXUIPaths());
+
+ // Create container for all sub-views
+ LLView::Params rvp;
+ rvp.name("root");
+ rvp.rect(mWindowRectScaled);
+ rvp.mouse_opaque(false);
+ rvp.follows.flags(FOLLOWS_NONE);
+ mRootView = LLUICtrlFactory::create<LLRootView>(rvp);
+ LLUI::setRootView(mRootView);
+
+ // Make avatar head look forward at start
+ mCurrentMousePoint.mX = getWindowWidthScaled() / 2;
+ mCurrentMousePoint.mY = getWindowHeightScaled() / 2;
+
+ gShowOverlayTitle = gSavedSettings.getBOOL("ShowOverlayTitle");
+ mOverlayTitle = gSavedSettings.getString("OverlayTitle");
+ // Can't have spaces in settings.ini strings, so use underscores instead and convert them.
+ LLStringUtil::replaceChar(mOverlayTitle, '_', ' ');
+
+ // sync the keyboard's setting with the saved setting
+ gSavedSettings.getControl("NumpadControl")->firePropertyChanged();
+
+ mDebugText = new LLDebugText(this);
+
+ mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
+}
+
+void LLViewerWindow::initGLDefaults()
+{
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE );
+
+ F32 ambient[4] = {0.f,0.f,0.f,0.f };
+ F32 diffuse[4] = {1.f,1.f,1.f,1.f };
+ glMaterialfv(GL_FRONT_AND_BACK,GL_AMBIENT,ambient);
+ glMaterialfv(GL_FRONT_AND_BACK,GL_DIFFUSE,diffuse);
+
+ glPixelStorei(GL_PACK_ALIGNMENT,1);
+ glPixelStorei(GL_UNPACK_ALIGNMENT,1);
+
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+
+ // lights for objects
+ glShadeModel( GL_SMOOTH );
+
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient);
+
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ glCullFace(GL_BACK);
+
+ // RN: Need this for translation and stretch manip.
+ gCone.prerender();
+ gBox.prerender();
+ gSphere.prerender();
+ gCylinder.prerender();
+}
+
+struct MainPanel : public LLPanel
+{
+};
+
+void LLViewerWindow::initBase()
+{
+ S32 height = getWindowHeightScaled();
+ S32 width = getWindowWidthScaled();
+
+ LLRect full_window(0, height, width, 0);
+
+ ////////////////////
+ //
+ // Set the gamma
+ //
+
+ F32 gamma = gSavedSettings.getF32("RenderGamma");
+ if (gamma != 0.0f)
+ {
+ getWindow()->setGamma(gamma);
+ }
+
+ // Create global views
+
+ // Create the floater view at the start so that other views can add children to it.
+ // (But wait to add it as a child of the root view so that it will be in front of the
+ // other views.)
+ MainPanel* main_view = new MainPanel();
+ main_view->buildFromFile("main_view.xml");
+ main_view->setShape(full_window);
+ getRootView()->addChild(main_view);
+
+ // placeholder widget that controls where "world" is rendered
+ mWorldViewPlaceholder = main_view->getChildView("world_view_rect")->getHandle();
+ mNonSideTrayView = main_view->getChildView("non_side_tray_view")->getHandle();
+ mFloaterViewHolder = main_view->getChildView("floater_view_holder")->getHandle();
+ mPopupView = main_view->getChild<LLPopupView>("popup_holder");
+ mHintHolder = main_view->getChild<LLView>("hint_holder")->getHandle();
+ mLoginPanelHolder = main_view->getChild<LLView>("login_panel_holder")->getHandle();
+
+ // Constrain floaters to inside the menu and status bar regions.
+ gFloaterView = main_view->getChild<LLFloaterView>("Floater View");
+ gFloaterView->setFloaterSnapView(main_view->getChild<LLView>("floater_snap_region")->getHandle());
+ gSnapshotFloaterView = main_view->getChild<LLSnapshotFloaterView>("Snapshot Floater View");
+
+
+ // Console
+ llassert( !gConsole );
+ LLConsole::Params cp;
+ cp.name("console");
+ cp.max_lines(gSavedSettings.getS32("ConsoleBufferSize"));
+ cp.rect(getChatConsoleRect());
+ cp.persist_time(gSavedSettings.getF32("ChatPersistTime"));
+ cp.font_size_index(gSavedSettings.getS32("ChatFontSize"));
+ cp.follows.flags(FOLLOWS_LEFT | FOLLOWS_RIGHT | FOLLOWS_BOTTOM);
+ gConsole = LLUICtrlFactory::create<LLConsole>(cp);
+ getRootView()->addChild(gConsole);
+
+ // optionally forward warnings to chat console/chat floater
+ // for qa runs and dev builds
+#if !LL_RELEASE_FOR_DOWNLOAD
+ LLError::addRecorder(RecordToChatConsole::getInstance());
+#else
+ if(gSavedSettings.getBOOL("QAMode"))
+ {
+ LLError::addRecorder(RecordToChatConsole::getInstance());
+ }
+#endif
+
+ gDebugView = getRootView()->getChild<LLDebugView>("DebugView");
+ gDebugView->init();
+ gToolTipView = getRootView()->getChild<LLToolTipView>("tooltip view");
+
+ // Initialize busy response message when logged in
+ LLAppViewer::instance()->setOnLoginCompletedCallback(boost::bind(&LLFloaterPreference::initBusyResponse));
+
+ // Add the progress bar view (startup view), which overrides everything
+ mProgressView = getRootView()->findChild<LLProgressView>("progress_view");
+ setShowProgress(FALSE);
+ setProgressCancelButtonVisible(FALSE);
+
+ gMenuHolder = getRootView()->getChild<LLViewerMenuHolderGL>("Menu Holder");
+
+ LLMenuGL::sMenuContainer = gMenuHolder;
+
+}
+
+void LLViewerWindow::initWorldUI()
+{
+ S32 height = mRootView->getRect().getHeight();
+ S32 width = mRootView->getRect().getWidth();
+ LLRect full_window(0, height, width, 0);
+
+
+ gIMMgr = LLIMMgr::getInstance();
+
+ //getRootView()->sendChildToFront(gFloaterView);
+ //getRootView()->sendChildToFront(gSnapshotFloaterView);
+
+ // new bottom panel
+ LLPanel* bottom_tray_container = getRootView()->getChild<LLPanel>("bottom_tray_container");
+ LLBottomTray* bottom_tray = LLBottomTray::getInstance();
+ bottom_tray->setShape(bottom_tray_container->getLocalRect());
+ bottom_tray->setFollowsAll();
+ bottom_tray_container->addChild(bottom_tray);
+ bottom_tray_container->setVisible(TRUE);
+
+ LLRect morph_view_rect = full_window;
+ morph_view_rect.stretch( -STATUS_BAR_HEIGHT );
+ morph_view_rect.mTop = full_window.mTop - 32;
+ LLMorphView::Params mvp;
+ mvp.name("MorphView");
+ mvp.rect(morph_view_rect);
+ mvp.visible(false);
+ gMorphView = LLUICtrlFactory::create<LLMorphView>(mvp);
+ getRootView()->addChild(gMorphView);
+
+ LLWorldMapView::initClass();
+
+ // Force gFloaterWorldMap to initialize
+ LLFloaterReg::getInstance("world_map");
+
+ // Force gFloaterTools to initialize
+ LLFloaterReg::getInstance("build");
+ LLFloaterReg::hideInstance("build");
+
+ // Status bar
+ LLPanel* status_bar_container = getRootView()->getChild<LLPanel>("status_bar_container");
+ gStatusBar = new LLStatusBar(status_bar_container->getLocalRect());
+ gStatusBar->setFollowsAll();
+ gStatusBar->setShape(status_bar_container->getLocalRect());
+ // sync bg color with menu bar
+ gStatusBar->setBackgroundColor( gMenuBarView->getBackgroundColor().get() );
+ status_bar_container->addChild(gStatusBar);
+ status_bar_container->setVisible(TRUE);
+
+ // Navigation bar
+ LLPanel* nav_bar_container = getRootView()->getChild<LLPanel>("nav_bar_container");
+
+ LLNavigationBar* navbar = LLNavigationBar::getInstance();
+ navbar->setShape(nav_bar_container->getLocalRect());
+ navbar->setBackgroundColor(gMenuBarView->getBackgroundColor().get());
+ nav_bar_container->addChild(navbar);
+ nav_bar_container->setVisible(TRUE);
+
+ if (!gSavedSettings.getBOOL("ShowNavbarNavigationPanel"))
+ {
+ navbar->showNavigationPanel(FALSE);
+ }
+
+ if (!gSavedSettings.getBOOL("ShowNavbarFavoritesPanel"))
+ {
+ navbar->showFavoritesPanel(FALSE);
+ }
+
+ // Top Info bar
+ LLPanel* topinfo_bar_container = getRootView()->getChild<LLPanel>("topinfo_bar_container");
+ LLPanelTopInfoBar* topinfo_bar = LLPanelTopInfoBar::getInstance();
+
+ topinfo_bar->setShape(topinfo_bar_container->getLocalRect());
+
+ topinfo_bar_container->addChild(topinfo_bar);
+ topinfo_bar_container->setVisible(TRUE);
+
+ if (!gSavedSettings.getBOOL("ShowMiniLocationPanel"))
+ {
+ topinfo_bar->setVisible(FALSE);
+ }
+
+ if ( gHUDView == NULL )
+ {
+ LLRect hud_rect = full_window;
+ hud_rect.mBottom += 50;
+ if (gMenuBarView && gMenuBarView->isInVisibleChain())
+ {
+ hud_rect.mTop -= gMenuBarView->getRect().getHeight();
+ }
+ gHUDView = new LLHUDView(hud_rect);
+ // put behind everything else in the UI
+ getRootView()->addChildInBack(gHUDView);
+ }
+
+ LLPanel* panel_ssf_container = getRootView()->getChild<LLPanel>("stand_stop_flying_container");
+ LLPanelStandStopFlying* panel_stand_stop_flying = LLPanelStandStopFlying::getInstance();
+ panel_ssf_container->addChild(panel_stand_stop_flying);
+ panel_ssf_container->setVisible(TRUE);
+
+ // put sidetray in container
+ LLPanel* side_tray_container = getRootView()->getChild<LLPanel>("side_tray_container");
+ LLSideTray* sidetrayp = LLSideTray::getInstance();
+ sidetrayp->setShape(side_tray_container->getLocalRect());
+ // don't follow right edge to avoid spurious resizes, since we are using a fixed width layout
+ sidetrayp->setFollows(FOLLOWS_LEFT|FOLLOWS_TOP|FOLLOWS_BOTTOM);
+ side_tray_container->addChild(sidetrayp);
+ side_tray_container->setVisible(FALSE);
+
+ // put sidetray buttons in their own panel
+ LLPanel* buttons_panel = sidetrayp->getButtonsPanel();
+ LLPanel* buttons_panel_container = getRootView()->getChild<LLPanel>("side_bar_tabs");
+ buttons_panel->setShape(buttons_panel_container->getLocalRect());
+ buttons_panel->setFollowsAll();
+ buttons_panel_container->addChild(buttons_panel);
+
+ LLView* avatar_picker_destination_guide_container = gViewerWindow->getRootView()->getChild<LLView>("avatar_picker_and_destination_guide_container");
+ avatar_picker_destination_guide_container->getChild<LLButton>("close")->setCommitCallback(boost::bind(toggle_destination_and_avatar_picker, LLSD()));
+ LLMediaCtrl* destinations = avatar_picker_destination_guide_container->findChild<LLMediaCtrl>("destination_guide_contents");
+ LLMediaCtrl* avatar_picker = avatar_picker_destination_guide_container->findChild<LLMediaCtrl>("avatar_picker_contents");
+ if (destinations)
+ {
+ destinations->navigateTo(gSavedSettings.getString("DestinationGuideURL"), "text/html");
+ }
+
+ if (avatar_picker)
+ {
+ avatar_picker->navigateTo(gSavedSettings.getString("AvatarPickerURL"), "text/html");
+ }
+
+}
+
+// Destroy the UI
+void LLViewerWindow::shutdownViews()
+{
+ // clean up warning logger
+ LLError::removeRecorder(RecordToChatConsole::getInstance());
+
+ delete mDebugText;
+ mDebugText = NULL;
+
+ // Cleanup global views
+ if (gMorphView)
+ {
+ gMorphView->setVisible(FALSE);
+ }
+
+ // DEV-40930: Clear sModalStack. Otherwise, any LLModalDialog left open
+ // will crump with LL_ERRS.
+ LLModalDialog::shutdownModals();
+
+ // destroy the nav bar, not currently part of gViewerWindow
+ // *TODO: Make LLNavigationBar part of gViewerWindow
+ delete LLNavigationBar::getInstance();
+
+ // destroy menus after instantiating navbar above, as it needs
+ // access to gMenuHolder
+ cleanup_menus();
+
+ // Delete all child views.
+ delete mRootView;
+ mRootView = NULL;
+
+ // Automatically deleted as children of mRootView. Fix the globals.
+ gStatusBar = NULL;
+ gIMMgr = NULL;
+ gToolTipView = NULL;
+
+ gFloaterView = NULL;
+ gMorphView = NULL;
+
+ gHUDView = NULL;
+}
+
+void LLViewerWindow::shutdownGL()
+{
+ //--------------------------------------------------------
+ // Shutdown GL cleanly. Order is very important here.
+ //--------------------------------------------------------
+ LLFontGL::destroyDefaultFonts();
+ LLFontManager::cleanupClass();
+ stop_glerror();
+
+ gSky.cleanup();
+ stop_glerror();
+
+ LLWearableList::instance().cleanup() ;
+
+ gTextureList.shutdown();
+ stop_glerror();
+
+ gBumpImageList.shutdown();
+ stop_glerror();
+
+ LLWorldMapView::cleanupTextures();
+
+ llinfos << "Cleaning up pipeline" << llendl;
+ gPipeline.cleanup();
+ stop_glerror();
+
+ LLViewerTextureManager::cleanup() ;
+ LLImageGL::cleanupClass() ;
+
+ llinfos << "All textures and llimagegl images are destroyed!" << llendl ;
+
+ llinfos << "Cleaning up select manager" << llendl;
+ LLSelectMgr::getInstance()->cleanup();
+
+ LLVertexBuffer::cleanupClass();
+
+ llinfos << "Stopping GL during shutdown" << llendl;
+ if (!gNoRender)
+ {
+ stopGL(FALSE);
+ stop_glerror();
+ }
+
+ gGL.shutdown();
+}
+
+// shutdownViews() and shutdownGL() need to be called first
+LLViewerWindow::~LLViewerWindow()
+{
+ llinfos << "Destroying Window" << llendl;
+ destroyWindow();
+
+ delete mDebugText;
+ mDebugText = NULL;
+}
+
+
+void LLViewerWindow::setCursor( ECursorType c )
+{
+ mWindow->setCursor( c );
+}
+
+void LLViewerWindow::showCursor()
+{
+ mWindow->showCursor();
+
+ mCursorHidden = FALSE;
+}
+
+void LLViewerWindow::hideCursor()
+{
+ // And hide the cursor
+ mWindow->hideCursor();
+
+ mCursorHidden = TRUE;
+}
+
+void LLViewerWindow::sendShapeToSim()
+{
+ LLMessageSystem* msg = gMessageSystem;
+ if(!msg) return;
+ msg->newMessageFast(_PREHASH_AgentHeightWidth);
+ msg->nextBlockFast(_PREHASH_AgentData);
+ msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
+ msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
+ msg->addU32Fast(_PREHASH_CircuitCode, gMessageSystem->mOurCircuitCode);
+ msg->nextBlockFast(_PREHASH_HeightWidthBlock);
+ msg->addU32Fast(_PREHASH_GenCounter, 0);
+ U16 height16 = (U16) mWorldViewRectRaw.getHeight();
+ U16 width16 = (U16) mWorldViewRectRaw.getWidth();
+ msg->addU16Fast(_PREHASH_Height, height16);
+ msg->addU16Fast(_PREHASH_Width, width16);
+ gAgent.sendReliableMessage();
+}
+
+// Must be called after window is created to set up agent
+// camera variables and UI variables.
+void LLViewerWindow::reshape(S32 width, S32 height)
+{
+ // Destroying the window at quit time generates spurious
+ // reshape messages. We don't care about these, and we
+ // don't want to send messages because the message system
+ // may have been destructed.
+ if (!LLApp::isExiting())
+ {
+ if (gNoRender)
+ {
+ return;
+ }
+
+ gWindowResized = TRUE;
+
+ // update our window rectangle
+ mWindowRectRaw.mRight = mWindowRectRaw.mLeft + width;
+ mWindowRectRaw.mTop = mWindowRectRaw.mBottom + height;
+
+ //glViewport(0, 0, width, height );
+
+ if (height > 0)
+ {
+ LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
+ LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
+ }
+
+ calcDisplayScale();
+
+ BOOL display_scale_changed = mDisplayScale != LLUI::sGLScaleFactor;
+ LLUI::setScaleFactor(mDisplayScale);
+
+ // update our window rectangle
+ mWindowRectScaled.mRight = mWindowRectScaled.mLeft + llround((F32)width / mDisplayScale.mV[VX]);
+ mWindowRectScaled.mTop = mWindowRectScaled.mBottom + llround((F32)height / mDisplayScale.mV[VY]);
+
+ setup2DViewport();
+
+ // Inform lower views of the change
+ // round up when converting coordinates to make sure there are no gaps at edge of window
+ LLView::sForceReshape = display_scale_changed;
+ mRootView->reshape(llceil((F32)width / mDisplayScale.mV[VX]), llceil((F32)height / mDisplayScale.mV[VY]));
+ LLView::sForceReshape = FALSE;
+
+ // clear font width caches
+ if (display_scale_changed)
+ {
+ LLHUDObject::reshapeAll();
+ }
+
+ sendShapeToSim();
+
+ // store new settings for the mode we are in, regardless
+ // Only save size if not maximized
+ BOOL maximized = mWindow->getMaximized();
+ gSavedSettings.setBOOL("WindowMaximized", maximized);
+
+ LLCoordScreen window_size;
+ if (!maximized
+ && mWindow->getSize(&window_size))
+ {
+ gSavedSettings.setS32("WindowWidth", window_size.mX);
+ gSavedSettings.setS32("WindowHeight", window_size.mY);
+ }
+
+ LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_WIDTH, (F64)width);
+ LLViewerStats::getInstance()->setStat(LLViewerStats::ST_WINDOW_HEIGHT, (F64)height);
+ }
+}
+
+
+// Hide normal UI when a logon fails
+void LLViewerWindow::setNormalControlsVisible( BOOL visible )
+{
+ if(LLBottomTray::instanceExists())
+ {
+ LLBottomTray::getInstance()->setVisible(visible);
+ LLBottomTray::getInstance()->setEnabled(visible);
+ }
+
+ if ( gMenuBarView )
+ {
+ gMenuBarView->setVisible( visible );
+ gMenuBarView->setEnabled( visible );
+
+ // ...and set the menu color appropriately.
+ setMenuBackgroundColor(gAgent.getGodLevel() > GOD_NOT,
+ LLGridManager::getInstance()->isInProductionGrid());
+ }
+
+ if ( gStatusBar )
+ {
+ gStatusBar->setVisible( visible );
+ gStatusBar->setEnabled( visible );
+ }
+
+ LLNavigationBar* navbarp = LLUI::getRootView()->findChild<LLNavigationBar>("navigation_bar");
+ if (navbarp)
+ {
+ navbarp->setVisible( visible );
+ }
+}
+
+void LLViewerWindow::setMenuBackgroundColor(bool god_mode, bool dev_grid)
+{
+ LLSD args;
+ LLColor4 new_bg_color;
+
+ // no l10n problem because channel is always an english string
+ std::string channel = LLVersionInfo::getChannel();
+ bool isProject = (channel.find("Project") != std::string::npos);
+
+ // god more important than project, proj more important than grid
+ if(god_mode && LLGridManager::getInstance()->isInProductionGrid())
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarGodBgColor" );
+ }
+ else if(god_mode && !LLGridManager::getInstance()->isInProductionGrid())
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionGodBgColor" );
+ }
+ else if (!god_mode && isProject)
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarProjectBgColor" );
+ }
+ else if(!god_mode && !LLGridManager::getInstance()->isInProductionGrid())
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuNonProductionBgColor" );
+ }
+ else
+ {
+ new_bg_color = LLUIColorTable::instance().getColor( "MenuBarBgColor" );
+ }
+
+ if(gMenuBarView)
+ {
+ gMenuBarView->setBackgroundColor( new_bg_color );
+ }
+
+ if(gStatusBar)
+ {
+ gStatusBar->setBackgroundColor( new_bg_color );
+ }
+}
+
+void LLViewerWindow::drawDebugText()
+{
+ gGL.color4f(1,1,1,1);
+ gGL.pushMatrix();
+ gGL.pushUIMatrix();
+ {
+ // scale view by UI global scale factor and aspect ratio correction factor
+ gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
+ mDebugText->draw();
+ }
+ gGL.popUIMatrix();
+ gGL.popMatrix();
+
+ gGL.flush();
+}
+
+void LLViewerWindow::draw()
+{
+
+//#if LL_DEBUG
+ LLView::sIsDrawing = TRUE;
+//#endif
+ stop_glerror();
+
+ LLUI::setLineWidth(1.f);
+
+ LLUI::setLineWidth(1.f);
+ // Reset any left-over transforms
+ glMatrixMode(GL_MODELVIEW);
+
+ glLoadIdentity();
+
+ //S32 screen_x, screen_y;
+
+ if (!gSavedSettings.getBOOL("RenderUIBuffer"))
+ {
+ LLUI::sDirtyRect = getWindowRectScaled();
+ }
+
+ // HACK for timecode debugging
+ if (gSavedSettings.getBOOL("DisplayTimecode"))
+ {
+ // draw timecode block
+ std::string text;
+
+ glLoadIdentity();
+
+ microsecondsToTimecodeString(gFrameTime,text);
+ const LLFontGL* font = LLFontGL::getFontSansSerif();
+ font->renderUTF8(text, 0,
+ llround((getWindowWidthScaled()/2)-100.f),
+ llround((getWindowHeightScaled()-60.f)),
+ LLColor4( 1.f, 1.f, 1.f, 1.f ),
+ LLFontGL::LEFT, LLFontGL::TOP);
+ }
+
+ // Draw all nested UI views.
+ // No translation needed, this view is glued to 0,0
+
+ gGL.pushMatrix();
+ LLUI::pushMatrix();
+ {
+
+ // scale view by UI global scale factor and aspect ratio correction factor
+ gGL.scaleUI(mDisplayScale.mV[VX], mDisplayScale.mV[VY], 1.f);
+
+ LLVector2 old_scale_factor = LLUI::sGLScaleFactor;
+ // apply camera zoom transform (for high res screenshots)
+ F32 zoom_factor = LLViewerCamera::getInstance()->getZoomFactor();
+ S16 sub_region = LLViewerCamera::getInstance()->getZoomSubRegion();
+ if (zoom_factor > 1.f)
+ {
+ //decompose subregion number to x and y values
+ int pos_y = sub_region / llceil(zoom_factor);
+ int pos_x = sub_region - (pos_y*llceil(zoom_factor));
+ // offset for this tile
+ glTranslatef((F32)getWindowWidthScaled() * -(F32)pos_x,
+ (F32)getWindowHeightScaled() * -(F32)pos_y,
+ 0.f);
+ glScalef(zoom_factor, zoom_factor, 1.f);
+ LLUI::sGLScaleFactor *= zoom_factor;
+ }
+
+ // Draw tool specific overlay on world
+ LLToolMgr::getInstance()->getCurrentTool()->draw();
+
+ if( gAgentCamera.cameraMouselook() || LLFloaterCamera::inFreeCameraMode() )
+ {
+ drawMouselookInstructions();
+ stop_glerror();
+ }
+
+ // Draw all nested UI views.
+ // No translation needed, this view is glued to 0,0
+ mRootView->draw();
+
+ if (LLView::sDebugRects)
+ {
+ gToolTipView->drawStickyRect();
+ }
+
+ // Draw optional on-top-of-everyone view
+ LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ if (top_ctrl && top_ctrl->getVisible())
+ {
+ S32 screen_x, screen_y;
+ top_ctrl->localPointToScreen(0, 0, &screen_x, &screen_y);
+
+ glMatrixMode(GL_MODELVIEW);
+ LLUI::pushMatrix();
+ LLUI::translate( (F32) screen_x, (F32) screen_y, 0.f);
+ top_ctrl->draw();
+ LLUI::popMatrix();
+ }
+
+
+ if( gShowOverlayTitle && !mOverlayTitle.empty() )
+ {
+ // Used for special titles such as "Second Life - Special E3 2003 Beta"
+ const S32 DIST_FROM_TOP = 20;
+ LLFontGL::getFontSansSerifBig()->renderUTF8(
+ mOverlayTitle, 0,
+ llround( getWindowWidthScaled() * 0.5f),
+ getWindowHeightScaled() - DIST_FROM_TOP,
+ LLColor4(1, 1, 1, 0.4f),
+ LLFontGL::HCENTER, LLFontGL::TOP);
+ }
+
+ LLUI::sGLScaleFactor = old_scale_factor;
+ }
+ LLUI::popMatrix();
+ gGL.popMatrix();
+
+//#if LL_DEBUG
+ LLView::sIsDrawing = FALSE;
+//#endif
+}
+
+// Takes a single keydown event, usually when UI is visible
+BOOL LLViewerWindow::handleKey(KEY key, MASK mask)
+{
+ // hide tooltips on keypress
+ LLToolTipMgr::instance().blockToolTips();
+
+ if (gFocusMgr.getKeyboardFocus()
+ && !(mask & (MASK_CONTROL | MASK_ALT))
+ && !gFocusMgr.getKeystrokesOnly())
+ {
+ // We have keyboard focus, and it's not an accelerator
+ if (key < 0x80)
+ {
+ // Not a special key, so likely (we hope) to generate a character. Let it fall through to character handler first.
+ return (gFocusMgr.getKeyboardFocus() != NULL);
+ }
+ }
+
+ // let menus handle navigation keys for navigation
+ if ((gMenuBarView && gMenuBarView->handleKey(key, mask, TRUE))
+ ||(gLoginMenuBarView && gLoginMenuBarView->handleKey(key, mask, TRUE))
+ ||(gMenuHolder && gMenuHolder->handleKey(key, mask, TRUE)))
+ {
+ return TRUE;
+ }
+
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+
+ // give menus a chance to handle modified (Ctrl, Alt) shortcut keys before current focus
+ // as long as focus isn't locked
+ if (mask & (MASK_CONTROL | MASK_ALT) && !gFocusMgr.focusLocked())
+ {
+ // Check the current floater's menu first, if it has one.
+ if (gFocusMgr.keyboardFocusHasAccelerators()
+ && keyboard_focus
+ && keyboard_focus->handleKey(key,mask,FALSE))
+ {
+ return TRUE;
+ }
+
+ if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
+ ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
+ {
+ return TRUE;
+ }
+ }
+
+ // give floaters first chance to handle TAB key
+ // so frontmost floater gets focus
+ // if nothing has focus, go to first or last UI element as appropriate
+ if (key == KEY_TAB && (mask & MASK_CONTROL || gFocusMgr.getKeyboardFocus() == NULL))
+ {
+ if (gMenuHolder) gMenuHolder->hideMenus();
+
+ // if CTRL-tabbing (and not just TAB with no focus), go into window cycle mode
+ gFloaterView->setCycleMode((mask & MASK_CONTROL) != 0);
+
+ // do CTRL-TAB and CTRL-SHIFT-TAB logic
+ if (mask & MASK_SHIFT)
+ {
+ mRootView->focusPrevRoot();
+ }
+ else
+ {
+ mRootView->focusNextRoot();
+ }
+ return TRUE;
+ }
+ // hidden edit menu for cut/copy/paste
+ if (gEditMenu && gEditMenu->handleAcceleratorKey(key, mask))
+ {
+ return TRUE;
+ }
+
+ // Traverses up the hierarchy
+ if( keyboard_focus )
+ {
+ LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL;
+ // arrow keys move avatar while chatting hack
+ if (chat_editor && chat_editor->hasFocus())
+ {
+ // If text field is empty, there's no point in trying to move
+ // cursor with arrow keys, so allow movement
+ if (chat_editor->getText().empty()
+ || gSavedSettings.getBOOL("ArrowKeysAlwaysMove"))
+ {
+ // let Control-Up and Control-Down through for chat line history,
+ if (!(key == KEY_UP && mask == MASK_CONTROL)
+ && !(key == KEY_DOWN && mask == MASK_CONTROL))
+ {
+ switch(key)
+ {
+ case KEY_LEFT:
+ case KEY_RIGHT:
+ case KEY_UP:
+ case KEY_DOWN:
+ case KEY_PAGE_UP:
+ case KEY_PAGE_DOWN:
+ case KEY_HOME:
+ // when chatbar is empty or ArrowKeysAlwaysMove set,
+ // pass arrow keys on to avatar...
+ return FALSE;
+ default:
+ break;
+ }
+ }
+ }
+ }
+
+ if (keyboard_focus->handleKey(key, mask, FALSE))
+ {
+ return TRUE;
+ }
+ }
+
+ if( LLToolMgr::getInstance()->getCurrentTool()->handleKey(key, mask) )
+ {
+ return TRUE;
+ }
+
+ // Try for a new-format gesture
+ if (LLGestureMgr::instance().triggerGesture(key, mask))
+ {
+ return TRUE;
+ }
+
+ // See if this is a gesture trigger. If so, eat the key and
+ // don't pass it down to the menus.
+ if (gGestureList.trigger(key, mask))
+ {
+ return TRUE;
+ }
+
+ // If "Pressing letter keys starts local chat" option is selected, we are not in mouselook,
+ // no view has keyboard focus, this is a printable character key (and no modifier key is
+ // pressed except shift), then give focus to nearby chat (STORM-560)
+ if ( gSavedSettings.getS32("LetterKeysFocusChatBar") && !gAgentCamera.cameraMouselook() &&
+ !keyboard_focus && key < 0x80 && (mask == MASK_NONE || mask == MASK_SHIFT) )
+ {
+ LLLineEditor* chat_editor = LLBottomTray::instanceExists() ? LLBottomTray::getInstance()->getNearbyChatBar()->getChatBox() : NULL;
+ if (chat_editor)
+ {
+ // passing NULL here, character will be added later when it is handled by character handler.
+ LLBottomTray::getInstance()->getNearbyChatBar()->startChat(NULL);
+ return TRUE;
+ }
+ }
+
+ // give menus a chance to handle unmodified accelerator keys
+ if ((gMenuBarView && gMenuBarView->handleAcceleratorKey(key, mask))
+ ||(gLoginMenuBarView && gLoginMenuBarView->handleAcceleratorKey(key, mask)))
+ {
+ return TRUE;
+ }
+
+ // don't pass keys on to world when something in ui has focus
+ return gFocusMgr.childHasKeyboardFocus(mRootView)
+ || LLMenuGL::getKeyboardMode()
+ || (gMenuBarView && gMenuBarView->getHighlightedItem() && gMenuBarView->getHighlightedItem()->isActive());
+}
+
+
+BOOL LLViewerWindow::handleUnicodeChar(llwchar uni_char, MASK mask)
+{
+ // HACK: We delay processing of return keys until they arrive as a Unicode char,
+ // so that if you're typing chat text at low frame rate, we don't send the chat
+ // until all keystrokes have been entered. JC
+ // HACK: Numeric keypad <enter> on Mac is Unicode 3
+ // HACK: Control-M on Windows is Unicode 13
+ if ((uni_char == 13 && mask != MASK_CONTROL)
+ || (uni_char == 3 && mask == MASK_NONE))
+ {
+ return gViewerKeyboard.handleKey(KEY_RETURN, mask, gKeyboard->getKeyRepeated(KEY_RETURN));
+ }
+
+ // let menus handle navigation (jump) keys
+ if (gMenuBarView && gMenuBarView->handleUnicodeChar(uni_char, TRUE))
+ {
+ return TRUE;
+ }
+
+ // Traverses up the hierarchy
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+ if( keyboard_focus )
+ {
+ if (keyboard_focus->handleUnicodeChar(uni_char, FALSE))
+ {
+ return TRUE;
+ }
+
+ //// Topmost view gets a chance before the hierarchy
+ //LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ //if (top_ctrl && top_ctrl->handleUnicodeChar( uni_char, FALSE ) )
+ //{
+ // return TRUE;
+ //}
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+void LLViewerWindow::handleScrollWheel(S32 clicks)
+{
+ LLView::sMouseHandlerMessage.clear();
+
+ LLUI::resetMouseIdleTimer();
+
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ if( mouse_captor )
+ {
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
+ mouse_captor->handleScrollWheel(local_x, local_y, clicks);
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << "Scroll Wheel handled by captor " << mouse_captor->getName() << llendl;
+ }
+ return;
+ }
+
+ LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ if (top_ctrl)
+ {
+ S32 local_x;
+ S32 local_y;
+ top_ctrl->screenPointToLocal( mCurrentMousePoint.mX, mCurrentMousePoint.mY, &local_x, &local_y );
+ if (top_ctrl->handleScrollWheel(local_x, local_y, clicks)) return;
+ }
+
+ if (mRootView->handleScrollWheel(mCurrentMousePoint.mX, mCurrentMousePoint.mY, clicks) )
+ {
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << "Scroll Wheel" << LLView::sMouseHandlerMessage << llendl;
+ }
+ return;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ llinfos << "Scroll Wheel not handled by view" << llendl;
+ }
+
+ // Zoom the camera in and out behavior
+
+ if(top_ctrl == 0
+ && getWorldViewRectScaled().pointInRect(mCurrentMousePoint.mX, mCurrentMousePoint.mY)
+ && gAgentCamera.isInitialized())
+ gAgentCamera.handleScrollWheel(clicks);
+
+ return;
+}
+
+void LLViewerWindow::addPopup(LLView* popup)
+{
+ if (mPopupView)
+ {
+ mPopupView->addPopup(popup);
+ }
+}
+
+void LLViewerWindow::removePopup(LLView* popup)
+{
+ if (mPopupView)
+ {
+ mPopupView->removePopup(popup);
+ }
+}
+
+void LLViewerWindow::clearPopups()
+{
+ if (mPopupView)
+ {
+ mPopupView->clearPopups();
+ }
+}
+
+void LLViewerWindow::moveCursorToCenter()
+{
+ if (! gSavedSettings.getBOOL("DisableMouseWarp"))
+ {
+ S32 x = getWorldViewWidthScaled() / 2;
+ S32 y = getWorldViewHeightScaled() / 2;
+
+ //on a forced move, all deltas get zeroed out to prevent jumping
+ mCurrentMousePoint.set(x,y);
+ mLastMousePoint.set(x,y);
+ mCurrentMouseDelta.set(0,0);
+
+ LLUI::setMousePositionScreen(x, y);
+ }
+}
+
+
+//////////////////////////////////////////////////////////////////////
+//
+// Hover handlers
+//
+
+void append_xui_tooltip(LLView* viewp, LLToolTip::Params& params)
+{
+ if (viewp)
+ {
+ if (!params.styled_message.empty())
+ {
+ params.styled_message.add().text("\n---------\n");
+ }
+ LLView::root_to_view_iterator_t end_tooltip_it = viewp->endRootToView();
+ // NOTE: we skip "root" since it is assumed
+ for (LLView::root_to_view_iterator_t tooltip_it = ++viewp->beginRootToView();
+ tooltip_it != end_tooltip_it;
+ ++tooltip_it)
+ {
+ LLView* viewp = *tooltip_it;
+
+ params.styled_message.add().text(viewp->getName());
+
+ LLPanel* panelp = dynamic_cast<LLPanel*>(viewp);
+ if (panelp && !panelp->getXMLFilename().empty())
+ {
+ params.styled_message.add()
+ .text("(" + panelp->getXMLFilename() + ")")
+ .style.color(LLColor4(0.7f, 0.7f, 1.f, 1.f));
+ }
+ params.styled_message.add().text("/");
+ }
+ }
+}
+
+// Update UI based on stored mouse position from mouse-move
+// event processing.
+void LLViewerWindow::updateUI()
+{
+ static LLFastTimer::DeclareTimer ftm("Update UI");
+ LLFastTimer t(ftm);
+
+ static std::string last_handle_msg;
+
+ if (gLoggedInTime.getStarted())
+ {
+ if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("DestinationGuideHintTimeout"))
+ {
+ LLFirstUse::notUsingDestinationGuide();
+ }
+ if (gLoggedInTime.getElapsedTimeF32() > gSavedSettings.getF32("SidePanelHintTimeout"))
+ {
+ LLFirstUse::notUsingSidePanel();
+ }
+ }
+
+ LLConsole::updateClass();
+
+ // animate layout stacks so we have up to date rect for world view
+ LLLayoutStack::updateClass();
+
+ // use full window for world view when not rendering UI
+ bool world_view_uses_full_window = gAgentCamera.cameraMouselook() || !gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ updateWorldViewRect(world_view_uses_full_window);
+
+ LLView::sMouseHandlerMessage.clear();
+
+ S32 x = mCurrentMousePoint.mX;
+ S32 y = mCurrentMousePoint.mY;
+ MASK mask = gKeyboard->currentMask(TRUE);
+
+ if (gNoRender)
+ {
+ return;
+ }
+
+ if (gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_RAYCAST))
+ {
+ gDebugRaycastFaceHit = -1;
+ gDebugRaycastObject = cursorIntersect(-1, -1, 512.f, NULL, -1, FALSE,
+ &gDebugRaycastFaceHit,
+ &gDebugRaycastIntersection,
+ &gDebugRaycastTexCoord,
+ &gDebugRaycastNormal,
+ &gDebugRaycastBinormal);
+ }
+
+ updateMouseDelta();
+ updateKeyboardFocus();
+
+ BOOL handled = FALSE;
+
+ BOOL handled_by_top_ctrl = FALSE;
+ LLUICtrl* top_ctrl = gFocusMgr.getTopCtrl();
+ LLMouseHandler* mouse_captor = gFocusMgr.getMouseCapture();
+ LLView* captor_view = dynamic_cast<LLView*>(mouse_captor);
+
+ //FIXME: only include captor and captor's ancestors if mouse is truly over them --RN
+
+ //build set of views containing mouse cursor by traversing UI hierarchy and testing
+ //screen rect against mouse cursor
+ view_handle_set_t mouse_hover_set;
+
+ // constraint mouse enter events to children of mouse captor
+ LLView* root_view = captor_view;
+
+ // if mouse captor doesn't exist or isn't a LLView
+ // then allow mouse enter events on entire UI hierarchy
+ if (!root_view)
+ {
+ root_view = mRootView;
+ }
+
+ // only update mouse hover set when UI is visible (since we shouldn't send hover events to invisible UI
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ // include all ancestors of captor_view as automatically having mouse
+ if (captor_view)
+ {
+ LLView* captor_parent_view = captor_view->getParent();
+ while(captor_parent_view)
+ {
+ mouse_hover_set.insert(captor_parent_view->getHandle());
+ captor_parent_view = captor_parent_view->getParent();
+ }
+ }
+
+ // aggregate visible views that contain mouse cursor in display order
+ LLPopupView::popup_list_t popups = mPopupView->getCurrentPopups();
+
+ for(LLPopupView::popup_list_t::iterator popup_it = popups.begin(); popup_it != popups.end(); ++popup_it)
+ {
+ LLView* popup = popup_it->get();
+ if (popup && popup->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // iterator over contents of top_ctrl, and throw into mouse_hover_set
+ for (LLView::tree_iterator_t it = popup->beginTreeDFS();
+ it != popup->endTreeDFS();
+ ++it)
+ {
+ LLView* viewp = *it;
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
+ {
+ // skip this view and all of its children
+ it.skipDescendants();
+ }
+ }
+ }
+ }
+
+ // while the top_ctrl contains the mouse cursor, only it and its descendants will receive onMouseEnter events
+ if (top_ctrl && top_ctrl->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // iterator over contents of top_ctrl, and throw into mouse_hover_set
+ for (LLView::tree_iterator_t it = top_ctrl->beginTreeDFS();
+ it != top_ctrl->endTreeDFS();
+ ++it)
+ {
+ LLView* viewp = *it;
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
+ {
+ // skip this view and all of its children
+ it.skipDescendants();
+ }
+ }
+ }
+ else
+ {
+ // walk UI tree in depth-first order
+ for (LLView::tree_iterator_t it = root_view->beginTreeDFS();
+ it != root_view->endTreeDFS();
+ ++it)
+ {
+ LLView* viewp = *it;
+ // calculating the screen rect involves traversing the parent, so this is less than optimal
+ if (viewp->getVisible()
+ && viewp->calcScreenBoundingRect().pointInRect(x, y))
+ {
+
+ // if this view is mouse opaque, nothing behind it should be in mouse_hover_set
+ if (viewp->getMouseOpaque())
+ {
+ // constrain further iteration to children of this widget
+ it = viewp->beginTreeDFS();
+ }
+
+ // we have a view that contains the mouse, add it to the set
+ mouse_hover_set.insert(viewp->getHandle());
+ }
+ else
+ {
+ // skip this view and all of its children
+ it.skipDescendants();
+ }
+ }
+ }
+ }
+
+ typedef std::vector<LLHandle<LLView> > view_handle_list_t;
+
+ // call onMouseEnter() on all views which contain the mouse cursor but did not before
+ view_handle_list_t mouse_enter_views;
+ std::set_difference(mouse_hover_set.begin(), mouse_hover_set.end(),
+ mMouseHoverViews.begin(), mMouseHoverViews.end(),
+ std::back_inserter(mouse_enter_views));
+ for (view_handle_list_t::iterator it = mouse_enter_views.begin();
+ it != mouse_enter_views.end();
+ ++it)
+ {
+ LLView* viewp = it->get();
+ if (viewp)
+ {
+ LLRect view_screen_rect = viewp->calcScreenRect();
+ viewp->onMouseEnter(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
+ }
+ }
+
+ // call onMouseLeave() on all views which no longer contain the mouse cursor
+ view_handle_list_t mouse_leave_views;
+ std::set_difference(mMouseHoverViews.begin(), mMouseHoverViews.end(),
+ mouse_hover_set.begin(), mouse_hover_set.end(),
+ std::back_inserter(mouse_leave_views));
+ for (view_handle_list_t::iterator it = mouse_leave_views.begin();
+ it != mouse_leave_views.end();
+ ++it)
+ {
+ LLView* viewp = it->get();
+ if (viewp)
+ {
+ LLRect view_screen_rect = viewp->calcScreenRect();
+ viewp->onMouseLeave(x - view_screen_rect.mLeft, y - view_screen_rect.mBottom, mask);
+ }
+ }
+
+ // store resulting hover set for next frame
+ swap(mMouseHoverViews, mouse_hover_set);
+
+ // only handle hover events when UI is enabled
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+
+ if( mouse_captor )
+ {
+ // Pass hover events to object capturing mouse events.
+ S32 local_x;
+ S32 local_y;
+ mouse_captor->screenPointToLocal( x, y, &local_x, &local_y );
+ handled = mouse_captor->handleHover(local_x, local_y, mask);
+ if (LLView::sDebugMouseHandling)
+ {
+ llinfos << "Hover handled by captor " << mouse_captor->getName() << llendl;
+ }
+
+ if( !handled )
+ {
+ lldebugst(LLERR_USER_INPUT) << "hover not handled by mouse captor" << llendl;
+ }
+ }
+ else
+ {
+ if (top_ctrl)
+ {
+ S32 local_x, local_y;
+ top_ctrl->screenPointToLocal( x, y, &local_x, &local_y );
+ handled = top_ctrl->pointInView(local_x, local_y) && top_ctrl->handleHover(local_x, local_y, mask);
+ handled_by_top_ctrl = TRUE;
+ }
+
+ if ( !handled )
+ {
+ // x and y are from last time mouse was in window
+ // mMouseInWindow tracks *actual* mouse location
+ if (mMouseInWindow && mRootView->handleHover(x, y, mask) )
+ {
+ if (LLView::sDebugMouseHandling && LLView::sMouseHandlerMessage != last_handle_msg)
+ {
+ last_handle_msg = LLView::sMouseHandlerMessage;
+ llinfos << "Hover" << LLView::sMouseHandlerMessage << llendl;
+ }
+ handled = TRUE;
+ }
+ else if (LLView::sDebugMouseHandling)
+ {
+ if (last_handle_msg != LLStringUtil::null)
+ {
+ last_handle_msg.clear();
+ llinfos << "Hover not handled by view" << llendl;
+ }
+ }
+ }
+
+ if (!handled)
+ {
+ LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
+
+ if(mMouseInWindow && tool)
+ {
+ handled = tool->handleHover(x, y, mask);
+ }
+ }
+ }
+
+ // Show a new tool tip (or update one that is already shown)
+ BOOL tool_tip_handled = FALSE;
+ std::string tool_tip_msg;
+ if( handled
+ && !mWindow->isCursorHidden())
+ {
+ LLRect screen_sticky_rect = mRootView->getLocalRect();
+ S32 local_x, local_y;
+
+ if (gSavedSettings.getBOOL("DebugShowXUINames"))
+ {
+ LLToolTip::Params params;
+
+ LLView* tooltip_view = mRootView;
+ LLView::tree_iterator_t end_it = mRootView->endTreeDFS();
+ for (LLView::tree_iterator_t it = mRootView->beginTreeDFS(); it != end_it; ++it)
+ {
+ LLView* viewp = *it;
+ LLRect screen_rect;
+ viewp->localRectToScreen(viewp->getLocalRect(), &screen_rect);
+ if (!(viewp->getVisible()
+ && screen_rect.pointInRect(x, y)))
+ {
+ it.skipDescendants();
+ }
+ // only report xui names for LLUICtrls,
+ // and blacklist the various containers we don't care about
+ else if (dynamic_cast<LLUICtrl*>(viewp)
+ && viewp != gMenuHolder
+ && viewp != gFloaterView
+ && viewp != gConsole)
+ {
+ if (dynamic_cast<LLFloater*>(viewp))
+ {
+ // constrain search to descendants of this (frontmost) floater
+ // by resetting iterator
+ it = viewp->beginTreeDFS();
+ }
+
+ // if we are in a new part of the tree (not a descendent of current tooltip_view)
+ // then push the results for tooltip_view and start with a new potential view
+ // NOTE: this emulates visiting only the leaf nodes that meet our criteria
+ if (!viewp->hasAncestor(tooltip_view))
+ {
+ append_xui_tooltip(tooltip_view, params);
+ screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
+ }
+ tooltip_view = viewp;
+ }
+ }
+
+ append_xui_tooltip(tooltip_view, params);
+ screen_sticky_rect.intersectWith(tooltip_view->calcScreenRect());
+
+ params.sticky_rect = screen_sticky_rect;
+ params.max_width = 400;
+
+ LLToolTipMgr::instance().show(params);
+ }
+ // if there is a mouse captor, nothing else gets a tooltip
+ else if (mouse_captor)
+ {
+ mouse_captor->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = mouse_captor->handleToolTip(local_x, local_y, mask);
+ }
+ else
+ {
+ // next is top_ctrl
+ if (!tool_tip_handled && top_ctrl)
+ {
+ top_ctrl->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = top_ctrl->handleToolTip(local_x, local_y, mask );
+ }
+
+ if (!tool_tip_handled)
+ {
+ local_x = x; local_y = y;
+ tool_tip_handled = mRootView->handleToolTip(local_x, local_y, mask );
+ }
+
+ LLTool* current_tool = LLToolMgr::getInstance()->getCurrentTool();
+ if (!tool_tip_handled && current_tool)
+ {
+ current_tool->screenPointToLocal(x, y, &local_x, &local_y);
+ tool_tip_handled = current_tool->handleToolTip(local_x, local_y, mask );
+ }
+ }
+ }
+ }
+ else
+ { // just have tools handle hover when UI is turned off
+ LLTool *tool = LLToolMgr::getInstance()->getCurrentTool();
+
+ if(mMouseInWindow && tool)
+ {
+ handled = tool->handleHover(x, y, mask);
+ }
+ }
+
+ updateLayout();
+
+ mLastMousePoint = mCurrentMousePoint;
+
+ // cleanup unused selections when no modal dialogs are open
+ if (LLModalDialog::activeCount() == 0)
+ {
+ LLViewerParcelMgr::getInstance()->deselectUnused();
+ }
+
+ if (LLModalDialog::activeCount() == 0)
+ {
+ LLSelectMgr::getInstance()->deselectUnused();
+ }
+}
+
+
+void LLViewerWindow::updateLayout()
+{
+ LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
+ if (gFloaterTools != NULL
+ && tool != NULL
+ && tool != gToolNull
+ && tool != LLToolCompInspect::getInstance()
+ && tool != LLToolDragAndDrop::getInstance()
+ && !gSavedSettings.getBOOL("FreezeTime"))
+ {
+ // Suppress the toolbox view if our source tool was the pie tool,
+ // and we've overridden to something else.
+ bool suppress_toolbox =
+ (LLToolMgr::getInstance()->getBaseTool() == LLToolPie::getInstance()) &&
+ (LLToolMgr::getInstance()->getCurrentTool() != LLToolPie::getInstance());
+
+ LLMouseHandler *captor = gFocusMgr.getMouseCapture();
+ // With the null, inspect, or drag and drop tool, don't muck
+ // with visibility.
+
+ if (gFloaterTools->isMinimized()
+ || (tool != LLToolPie::getInstance() // not default tool
+ && tool != LLToolCompGun::getInstance() // not coming out of mouselook
+ && !suppress_toolbox // not override in third person
+ && LLToolMgr::getInstance()->getCurrentToolset() != gFaceEditToolset // not special mode
+ && LLToolMgr::getInstance()->getCurrentToolset() != gMouselookToolset
+ && (!captor || dynamic_cast<LLView*>(captor) != NULL))) // not dragging
+ {
+ // Force floater tools to be visible (unless minimized)
+ if (!gFloaterTools->getVisible())
+ {
+ gFloaterTools->openFloater();
+ }
+ // Update the location of the blue box tool popup
+ LLCoordGL select_center_screen;
+ gFloaterTools->updatePopup( select_center_screen, gKeyboard->currentMask(TRUE) );
+ }
+ else
+ {
+ gFloaterTools->setVisible(FALSE);
+ }
+ //gMenuBarView->setItemVisible("BuildTools", gFloaterTools->getVisible());
+ }
+
+ // Always update console
+ if(gConsole)
+ {
+ LLRect console_rect = getChatConsoleRect();
+ gConsole->reshape(console_rect.getWidth(), console_rect.getHeight());
+ gConsole->setRect(console_rect);
+ }
+}
+
+void LLViewerWindow::updateMouseDelta()
+{
+ S32 dx = lltrunc((F32) (mCurrentMousePoint.mX - mLastMousePoint.mX) * LLUI::sGLScaleFactor.mV[VX]);
+ S32 dy = lltrunc((F32) (mCurrentMousePoint.mY - mLastMousePoint.mY) * LLUI::sGLScaleFactor.mV[VY]);
+
+ //RN: fix for asynchronous notification of mouse leaving window not working
+ LLCoordWindow mouse_pos;
+ mWindow->getCursorPosition(&mouse_pos);
+ if (mouse_pos.mX < 0 ||
+ mouse_pos.mY < 0 ||
+ mouse_pos.mX > mWindowRectRaw.getWidth() ||
+ mouse_pos.mY > mWindowRectRaw.getHeight())
+ {
+ mMouseInWindow = FALSE;
+ }
+ else
+ {
+ mMouseInWindow = TRUE;
+ }
+
+ LLVector2 mouse_vel;
+
+ if (gSavedSettings.getBOOL("MouseSmooth"))
+ {
+ static F32 fdx = 0.f;
+ static F32 fdy = 0.f;
+
+ F32 amount = 16.f;
+ fdx = fdx + ((F32) dx - fdx) * llmin(gFrameIntervalSeconds*amount,1.f);
+ fdy = fdy + ((F32) dy - fdy) * llmin(gFrameIntervalSeconds*amount,1.f);
+
+ mCurrentMouseDelta.set(llround(fdx), llround(fdy));
+ mouse_vel.setVec(fdx,fdy);
+ }
+ else
+ {
+ mCurrentMouseDelta.set(dx, dy);
+ mouse_vel.setVec((F32) dx, (F32) dy);
+ }
+
+ mMouseVelocityStat.addValue(mouse_vel.magVec());
+}
+
+void LLViewerWindow::updateKeyboardFocus()
+{
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ gFocusMgr.setKeyboardFocus(NULL);
+ }
+
+ // clean up current focus
+ LLUICtrl* cur_focus = dynamic_cast<LLUICtrl*>(gFocusMgr.getKeyboardFocus());
+ if (cur_focus)
+ {
+ if (!cur_focus->isInVisibleChain() || !cur_focus->isInEnabledChain())
+ {
+ // don't release focus, just reassign so that if being given
+ // to a sibling won't call onFocusLost on all the ancestors
+ // gFocusMgr.releaseFocusIfNeeded(cur_focus);
+
+ LLUICtrl* parent = cur_focus->getParentUICtrl();
+ const LLUICtrl* focus_root = cur_focus->findRootMostFocusRoot();
+ bool new_focus_found = false;
+ while(parent)
+ {
+ if (parent->isCtrl()
+ && (parent->hasTabStop() || parent == focus_root)
+ && !parent->getIsChrome()
+ && parent->isInVisibleChain()
+ && parent->isInEnabledChain())
+ {
+ if (!parent->focusFirstItem())
+ {
+ parent->setFocus(TRUE);
+ }
+ new_focus_found = true;
+ break;
+ }
+ parent = parent->getParentUICtrl();
+ }
+
+ // if we didn't find a better place to put focus, just release it
+ // hasFocus() will return true if and only if we didn't touch focus since we
+ // are only moving focus higher in the hierarchy
+ if (!new_focus_found)
+ {
+ cur_focus->setFocus(FALSE);
+ }
+ }
+ else if (cur_focus->isFocusRoot())
+ {
+ // focus roots keep trying to delegate focus to their first valid descendant
+ // this assumes that focus roots are not valid focus holders on their own
+ cur_focus->focusFirstItem();
+ }
+ }
+
+ // last ditch force of edit menu to selection manager
+ if (LLEditMenuHandler::gEditMenuHandler == NULL && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
+ {
+ LLEditMenuHandler::gEditMenuHandler = LLSelectMgr::getInstance();
+ }
+
+ if (gFloaterView->getCycleMode())
+ {
+ // sync all floaters with their focus state
+ gFloaterView->highlightFocusedFloater();
+ gSnapshotFloaterView->highlightFocusedFloater();
+ if ((gKeyboard->currentMask(TRUE) & MASK_CONTROL) == 0)
+ {
+ // control key no longer held down, finish cycle mode
+ gFloaterView->setCycleMode(FALSE);
+
+ gFloaterView->syncFloaterTabOrder();
+ }
+ else
+ {
+ // user holding down CTRL, don't update tab order of floaters
+ }
+ }
+ else
+ {
+ // update focused floater
+ gFloaterView->highlightFocusedFloater();
+ gSnapshotFloaterView->highlightFocusedFloater();
+ // make sure floater visible order is in sync with tab order
+ gFloaterView->syncFloaterTabOrder();
+ }
+
+ if(LLSideTray::instanceCreated())//just getInstance will create sidetray. we don't want this
+ LLSideTray::getInstance()->highlightFocused();
+}
+
+static LLFastTimer::DeclareTimer FTM_UPDATE_WORLD_VIEW("Update World View");
+void LLViewerWindow::updateWorldViewRect(bool use_full_window)
+{
+ LLFastTimer ft(FTM_UPDATE_WORLD_VIEW);
+
+ // start off using whole window to render world
+ LLRect new_world_rect = mWindowRectRaw;
+
+ if (use_full_window == false && mWorldViewPlaceholder.get())
+ {
+ new_world_rect = mWorldViewPlaceholder.get()->calcScreenRect();
+ // clamp to at least a 1x1 rect so we don't try to allocate zero width gl buffers
+ new_world_rect.mTop = llmax(new_world_rect.mTop, new_world_rect.mBottom + 1);
+ new_world_rect.mRight = llmax(new_world_rect.mRight, new_world_rect.mLeft + 1);
+
+ new_world_rect.mLeft = llround((F32)new_world_rect.mLeft * mDisplayScale.mV[VX]);
+ new_world_rect.mRight = llround((F32)new_world_rect.mRight * mDisplayScale.mV[VX]);
+ new_world_rect.mBottom = llround((F32)new_world_rect.mBottom * mDisplayScale.mV[VY]);
+ new_world_rect.mTop = llround((F32)new_world_rect.mTop * mDisplayScale.mV[VY]);
+ }
+
+ if (gSavedSettings.getBOOL("SidebarCameraMovement") == FALSE)
+ {
+ // use right edge of window, ignoring sidebar
+ new_world_rect.mRight = mWindowRectRaw.mRight;
+ }
+
+ if (mWorldViewRectRaw != new_world_rect)
+ {
+ mWorldViewRectRaw = new_world_rect;
+ gResizeScreenTexture = TRUE;
+ LLViewerCamera::getInstance()->setViewHeightInPixels( mWorldViewRectRaw.getHeight() );
+ LLViewerCamera::getInstance()->setAspect( getWorldViewAspectRatio() );
+
+ LLRect old_world_rect_scaled = mWorldViewRectScaled;
+ mWorldViewRectScaled = calcScaledRect(mWorldViewRectRaw, mDisplayScale);
+
+ // sending a signal with a new WorldView rect
+ mOnWorldViewRectUpdated(old_world_rect_scaled, mWorldViewRectScaled);
+ }
+}
+
+void LLViewerWindow::saveLastMouse(const LLCoordGL &point)
+{
+ // Store last mouse location.
+ // If mouse leaves window, pretend last point was on edge of window
+ if (point.mX < 0)
+ {
+ mCurrentMousePoint.mX = 0;
+ }
+ else if (point.mX > getWindowWidthScaled())
+ {
+ mCurrentMousePoint.mX = getWindowWidthScaled();
+ }
+ else
+ {
+ mCurrentMousePoint.mX = point.mX;
+ }
+
+ if (point.mY < 0)
+ {
+ mCurrentMousePoint.mY = 0;
+ }
+ else if (point.mY > getWindowHeightScaled() )
+ {
+ mCurrentMousePoint.mY = getWindowHeightScaled();
+ }
+ else
+ {
+ mCurrentMousePoint.mY = point.mY;
+ }
+}
+
+
+// Draws the selection outlines for the currently selected objects
+// Must be called after displayObjects is called, which sets the mGLName parameter
+// NOTE: This function gets called 3 times:
+// render_ui_3d: FALSE, FALSE, TRUE
+// render_hud_elements: FALSE, FALSE, FALSE
+void LLViewerWindow::renderSelections( BOOL for_gl_pick, BOOL pick_parcel_walls, BOOL for_hud )
+{
+ LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection();
+
+ if (!for_hud && !for_gl_pick)
+ {
+ // Call this once and only once
+ LLSelectMgr::getInstance()->updateSilhouettes();
+ }
+
+ // Draw fence around land selections
+ if (for_gl_pick)
+ {
+ if (pick_parcel_walls)
+ {
+ LLViewerParcelMgr::getInstance()->renderParcelCollision();
+ }
+ }
+ else if (( for_hud && selection->getSelectType() == SELECT_TYPE_HUD) ||
+ (!for_hud && selection->getSelectType() != SELECT_TYPE_HUD))
+ {
+ LLSelectMgr::getInstance()->renderSilhouettes(for_hud);
+
+ stop_glerror();
+
+ // setup HUD render
+ if (selection->getSelectType() == SELECT_TYPE_HUD && LLSelectMgr::getInstance()->getSelection()->getObjectCount())
+ {
+ LLBBox hud_bbox = gAgentAvatarp->getHUDBBox();
+
+ // set up transform to encompass bounding box of HUD
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ F32 depth = llmax(1.f, hud_bbox.getExtentLocal().mV[VX] * 1.1f);
+ glOrtho(-0.5f * LLViewerCamera::getInstance()->getAspect(), 0.5f * LLViewerCamera::getInstance()->getAspect(), -0.5f, 0.5f, 0.f, depth);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+ glLoadMatrixf(OGL_TO_CFR_ROTATION); // Load Cory's favorite reference frame
+ glTranslatef(-hud_bbox.getCenterLocal().mV[VX] + (depth *0.5f), 0.f, 0.f);
+ }
+
+ // Render light for editing
+ if (LLSelectMgr::sRenderLightRadius && LLToolMgr::getInstance()->inEdit())
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLGLEnable gls_blend(GL_BLEND);
+ LLGLEnable gls_cull(GL_CULL_FACE);
+ LLGLDepthTest gls_depth(GL_TRUE, GL_FALSE);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ if (selection->getSelectType() == SELECT_TYPE_HUD)
+ {
+ F32 zoom = gAgentCamera.mHUDCurZoom;
+ glScalef(zoom, zoom, zoom);
+ }
+
+ struct f : public LLSelectedObjectFunctor
+ {
+ virtual bool apply(LLViewerObject* object)
+ {
+ LLDrawable* drawable = object->mDrawable;
+ if (drawable && drawable->isLight())
+ {
+ LLVOVolume* vovolume = drawable->getVOVolume();
+ glPushMatrix();
+
+ LLVector3 center = drawable->getPositionAgent();
+ glTranslatef(center[0], center[1], center[2]);
+ F32 scale = vovolume->getLightRadius();
+ glScalef(scale, scale, scale);
+
+ LLColor4 color(vovolume->getLightColor(), .5f);
+ glColor4fv(color.mV);
+
+ F32 pixel_area = 100000.f;
+ // Render Outside
+ gSphere.render(pixel_area);
+
+ // Render Inside
+ glCullFace(GL_FRONT);
+ gSphere.render(pixel_area);
+ glCullFace(GL_BACK);
+
+ glPopMatrix();
+ }
+ return true;
+ }
+ } func;
+ LLSelectMgr::getInstance()->getSelection()->applyToObjects(&func);
+
+ glPopMatrix();
+ }
+
+ // NOTE: The average position for the axis arrows of the selected objects should
+ // not be recalculated at this time. If they are, then group rotations will break.
+
+ // Draw arrows at average center of all selected objects
+ LLTool* tool = LLToolMgr::getInstance()->getCurrentTool();
+ if (tool)
+ {
+ if(tool->isAlwaysRendered())
+ {
+ tool->render();
+ }
+ else
+ {
+ if( !LLSelectMgr::getInstance()->getSelection()->isEmpty() )
+ {
+ BOOL moveable_object_selected = FALSE;
+ BOOL all_selected_objects_move = TRUE;
+ BOOL all_selected_objects_modify = TRUE;
+ BOOL selecting_linked_set = !gSavedSettings.getBOOL("EditLinkedParts");
+
+ for (LLObjectSelection::iterator iter = LLSelectMgr::getInstance()->getSelection()->begin();
+ iter != LLSelectMgr::getInstance()->getSelection()->end(); iter++)
+ {
+ LLSelectNode* nodep = *iter;
+ LLViewerObject* object = nodep->getObject();
+ BOOL this_object_movable = FALSE;
+ if (object->permMove() && (object->permModify() || selecting_linked_set))
+ {
+ moveable_object_selected = TRUE;
+ this_object_movable = TRUE;
+ }
+ all_selected_objects_move = all_selected_objects_move && this_object_movable;
+ all_selected_objects_modify = all_selected_objects_modify && object->permModify();
+ }
+
+ BOOL draw_handles = TRUE;
+
+ if (tool == LLToolCompTranslate::getInstance() && (!moveable_object_selected || !all_selected_objects_move))
+ {
+ draw_handles = FALSE;
+ }
+
+ if (tool == LLToolCompRotate::getInstance() && (!moveable_object_selected || !all_selected_objects_move))
+ {
+ draw_handles = FALSE;
+ }
+
+ if ( !all_selected_objects_modify && tool == LLToolCompScale::getInstance() )
+ {
+ draw_handles = FALSE;
+ }
+
+ if( draw_handles )
+ {
+ tool->render();
+ }
+ }
+ }
+ if (selection->getSelectType() == SELECT_TYPE_HUD && selection->getObjectCount())
+ {
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ stop_glerror();
+ }
+ }
+ }
+}
+
+// Return a point near the clicked object representative of the place the object was clicked.
+LLVector3d LLViewerWindow::clickPointInWorldGlobal(S32 x, S32 y_from_bot, LLViewerObject* clicked_object) const
+{
+ // create a normalized vector pointing from the camera center into the
+ // world at the location of the mouse click
+ LLVector3 mouse_direction_global = mouseDirectionGlobal( x, y_from_bot );
+
+ LLVector3d relative_object = clicked_object->getPositionGlobal() - gAgentCamera.getCameraPositionGlobal();
+
+ // make mouse vector as long as object vector, so it touchs a point near
+ // where the user clicked on the object
+ mouse_direction_global *= (F32) relative_object.magVec();
+
+ LLVector3d new_pos;
+ new_pos.setVec(mouse_direction_global);
+ // transform mouse vector back to world coords
+ new_pos += gAgentCamera.getCameraPositionGlobal();
+
+ return new_pos;
+}
+
+
+BOOL LLViewerWindow::clickPointOnSurfaceGlobal(const S32 x, const S32 y, LLViewerObject *objectp, LLVector3d &point_global) const
+{
+ BOOL intersect = FALSE;
+
+// U8 shape = objectp->mPrimitiveCode & LL_PCODE_BASE_MASK;
+ if (!intersect)
+ {
+ point_global = clickPointInWorldGlobal(x, y, objectp);
+ llinfos << "approx intersection at " << (objectp->getPositionGlobal() - point_global) << llendl;
+ }
+ else
+ {
+ llinfos << "good intersection at " << (objectp->getPositionGlobal() - point_global) << llendl;
+ }
+
+ return intersect;
+}
+
+void LLViewerWindow::pickAsync(S32 x, S32 y_from_bot, MASK mask, void (*callback)(const LLPickInfo& info), BOOL pick_transparent)
+{
+ if (gNoRender)
+ {
+ return;
+ }
+
+ BOOL in_build_mode = LLFloaterReg::instanceVisible("build");
+ if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
+ {
+ // build mode allows interaction with all transparent objects
+ // "Show Debug Alpha" means no object actually transparent
+ pick_transparent = TRUE;
+ }
+
+ LLPickInfo pick_info(LLCoordGL(x, y_from_bot), mask, pick_transparent, TRUE, callback);
+ schedulePick(pick_info);
+}
+
+void LLViewerWindow::schedulePick(LLPickInfo& pick_info)
+{
+ if (mPicks.size() >= 1024 || mWindow->getMinimized())
+ { //something went wrong, picks are being scheduled but not processed
+
+ if (pick_info.mPickCallback)
+ {
+ pick_info.mPickCallback(pick_info);
+ }
+
+ return;
+ }
+ mPicks.push_back(pick_info);
+
+ // delay further event processing until we receive results of pick
+ // only do this for async picks so that handleMouseUp won't be called
+ // until the pick triggered in handleMouseDown has been processed, for example
+ mWindow->delayInputProcessing();
+}
+
+
+void LLViewerWindow::performPick()
+{
+ if (gNoRender)
+ {
+ return;
+ }
+
+ if (!mPicks.empty())
+ {
+ std::vector<LLPickInfo>::iterator pick_it;
+ for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
+ {
+ pick_it->fetchResults();
+ }
+
+ mLastPick = mPicks.back();
+ mPicks.clear();
+ }
+}
+
+void LLViewerWindow::returnEmptyPicks()
+{
+ std::vector<LLPickInfo>::iterator pick_it;
+ for (pick_it = mPicks.begin(); pick_it != mPicks.end(); ++pick_it)
+ {
+ mLastPick = *pick_it;
+ // just trigger callback with empty results
+ if (pick_it->mPickCallback)
+ {
+ pick_it->mPickCallback(*pick_it);
+ }
+ }
+ mPicks.clear();
+}
+
+// Performs the GL object/land pick.
+LLPickInfo LLViewerWindow::pickImmediate(S32 x, S32 y_from_bot, BOOL pick_transparent)
+{
+ if (gNoRender)
+ {
+ return LLPickInfo();
+ }
+
+ BOOL in_build_mode = LLFloaterReg::instanceVisible("build");
+ if (in_build_mode || LLDrawPoolAlpha::sShowDebugAlpha)
+ {
+ // build mode allows interaction with all transparent objects
+ // "Show Debug Alpha" means no object actually transparent
+ pick_transparent = TRUE;
+ }
+
+ // shortcut queueing in mPicks and just update mLastPick in place
+ mLastPick = LLPickInfo(LLCoordGL(x, y_from_bot), gKeyboard->currentMask(TRUE), pick_transparent, TRUE, NULL);
+ mLastPick.fetchResults();
+
+ return mLastPick;
+}
+
+LLHUDIcon* LLViewerWindow::cursorIntersectIcon(S32 mouse_x, S32 mouse_y, F32 depth,
+ LLVector3* intersection)
+{
+ S32 x = mouse_x;
+ S32 y = mouse_y;
+
+ if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
+ {
+ x = getCurrentMouseX();
+ y = getCurrentMouseY();
+ }
+
+ // world coordinates of mouse
+ LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
+ LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
+ LLVector3 mouse_world_start = mouse_point_global;
+ LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
+
+ return LLHUDIcon::lineSegmentIntersectAll(mouse_world_start, mouse_world_end, intersection);
+
+
+}
+
+LLViewerObject* LLViewerWindow::cursorIntersect(S32 mouse_x, S32 mouse_y, F32 depth,
+ LLViewerObject *this_object,
+ S32 this_face,
+ BOOL pick_transparent,
+ S32* face_hit,
+ LLVector3 *intersection,
+ LLVector2 *uv,
+ LLVector3 *normal,
+ LLVector3 *binormal)
+{
+ S32 x = mouse_x;
+ S32 y = mouse_y;
+
+ if ((mouse_x == -1) && (mouse_y == -1)) // use current mouse position
+ {
+ x = getCurrentMouseX();
+ y = getCurrentMouseY();
+ }
+
+ // HUD coordinates of mouse
+ LLVector3 mouse_point_hud = mousePointHUD(x, y);
+ LLVector3 mouse_hud_start = mouse_point_hud - LLVector3(depth, 0, 0);
+ LLVector3 mouse_hud_end = mouse_point_hud + LLVector3(depth, 0, 0);
+
+ // world coordinates of mouse
+ LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
+ LLVector3 mouse_point_global = LLViewerCamera::getInstance()->getOrigin();
+
+ //get near clip plane
+ LLVector3 n = LLViewerCamera::getInstance()->getAtAxis();
+ LLVector3 p = mouse_point_global + n * LLViewerCamera::getInstance()->getNear();
+
+ //project mouse point onto plane
+ LLVector3 pos;
+ line_plane(mouse_point_global, mouse_direction_global, p, n, pos);
+ mouse_point_global = pos;
+
+ LLVector3 mouse_world_start = mouse_point_global;
+ LLVector3 mouse_world_end = mouse_point_global + mouse_direction_global * depth;
+
+
+ LLViewerObject* found = NULL;
+
+ if (this_object) // check only this object
+ {
+ if (this_object->isHUDAttachment()) // is a HUD object?
+ {
+ if (this_object->lineSegmentIntersect(mouse_hud_start, mouse_hud_end, this_face, pick_transparent,
+ face_hit, intersection, uv, normal, binormal))
+ {
+ found = this_object;
+ }
+ }
+
+ else // is a world object
+ {
+ if (this_object->lineSegmentIntersect(mouse_world_start, mouse_world_end, this_face, pick_transparent,
+ face_hit, intersection, uv, normal, binormal))
+ {
+ found = this_object;
+ }
+ }
+ }
+
+ else // check ALL objects
+ {
+ found = gPipeline.lineSegmentIntersectInHUD(mouse_hud_start, mouse_hud_end, pick_transparent,
+ face_hit, intersection, uv, normal, binormal);
+
+ if (!found) // if not found in HUD, look in world:
+
+ {
+ found = gPipeline.lineSegmentIntersectInWorld(mouse_world_start, mouse_world_end, pick_transparent,
+ face_hit, intersection, uv, normal, binormal);
+ }
+
+ }
+
+ return found;
+}
+
+// Returns unit vector relative to camera
+// indicating direction of point on screen x,y
+LLVector3 LLViewerWindow::mouseDirectionGlobal(const S32 x, const S32 y) const
+{
+ // find vertical field of view
+ F32 fov = LLViewerCamera::getInstance()->getView();
+
+ // find world view center in scaled ui coordinates
+ F32 center_x = getWorldViewRectScaled().getCenterX();
+ F32 center_y = getWorldViewRectScaled().getCenterY();
+
+ // calculate pixel distance to screen
+ F32 distance = ((F32)getWorldViewHeightScaled() * 0.5f) / (tan(fov / 2.f));
+
+ // calculate click point relative to middle of screen
+ F32 click_x = x - center_x;
+ F32 click_y = y - center_y;
+
+ // compute mouse vector
+ LLVector3 mouse_vector = distance * LLViewerCamera::getInstance()->getAtAxis()
+ - click_x * LLViewerCamera::getInstance()->getLeftAxis()
+ + click_y * LLViewerCamera::getInstance()->getUpAxis();
+
+ mouse_vector.normVec();
+
+ return mouse_vector;
+}
+
+LLVector3 LLViewerWindow::mousePointHUD(const S32 x, const S32 y) const
+{
+ // find screen resolution
+ S32 height = getWorldViewHeightScaled();
+
+ // find world view center
+ F32 center_x = getWorldViewRectScaled().getCenterX();
+ F32 center_y = getWorldViewRectScaled().getCenterY();
+
+ // remap with uniform scale (1/height) so that top is -0.5, bottom is +0.5
+ F32 hud_x = -((F32)x - center_x) / height;
+ F32 hud_y = ((F32)y - center_y) / height;
+
+ return LLVector3(0.f, hud_x/gAgentCamera.mHUDCurZoom, hud_y/gAgentCamera.mHUDCurZoom);
+}
+
+// Returns unit vector relative to camera in camera space
+// indicating direction of point on screen x,y
+LLVector3 LLViewerWindow::mouseDirectionCamera(const S32 x, const S32 y) const
+{
+ // find vertical field of view
+ F32 fov_height = LLViewerCamera::getInstance()->getView();
+ F32 fov_width = fov_height * LLViewerCamera::getInstance()->getAspect();
+
+ // find screen resolution
+ S32 height = getWorldViewHeightScaled();
+ S32 width = getWorldViewWidthScaled();
+
+ // find world view center
+ F32 center_x = getWorldViewRectScaled().getCenterX();
+ F32 center_y = getWorldViewRectScaled().getCenterY();
+
+ // calculate click point relative to middle of screen
+ F32 click_x = (((F32)x - center_x) / (F32)width) * fov_width * -1.f;
+ F32 click_y = (((F32)y - center_y) / (F32)height) * fov_height;
+
+ // compute mouse vector
+ LLVector3 mouse_vector = LLVector3(0.f, 0.f, -1.f);
+ LLQuaternion mouse_rotate;
+ mouse_rotate.setQuat(click_y, click_x, 0.f);
+
+ mouse_vector = mouse_vector * mouse_rotate;
+ // project to z = -1 plane;
+ mouse_vector = mouse_vector * (-1.f / mouse_vector.mV[VZ]);
+
+ return mouse_vector;
+}
+
+
+
+BOOL LLViewerWindow::mousePointOnPlaneGlobal(LLVector3d& point, const S32 x, const S32 y,
+ const LLVector3d &plane_point_global,
+ const LLVector3 &plane_normal_global)
+{
+ LLVector3d mouse_direction_global_d;
+
+ mouse_direction_global_d.setVec(mouseDirectionGlobal(x,y));
+ LLVector3d plane_normal_global_d;
+ plane_normal_global_d.setVec(plane_normal_global);
+ F64 plane_mouse_dot = (plane_normal_global_d * mouse_direction_global_d);
+ LLVector3d plane_origin_camera_rel = plane_point_global - gAgentCamera.getCameraPositionGlobal();
+ F64 mouse_look_at_scale = (plane_normal_global_d * plane_origin_camera_rel)
+ / plane_mouse_dot;
+ if (llabs(plane_mouse_dot) < 0.00001)
+ {
+ // if mouse is parallel to plane, return closest point on line through plane origin
+ // that is parallel to camera plane by scaling mouse direction vector
+ // by distance to plane origin, modulated by deviation of mouse direction from plane origin
+ LLVector3d plane_origin_dir = plane_origin_camera_rel;
+ plane_origin_dir.normVec();
+
+ mouse_look_at_scale = plane_origin_camera_rel.magVec() / (plane_origin_dir * mouse_direction_global_d);
+ }
+
+ point = gAgentCamera.getCameraPositionGlobal() + mouse_look_at_scale * mouse_direction_global_d;
+
+ return mouse_look_at_scale > 0.0;
+}
+
+
+// Returns global position
+BOOL LLViewerWindow::mousePointOnLandGlobal(const S32 x, const S32 y, LLVector3d *land_position_global)
+{
+ LLVector3 mouse_direction_global = mouseDirectionGlobal(x,y);
+ F32 mouse_dir_scale;
+ BOOL hit_land = FALSE;
+ LLViewerRegion *regionp;
+ F32 land_z;
+ const F32 FIRST_PASS_STEP = 1.0f; // meters
+ const F32 SECOND_PASS_STEP = 0.1f; // meters
+ LLVector3d camera_pos_global;
+
+ camera_pos_global = gAgentCamera.getCameraPositionGlobal();
+ LLVector3d probe_point_global;
+ LLVector3 probe_point_region;
+
+ // walk forwards to find the point
+ for (mouse_dir_scale = FIRST_PASS_STEP; mouse_dir_scale < gAgentCamera.mDrawDistance; mouse_dir_scale += FIRST_PASS_STEP)
+ {
+ LLVector3d mouse_direction_global_d;
+ mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
+ probe_point_global = camera_pos_global + mouse_direction_global_d;
+
+ regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
+
+ if (!regionp)
+ {
+ // ...we're outside the world somehow
+ continue;
+ }
+
+ S32 i = (S32) (probe_point_region.mV[VX]/regionp->getLand().getMetersPerGrid());
+ S32 j = (S32) (probe_point_region.mV[VY]/regionp->getLand().getMetersPerGrid());
+ S32 grids_per_edge = (S32) regionp->getLand().mGridsPerEdge;
+ if ((i >= grids_per_edge) || (j >= grids_per_edge))
+ {
+ //llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
+ continue;
+ }
+
+ land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
+
+ //llinfos << "mousePointOnLand initial z " << land_z << llendl;
+
+ if (probe_point_region.mV[VZ] < land_z)
+ {
+ // ...just went under land
+
+ // cout << "under land at " << probe_point << " scale " << mouse_vec_scale << endl;
+
+ hit_land = TRUE;
+ break;
+ }
+ }
+
+
+ if (hit_land)
+ {
+ // Don't go more than one step beyond where we stopped above.
+ // This can't just be "mouse_vec_scale" because floating point error
+ // will stop the loop before the last increment.... X - 1.0 + 0.1 + 0.1 + ... + 0.1 != X
+ F32 stop_mouse_dir_scale = mouse_dir_scale + FIRST_PASS_STEP;
+
+ // take a step backwards, then walk forwards again to refine position
+ for ( mouse_dir_scale -= FIRST_PASS_STEP; mouse_dir_scale <= stop_mouse_dir_scale; mouse_dir_scale += SECOND_PASS_STEP)
+ {
+ LLVector3d mouse_direction_global_d;
+ mouse_direction_global_d.setVec(mouse_direction_global * mouse_dir_scale);
+ probe_point_global = camera_pos_global + mouse_direction_global_d;
+
+ regionp = LLWorld::getInstance()->resolveRegionGlobal(probe_point_region, probe_point_global);
+
+ if (!regionp)
+ {
+ // ...we're outside the world somehow
+ continue;
+ }
+
+ /*
+ i = (S32) (local_probe_point.mV[VX]/regionp->getLand().getMetersPerGrid());
+ j = (S32) (local_probe_point.mV[VY]/regionp->getLand().getMetersPerGrid());
+ if ((i >= regionp->getLand().mGridsPerEdge) || (j >= regionp->getLand().mGridsPerEdge))
+ {
+ // llinfos << "LLViewerWindow::mousePointOnLand probe_point is out of region" << llendl;
+ continue;
+ }
+ land_z = regionp->getLand().mSurfaceZ[ i + j * (regionp->getLand().mGridsPerEdge) ];
+ */
+
+ land_z = regionp->getLand().resolveHeightRegion(probe_point_region);
+
+ //llinfos << "mousePointOnLand refine z " << land_z << llendl;
+
+ if (probe_point_region.mV[VZ] < land_z)
+ {
+ // ...just went under land again
+
+ *land_position_global = probe_point_global;
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+// Saves an image to the harddrive as "SnapshotX" where X >= 1.
+BOOL LLViewerWindow::saveImageNumbered(LLImageFormatted *image)
+{
+ if (!image)
+ {
+ return FALSE;
+ }
+
+ LLFilePicker::ESaveFilter pick_type;
+ std::string extension("." + image->getExtension());
+ if (extension == ".j2c")
+ pick_type = LLFilePicker::FFSAVE_J2C;
+ else if (extension == ".bmp")
+ pick_type = LLFilePicker::FFSAVE_BMP;
+ else if (extension == ".jpg")
+ pick_type = LLFilePicker::FFSAVE_JPEG;
+ else if (extension == ".png")
+ pick_type = LLFilePicker::FFSAVE_PNG;
+ else if (extension == ".tga")
+ pick_type = LLFilePicker::FFSAVE_TGA;
+ else
+ pick_type = LLFilePicker::FFSAVE_ALL; // ???
+
+ // Get a base file location if needed.
+ if ( ! isSnapshotLocSet())
+ {
+ std::string proposed_name( sSnapshotBaseName );
+
+ // getSaveFile will append an appropriate extension to the proposed name, based on the ESaveFilter constant passed in.
+
+ // pick a directory in which to save
+ LLFilePicker& picker = LLFilePicker::instance();
+ if (!picker.getSaveFile(pick_type, proposed_name))
+ {
+ // Clicked cancel
+ return FALSE;
+ }
+
+ // Copy the directory + file name
+ std::string filepath = picker.getFirstFile();
+
+ LLViewerWindow::sSnapshotBaseName = gDirUtilp->getBaseFileName(filepath, true);
+ LLViewerWindow::sSnapshotDir = gDirUtilp->getDirName(filepath);
+ }
+
+ // Look for an unused file name
+ std::string filepath;
+ S32 i = 1;
+ S32 err = 0;
+
+ do
+ {
+ filepath = sSnapshotDir;
+ filepath += gDirUtilp->getDirDelimiter();
+ filepath += sSnapshotBaseName;
+ filepath += llformat("_%.3d",i);
+ filepath += extension;
+
+ llstat stat_info;
+ err = LLFile::stat( filepath, &stat_info );
+ i++;
+ }
+ while( -1 != err ); // search until the file is not found (i.e., stat() gives an error).
+
+ return image->save(filepath);
+}
+
+void LLViewerWindow::resetSnapshotLoc()
+{
+ sSnapshotDir.clear();
+}
+
+static S32 BORDERHEIGHT = 0;
+static S32 BORDERWIDTH = 0;
+
+// static
+void LLViewerWindow::movieSize(S32 new_width, S32 new_height)
+{
+ LLCoordScreen size;
+ gViewerWindow->mWindow->getSize(&size);
+ if ( (size.mX != new_width + BORDERWIDTH)
+ ||(size.mY != new_height + BORDERHEIGHT))
+ {
+ // use actual display dimensions, not virtual UI dimensions
+ S32 x = gViewerWindow->getWindowWidthRaw();
+ S32 y = gViewerWindow->getWindowHeightRaw();
+ BORDERWIDTH = size.mX - x;
+ BORDERHEIGHT = size.mY- y;
+ LLCoordScreen new_size(new_width + BORDERWIDTH,
+ new_height + BORDERHEIGHT);
+ gViewerWindow->mWindow->setSize(new_size);
+ }
+}
+
+BOOL LLViewerWindow::saveSnapshot( const std::string& filepath, S32 image_width, S32 image_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
+{
+ llinfos << "Saving snapshot to: " << filepath << llendl;
+
+ LLPointer<LLImageRaw> raw = new LLImageRaw;
+ BOOL success = rawSnapshot(raw, image_width, image_height, TRUE, FALSE, show_ui, do_rebuild);
+
+ if (success)
+ {
+ LLPointer<LLImageBMP> bmp_image = new LLImageBMP;
+ success = bmp_image->encode(raw, 0.0f);
+ if( success )
+ {
+ success = bmp_image->save(filepath);
+ }
+ else
+ {
+ llwarns << "Unable to encode bmp snapshot" << llendl;
+ }
+ }
+ else
+ {
+ llwarns << "Unable to capture raw snapshot" << llendl;
+ }
+
+ return success;
+}
+
+
+void LLViewerWindow::playSnapshotAnimAndSound()
+{
+ if (gSavedSettings.getBOOL("QuietSnapshotsToDisk"))
+ {
+ return;
+ }
+ gAgent.sendAnimationRequest(ANIM_AGENT_SNAPSHOT, ANIM_REQUEST_START);
+ send_sound_trigger(LLUUID(gSavedSettings.getString("UISndSnapshot")), 1.0f);
+}
+
+BOOL LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, BOOL show_ui, BOOL do_rebuild, ESnapshotType type)
+{
+ return rawSnapshot(raw, preview_width, preview_height, FALSE, FALSE, show_ui, do_rebuild, type);
+}
+
+// Saves the image from the screen to the specified filename and path.
+BOOL LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height,
+ BOOL keep_window_aspect, BOOL is_texture, BOOL show_ui, BOOL do_rebuild, ESnapshotType type, S32 max_size)
+{
+ if (!raw)
+ {
+ return FALSE;
+ }
+
+ // PRE SNAPSHOT
+ gDisplaySwapBuffers = FALSE;
+
+ glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
+ setCursor(UI_CURSOR_WAIT);
+
+ // Hide all the UI widgets first and draw a frame
+ BOOL prev_draw_ui = gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI) ? TRUE : FALSE;
+
+ show_ui = show_ui ? TRUE : FALSE;
+
+ if ( prev_draw_ui != show_ui)
+ {
+ LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+
+ BOOL hide_hud = !gSavedSettings.getBOOL("RenderHUDInSnapshot") && LLPipeline::sShowHUDAttachments;
+ if (hide_hud)
+ {
+ LLPipeline::sShowHUDAttachments = FALSE;
+ }
+
+ // if not showing ui, use full window to render world view
+ updateWorldViewRect(!show_ui);
+
+ // Copy screen to a buffer
+ // crop sides or top and bottom, if taking a snapshot of different aspect ratio
+ // from window
+ LLRect window_rect = show_ui ? getWindowRectRaw() : getWorldViewRectRaw();
+
+ S32 snapshot_width = window_rect.getWidth();
+ S32 snapshot_height = window_rect.getHeight();
+ // SNAPSHOT
+ S32 window_width = snapshot_width;
+ S32 window_height = snapshot_height;
+
+ if (show_ui)
+ {
+ image_width = llmin(image_width, window_width);
+ image_height = llmin(image_height, window_height);
+ }
+
+ F32 scale_factor = 1.0f ;
+ if(!keep_window_aspect) //image cropping
+ {
+ F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
+ snapshot_width = (S32)(ratio * image_width) ;
+ snapshot_height = (S32)(ratio * image_height) ;
+ scale_factor = llmax(1.0f, 1.0f / ratio) ;
+ }
+ else //the scene(window) proportion needs to be maintained.
+ {
+ if(image_width > window_width || image_height > window_height) //need to enlarge the scene
+ {
+ F32 ratio = llmin( (F32)window_width / image_width , (F32)window_height / image_height) ;
+ snapshot_width = (S32)(ratio * image_width) ;
+ snapshot_height = (S32)(ratio * image_height) ;
+ scale_factor = llmax(1.0f, 1.0f / ratio) ;
+ }
+ }
+
+ if (show_ui && scale_factor > 1.f)
+ {
+ llwarns << "over scaling UI not supported." << llendl;
+ }
+
+ S32 buffer_x_offset = llfloor(((window_width - snapshot_width) * scale_factor) / 2.f);
+ S32 buffer_y_offset = llfloor(((window_height - snapshot_height) * scale_factor) / 2.f);
+
+ S32 image_buffer_x = llfloor(snapshot_width*scale_factor) ;
+ S32 image_buffer_y = llfloor(snapshot_height *scale_factor) ;
+
+ if(image_buffer_x > max_size || image_buffer_y > max_size) //boundary check to avoid memory overflow
+ {
+ scale_factor *= llmin((F32)max_size / image_buffer_x, (F32)max_size / image_buffer_y) ;
+ image_buffer_x = llfloor(snapshot_width*scale_factor) ;
+ image_buffer_y = llfloor(snapshot_height *scale_factor) ;
+ }
+ if(image_buffer_x > 0 && image_buffer_y > 0)
+ {
+ raw->resize(image_buffer_x, image_buffer_y, 3);
+ }
+ else
+ {
+ return FALSE ;
+ }
+ if(raw->isBufferInvalid())
+ {
+ return FALSE ;
+ }
+
+ BOOL high_res = scale_factor >= 2.f; // Font scaling is slow, only do so if rez is much higher
+ if (high_res && show_ui)
+ {
+ llwarns << "High res UI snapshot not supported. " << llendl;
+ /*send_agent_pause();
+ //rescale fonts
+ initFonts(scale_factor);
+ LLHUDObject::reshapeAll();*/
+ }
+
+ S32 output_buffer_offset_y = 0;
+
+ F32 depth_conversion_factor_1 = (LLViewerCamera::getInstance()->getFar() + LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
+ F32 depth_conversion_factor_2 = (LLViewerCamera::getInstance()->getFar() - LLViewerCamera::getInstance()->getNear()) / (2.f * LLViewerCamera::getInstance()->getFar() * LLViewerCamera::getInstance()->getNear());
+
+ gObjectList.generatePickList(*LLViewerCamera::getInstance());
+
+ for (int subimage_y = 0; subimage_y < scale_factor; ++subimage_y)
+ {
+ S32 subimage_y_offset = llclamp(buffer_y_offset - (subimage_y * window_height), 0, window_height);;
+ // handle fractional columns
+ U32 read_height = llmax(0, (window_height - subimage_y_offset) -
+ llmax(0, (window_height * (subimage_y + 1)) - (buffer_y_offset + raw->getHeight())));
+
+ S32 output_buffer_offset_x = 0;
+ for (int subimage_x = 0; subimage_x < scale_factor; ++subimage_x)
+ {
+ gDisplaySwapBuffers = FALSE;
+ gDepthDirty = TRUE;
+
+ const U32 subfield = subimage_x+(subimage_y*llceil(scale_factor));
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ display(do_rebuild, scale_factor, subfield, TRUE);
+ }
+ else
+ {
+ display(do_rebuild, scale_factor, subfield, TRUE);
+ // Required for showing the GUI in snapshots and performing bloom composite overlay
+ // Call even if show_ui is FALSE
+ render_ui(scale_factor, subfield);
+ }
+
+ S32 subimage_x_offset = llclamp(buffer_x_offset - (subimage_x * window_width), 0, window_width);
+ // handle fractional rows
+ U32 read_width = llmax(0, (window_width - subimage_x_offset) -
+ llmax(0, (window_width * (subimage_x + 1)) - (buffer_x_offset + raw->getWidth())));
+ for(U32 out_y = 0; out_y < read_height ; out_y++)
+ {
+ S32 output_buffer_offset = (
+ (out_y * (raw->getWidth())) // ...plus iterated y...
+ + (window_width * subimage_x) // ...plus subimage start in x...
+ + (raw->getWidth() * window_height * subimage_y) // ...plus subimage start in y...
+ - output_buffer_offset_x // ...minus buffer padding x...
+ - (output_buffer_offset_y * (raw->getWidth())) // ...minus buffer padding y...
+ ) * raw->getComponents();
+
+ // Ping the wathdog thread every 100 lines to keep us alive (arbitrary number, feel free to change)
+ if (out_y % 100 == 0)
+ {
+ LLAppViewer::instance()->pingMainloopTimeout("LLViewerWindow::rawSnapshot");
+ }
+
+ if (type == SNAPSHOT_TYPE_COLOR)
+ {
+ glReadPixels(
+ subimage_x_offset, out_y + subimage_y_offset,
+ read_width, 1,
+ GL_RGB, GL_UNSIGNED_BYTE,
+ raw->getData() + output_buffer_offset
+ );
+ }
+ else // SNAPSHOT_TYPE_DEPTH
+ {
+ LLPointer<LLImageRaw> depth_line_buffer = new LLImageRaw(read_width, 1, sizeof(GL_FLOAT)); // need to store floating point values
+ glReadPixels(
+ subimage_x_offset, out_y + subimage_y_offset,
+ read_width, 1,
+ GL_DEPTH_COMPONENT, GL_FLOAT,
+ depth_line_buffer->getData()// current output pixel is beginning of buffer...
+ );
+
+ for (S32 i = 0; i < (S32)read_width; i++)
+ {
+ F32 depth_float = *(F32*)(depth_line_buffer->getData() + (i * sizeof(F32)));
+
+ F32 linear_depth_float = 1.f / (depth_conversion_factor_1 - (depth_float * depth_conversion_factor_2));
+ U8 depth_byte = F32_to_U8(linear_depth_float, LLViewerCamera::getInstance()->getNear(), LLViewerCamera::getInstance()->getFar());
+ //write converted scanline out to result image
+ for(S32 j = 0; j < raw->getComponents(); j++)
+ {
+ *(raw->getData() + output_buffer_offset + (i * raw->getComponents()) + j) = depth_byte;
+ }
+ }
+ }
+ }
+ output_buffer_offset_x += subimage_x_offset;
+ stop_glerror();
+ }
+ output_buffer_offset_y += subimage_y_offset;
+ }
+
+ gDisplaySwapBuffers = FALSE;
+ gDepthDirty = TRUE;
+
+ // POST SNAPSHOT
+ if (!gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ LLPipeline::toggleRenderDebugFeature((void*)LLPipeline::RENDER_DEBUG_FEATURE_UI);
+ }
+
+ if (hide_hud)
+ {
+ LLPipeline::sShowHUDAttachments = TRUE;
+ }
+
+ /*if (high_res)
+ {
+ initFonts(1.f);
+ LLHUDObject::reshapeAll();
+ }*/
+
+ // Pre-pad image to number of pixels such that the line length is a multiple of 4 bytes (for BMP encoding)
+ // Note: this formula depends on the number of components being 3. Not obvious, but it's correct.
+ image_width += (image_width * 3) % 4;
+
+ BOOL ret = TRUE ;
+ // Resize image
+ if(llabs(image_width - image_buffer_x) > 4 || llabs(image_height - image_buffer_y) > 4)
+ {
+ ret = raw->scale( image_width, image_height );
+ }
+ else if(image_width != image_buffer_x || image_height != image_buffer_y)
+ {
+ ret = raw->scale( image_width, image_height, FALSE );
+ }
+
+
+ setCursor(UI_CURSOR_ARROW);
+
+ if (do_rebuild)
+ {
+ // If we had to do a rebuild, that means that the lists of drawables to be rendered
+ // was empty before we started.
+ // Need to reset these, otherwise we call state sort on it again when render gets called the next time
+ // and we stand a good chance of crashing on rebuild because the render drawable arrays have multiple copies of
+ // objects on them.
+ gPipeline.resetDrawOrders();
+ }
+
+ if (high_res)
+ {
+ send_agent_resume();
+ }
+
+ return ret;
+}
+
+void LLViewerWindow::destroyWindow()
+{
+ if (mWindow)
+ {
+ LLWindowManager::destroyWindow(mWindow);
+ }
+ mWindow = NULL;
+}
+
+
+void LLViewerWindow::drawMouselookInstructions()
+{
+ // Draw instructions for mouselook ("Press ESC to return to World View" partially transparent at the bottom of the screen.)
+ const std::string instructions = LLTrans::getString("LeaveMouselook");
+ const LLFontGL* font = LLFontGL::getFont(LLFontDescriptor("SansSerif", "Large", LLFontGL::BOLD));
+
+ //to be on top of Bottom bar when it is opened
+ const S32 INSTRUCTIONS_PAD = 50;
+
+ font->renderUTF8(
+ instructions, 0,
+ getWorldViewRectScaled().getCenterX(),
+ getWorldViewRectScaled().mBottom + INSTRUCTIONS_PAD,
+ LLColor4( 1.0f, 1.0f, 1.0f, 0.5f ),
+ LLFontGL::HCENTER, LLFontGL::TOP,
+ LLFontGL::NORMAL,LLFontGL::DROP_SHADOW);
+}
+
+void* LLViewerWindow::getPlatformWindow() const
+{
+ return mWindow->getPlatformWindow();
+}
+
+void* LLViewerWindow::getMediaWindow() const
+{
+ return mWindow->getMediaWindow();
+}
+
+void LLViewerWindow::focusClient() const
+{
+ return mWindow->focusClient();
+}
+
+LLRootView* LLViewerWindow::getRootView() const
+{
+ return mRootView;
+}
+
+LLRect LLViewerWindow::getWorldViewRectScaled() const
+{
+ return mWorldViewRectScaled;
+}
+
+S32 LLViewerWindow::getWorldViewHeightScaled() const
+{
+ return mWorldViewRectScaled.getHeight();
+}
+
+S32 LLViewerWindow::getWorldViewWidthScaled() const
+{
+ return mWorldViewRectScaled.getWidth();
+}
+
+
+S32 LLViewerWindow::getWorldViewHeightRaw() const
+{
+ return mWorldViewRectRaw.getHeight();
+}
+
+S32 LLViewerWindow::getWorldViewWidthRaw() const
+{
+ return mWorldViewRectRaw.getWidth();
+}
+
+S32 LLViewerWindow::getWindowHeightScaled() const
+{
+ return mWindowRectScaled.getHeight();
+}
+
+S32 LLViewerWindow::getWindowWidthScaled() const
+{
+ return mWindowRectScaled.getWidth();
+}
+
+S32 LLViewerWindow::getWindowHeightRaw() const
+{
+ return mWindowRectRaw.getHeight();
+}
+
+S32 LLViewerWindow::getWindowWidthRaw() const
+{
+ return mWindowRectRaw.getWidth();
+}
+
+void LLViewerWindow::setup2DRender()
+{
+ // setup ortho camera
+ gl_state_for_2d(mWindowRectRaw.getWidth(), mWindowRectRaw.getHeight());
+ setup2DViewport();
+}
+
+void LLViewerWindow::setup2DViewport(S32 x_offset, S32 y_offset)
+{
+ gGLViewport[0] = mWindowRectRaw.mLeft + x_offset;
+ gGLViewport[1] = mWindowRectRaw.mBottom + y_offset;
+ gGLViewport[2] = mWindowRectRaw.getWidth();
+ gGLViewport[3] = mWindowRectRaw.getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+}
+
+
+void LLViewerWindow::setup3DRender()
+{
+ // setup perspective camera
+ LLViewerCamera::getInstance()->setPerspective(NOT_FOR_SELECTION, mWorldViewRectRaw.mLeft, mWorldViewRectRaw.mBottom, mWorldViewRectRaw.getWidth(), mWorldViewRectRaw.getHeight(), FALSE, LLViewerCamera::getInstance()->getNear(), MAX_FAR_CLIP*2.f);
+ setup3DViewport();
+}
+
+void LLViewerWindow::setup3DViewport(S32 x_offset, S32 y_offset)
+{
+ gGLViewport[0] = mWorldViewRectRaw.mLeft + x_offset;
+ gGLViewport[1] = mWorldViewRectRaw.mBottom + y_offset;
+ gGLViewport[2] = mWorldViewRectRaw.getWidth();
+ gGLViewport[3] = mWorldViewRectRaw.getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+}
+
+void LLViewerWindow::setShowProgress(const BOOL show)
+{
+ if (mProgressView)
+ {
+ mProgressView->setVisible(show);
+ }
+}
+
+BOOL LLViewerWindow::getShowProgress() const
+{
+ return (mProgressView && mProgressView->getVisible());
+}
+
+void LLViewerWindow::setProgressString(const std::string& string)
+{
+ if (mProgressView)
+ {
+ mProgressView->setText(string);
+ }
+}
+
+void LLViewerWindow::setProgressMessage(const std::string& msg)
+{
+ if(mProgressView)
+ {
+ mProgressView->setMessage(msg);
+ }
+}
+
+void LLViewerWindow::setProgressPercent(const F32 percent)
+{
+ if (mProgressView)
+ {
+ mProgressView->setPercent(percent);
+ }
+}
+
+void LLViewerWindow::setProgressCancelButtonVisible( BOOL b, const std::string& label )
+{
+ if (mProgressView)
+ {
+ mProgressView->setCancelButtonVisible( b, label );
+ }
+}
+
+
+LLProgressView *LLViewerWindow::getProgressView() const
+{
+ return mProgressView;
+}
+
+void LLViewerWindow::dumpState()
+{
+ llinfos << "LLViewerWindow Active " << S32(mActive) << llendl;
+ llinfos << "mWindow visible " << S32(mWindow->getVisible())
+ << " minimized " << S32(mWindow->getMinimized())
+ << llendl;
+}
+
+void LLViewerWindow::stopGL(BOOL save_state)
+{
+ //Note: --bao
+ //if not necessary, do not change the order of the function calls in this function.
+ //if change something, make sure it will not break anything.
+ //especially be careful to put anything behind gTextureList.destroyGL(save_state);
+ if (!gGLManager.mIsDisabled)
+ {
+ llinfos << "Shutting down GL..." << llendl;
+
+ // Pause texture decode threads (will get unpaused during main loop)
+ LLAppViewer::getTextureCache()->pause();
+ LLAppViewer::getImageDecodeThread()->pause();
+ LLAppViewer::getTextureFetch()->pause();
+
+ gSky.destroyGL();
+ stop_glerror();
+
+ LLManipTranslate::destroyGL() ;
+ stop_glerror();
+
+ gBumpImageList.destroyGL();
+ stop_glerror();
+
+ LLFontGL::destroyAllGL();
+ stop_glerror();
+
+ LLVOAvatar::destroyGL();
+ stop_glerror();
+
+ LLViewerDynamicTexture::destroyGL();
+ stop_glerror();
+
+ if (gPipeline.isInit())
+ {
+ gPipeline.destroyGL();
+ }
+
+ gCone.cleanupGL();
+ gBox.cleanupGL();
+ gSphere.cleanupGL();
+ gCylinder.cleanupGL();
+
+ if(gPostProcess)
+ {
+ gPostProcess->invalidate();
+ }
+
+ gTextureList.destroyGL(save_state);
+ stop_glerror();
+
+ gGLManager.mIsDisabled = TRUE;
+ stop_glerror();
+
+ llinfos << "Remaining allocated texture memory: " << LLImageGL::sGlobalTextureMemoryInBytes << " bytes" << llendl;
+ }
+}
+
+void LLViewerWindow::restoreGL(const std::string& progress_message)
+{
+ //Note: --bao
+ //if not necessary, do not change the order of the function calls in this function.
+ //if change something, make sure it will not break anything.
+ //especially, be careful to put something before gTextureList.restoreGL();
+ if (gGLManager.mIsDisabled)
+ {
+ llinfos << "Restoring GL..." << llendl;
+ gGLManager.mIsDisabled = FALSE;
+
+ initGLDefaults();
+ LLGLState::restoreGL();
+
+ gTextureList.restoreGL();
+
+ // for future support of non-square pixels, and fonts that are properly stretched
+ //LLFontGL::destroyDefaultFonts();
+ initFonts();
+
+ gSky.restoreGL();
+ gPipeline.restoreGL();
+ LLDrawPoolWater::restoreGL();
+ LLManipTranslate::restoreGL();
+
+ gBumpImageList.restoreGL();
+ LLViewerDynamicTexture::restoreGL();
+ LLVOAvatar::restoreGL();
+
+ gResizeScreenTexture = TRUE;
+ gWindowResized = TRUE;
+
+ if (isAgentAvatarValid() && !gAgentAvatarp->isUsingBakedTextures())
+ {
+ LLVisualParamHint::requestHintUpdates();
+ }
+
+ if (!progress_message.empty())
+ {
+ gRestoreGLTimer.reset();
+ gRestoreGL = TRUE;
+ setShowProgress(TRUE);
+ setProgressString(progress_message);
+ }
+ llinfos << "...Restoring GL done" << llendl;
+ if(!LLAppViewer::instance()->restoreErrorTrap())
+ {
+ llwarns << " Someone took over my signal/exception handler (post restoreGL)!" << llendl;
+ }
+
+ }
+}
+
+void LLViewerWindow::initFonts(F32 zoom_factor)
+{
+ LLFontGL::destroyAllGL();
+ // Initialize with possibly different zoom factor
+ LLFontGL::initClass( gSavedSettings.getF32("FontScreenDPI"),
+ mDisplayScale.mV[VX] * zoom_factor,
+ mDisplayScale.mV[VY] * zoom_factor,
+ gDirUtilp->getAppRODataDir(),
+ LLUI::getXUIPaths());
+ // Force font reloads, which can be very slow
+ LLFontGL::loadDefaultFonts();
+}
+
+void LLViewerWindow::requestResolutionUpdate()
+{
+ mResDirty = true;
+}
+
+void LLViewerWindow::checkSettings()
+{
+ if (mStatesDirty)
+ {
+ gGL.refreshState();
+ LLViewerShaderMgr::instance()->setShaders();
+ mStatesDirty = false;
+ }
+
+ // We want to update the resolution AFTER the states getting refreshed not before.
+ if (mResDirty)
+ {
+ reshape(getWindowWidthRaw(), getWindowHeightRaw());
+ mResDirty = false;
+ }
+}
+
+void LLViewerWindow::restartDisplay(BOOL show_progress_bar)
+{
+ llinfos << "Restaring GL" << llendl;
+ stopGL();
+ if (show_progress_bar)
+ {
+ restoreGL(LLTrans::getString("ProgressChangingResolution"));
+ }
+ else
+ {
+ restoreGL();
+ }
+}
+
+BOOL LLViewerWindow::changeDisplaySettings(LLCoordScreen size, BOOL disable_vsync, BOOL show_progress_bar)
+{
+ //BOOL was_maximized = gSavedSettings.getBOOL("WindowMaximized");
+
+ //gResizeScreenTexture = TRUE;
+
+ //U32 fsaa = gSavedSettings.getU32("RenderFSAASamples");
+ //U32 old_fsaa = mWindow->getFSAASamples();
+
+ // if not maximized, use the request size
+ if (!mWindow->getMaximized())
+ {
+ mWindow->setSize(size);
+ }
+
+ //if (fsaa == old_fsaa)
+ {
+ return TRUE;
+ }
+
+/*
+
+ // Close floaters that don't handle settings change
+ LLFloaterReg::hideInstance("snapshot");
+
+ BOOL result_first_try = FALSE;
+ BOOL result_second_try = FALSE;
+
+ LLFocusableElement* keyboard_focus = gFocusMgr.getKeyboardFocus();
+ send_agent_pause();
+ llinfos << "Stopping GL during changeDisplaySettings" << llendl;
+ stopGL();
+ mIgnoreActivate = TRUE;
+ LLCoordScreen old_size;
+ LLCoordScreen old_pos;
+ mWindow->getSize(&old_size);
+
+ //mWindow->setFSAASamples(fsaa);
+
+ result_first_try = mWindow->switchContext(false, size, disable_vsync);
+ if (!result_first_try)
+ {
+ // try to switch back
+ //mWindow->setFSAASamples(old_fsaa);
+ result_second_try = mWindow->switchContext(false, old_size, disable_vsync);
+
+ if (!result_second_try)
+ {
+ // we are stuck...try once again with a minimal resolution?
+ send_agent_resume();
+ mIgnoreActivate = FALSE;
+ return FALSE;
+ }
+ }
+ send_agent_resume();
+
+ llinfos << "Restoring GL during resolution change" << llendl;
+ if (show_progress_bar)
+ {
+ restoreGL(LLTrans::getString("ProgressChangingResolution"));
+ }
+ else
+ {
+ restoreGL();
+ }
+
+ if (!result_first_try)
+ {
+ LLSD args;
+ args["RESX"] = llformat("%d",size.mX);
+ args["RESY"] = llformat("%d",size.mY);
+ LLNotificationsUtil::add("ResolutionSwitchFail", args);
+ size = old_size; // for reshape below
+ }
+
+ BOOL success = result_first_try || result_second_try;
+
+ if (success)
+ {
+ // maximize window if was maximized, else reposition
+ if (was_maximized)
+ {
+ mWindow->maximize();
+ }
+ else
+ {
+ S32 windowX = gSavedSettings.getS32("WindowX");
+ S32 windowY = gSavedSettings.getS32("WindowY");
+
+ mWindow->setPosition(LLCoordScreen ( windowX, windowY ) );
+ }
+ }
+
+ mIgnoreActivate = FALSE;
+ gFocusMgr.setKeyboardFocus(keyboard_focus);
+
+ return success;
+
+ */
+}
+
+F32 LLViewerWindow::getWorldViewAspectRatio() const
+{
+ F32 world_aspect = (F32)mWorldViewRectRaw.getWidth() / (F32)mWorldViewRectRaw.getHeight();
+ return world_aspect;
+}
+
+void LLViewerWindow::calcDisplayScale()
+{
+ F32 ui_scale_factor = gSavedSettings.getF32("UIScaleFactor");
+ LLVector2 display_scale;
+ display_scale.setVec(llmax(1.f / mWindow->getPixelAspectRatio(), 1.f), llmax(mWindow->getPixelAspectRatio(), 1.f));
+ display_scale *= ui_scale_factor;
+
+ // limit minimum display scale
+ if (display_scale.mV[VX] < MIN_DISPLAY_SCALE || display_scale.mV[VY] < MIN_DISPLAY_SCALE)
+ {
+ display_scale *= MIN_DISPLAY_SCALE / llmin(display_scale.mV[VX], display_scale.mV[VY]);
+ }
+
+ if (display_scale != mDisplayScale)
+ {
+ llinfos << "Setting display scale to " << display_scale << llendl;
+
+ mDisplayScale = display_scale;
+ // Init default fonts
+ initFonts();
+ }
+}
+
+//static
+LLRect LLViewerWindow::calcScaledRect(const LLRect & rect, const LLVector2& display_scale)
+{
+ LLRect res = rect;
+ res.mLeft = llround((F32)res.mLeft / display_scale.mV[VX]);
+ res.mRight = llround((F32)res.mRight / display_scale.mV[VX]);
+ res.mBottom = llround((F32)res.mBottom / display_scale.mV[VY]);
+ res.mTop = llround((F32)res.mTop / display_scale.mV[VY]);
+
+ return res;
+}
+
+S32 LLViewerWindow::getChatConsoleBottomPad()
+{
+ S32 offset = 0;
+
+ if(LLBottomTray::instanceExists())
+ offset += LLBottomTray::getInstance()->getRect().getHeight();
+
+ return offset;
+}
+
+LLRect LLViewerWindow::getChatConsoleRect()
+{
+ LLRect full_window(0, getWindowHeightScaled(), getWindowWidthScaled(), 0);
+ LLRect console_rect = full_window;
+
+ const S32 CONSOLE_PADDING_TOP = 24;
+ const S32 CONSOLE_PADDING_LEFT = 24;
+ const S32 CONSOLE_PADDING_RIGHT = 10;
+
+ console_rect.mTop -= CONSOLE_PADDING_TOP;
+ console_rect.mBottom += getChatConsoleBottomPad();
+
+ console_rect.mLeft += CONSOLE_PADDING_LEFT;
+
+ static const BOOL CHAT_FULL_WIDTH = gSavedSettings.getBOOL("ChatFullWidth");
+
+ if (CHAT_FULL_WIDTH)
+ {
+ console_rect.mRight -= CONSOLE_PADDING_RIGHT;
+ }
+ else
+ {
+ // Make console rect somewhat narrow so having inventory open is
+ // less of a problem.
+ console_rect.mRight = console_rect.mLeft + 2 * getWindowWidthScaled() / 3;
+ }
+
+ return console_rect;
+}
+//----------------------------------------------------------------------------
+
+
+//static
+bool LLViewerWindow::onAlert(const LLSD& notify)
+{
+ LLNotificationPtr notification = LLNotifications::instance().find(notify["id"].asUUID());
+
+ if (gNoRender)
+ {
+ llinfos << "Alert: " << notification->getName() << llendl;
+ notification->respond(LLSD::emptyMap());
+ LLNotifications::instance().cancel(notification);
+ return false;
+ }
+
+ // If we're in mouselook, the mouse is hidden and so the user can't click
+ // the dialog buttons. In that case, change to First Person instead.
+ if( gAgentCamera.cameraMouselook() )
+ {
+ gAgentCamera.changeCameraToDefault();
+ }
+ return false;
+}
+
+////////////////////////////////////////////////////////////////////////////
+//
+// LLPickInfo
+//
+LLPickInfo::LLPickInfo()
+ : mKeyMask(MASK_NONE),
+ mPickCallback(NULL),
+ mPickType(PICK_INVALID),
+ mWantSurfaceInfo(FALSE),
+ mObjectFace(-1),
+ mUVCoords(-1.f, -1.f),
+ mSTCoords(-1.f, -1.f),
+ mXYCoords(-1, -1),
+ mIntersection(),
+ mNormal(),
+ mBinormal(),
+ mHUDIcon(NULL),
+ mPickTransparent(FALSE)
+{
+}
+
+LLPickInfo::LLPickInfo(const LLCoordGL& mouse_pos,
+ MASK keyboard_mask,
+ BOOL pick_transparent,
+ BOOL pick_uv_coords,
+ void (*pick_callback)(const LLPickInfo& pick_info))
+ : mMousePt(mouse_pos),
+ mKeyMask(keyboard_mask),
+ mPickCallback(pick_callback),
+ mPickType(PICK_INVALID),
+ mWantSurfaceInfo(pick_uv_coords),
+ mObjectFace(-1),
+ mUVCoords(-1.f, -1.f),
+ mSTCoords(-1.f, -1.f),
+ mXYCoords(-1, -1),
+ mNormal(),
+ mBinormal(),
+ mHUDIcon(NULL),
+ mPickTransparent(pick_transparent)
+{
+}
+
+void LLPickInfo::fetchResults()
+{
+
+ S32 face_hit = -1;
+ LLVector3 intersection, normal, binormal;
+ LLVector2 uv;
+
+ LLHUDIcon* hit_icon = gViewerWindow->cursorIntersectIcon(mMousePt.mX, mMousePt.mY, 512.f, &intersection);
+
+ F32 icon_dist = 0.f;
+ if (hit_icon)
+ {
+ icon_dist = (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec();
+ }
+ LLViewerObject* hit_object = gViewerWindow->cursorIntersect(mMousePt.mX, mMousePt.mY, 512.f,
+ NULL, -1, mPickTransparent, &face_hit,
+ &intersection, &uv, &normal, &binormal);
+
+ mPickPt = mMousePt;
+
+ U32 te_offset = face_hit > -1 ? face_hit : 0;
+
+ //unproject relative clicked coordinate from window coordinate using GL
+
+ LLViewerObject* objectp = hit_object;
+
+ if (hit_icon &&
+ (!objectp ||
+ icon_dist < (LLViewerCamera::getInstance()->getOrigin()-intersection).magVec()))
+ {
+ // was this name referring to a hud icon?
+ mHUDIcon = hit_icon;
+ mPickType = PICK_ICON;
+ mPosGlobal = mHUDIcon->getPositionGlobal();
+ }
+ else if (objectp)
+ {
+ if( objectp->getPCode() == LLViewerObject::LL_VO_SURFACE_PATCH )
+ {
+ // Hit land
+ mPickType = PICK_LAND;
+ mObjectID.setNull(); // land has no id
+
+ // put global position into land_pos
+ LLVector3d land_pos;
+ if (!gViewerWindow->mousePointOnLandGlobal(mPickPt.mX, mPickPt.mY, &land_pos))
+ {
+ // The selected point is beyond the draw distance or is otherwise
+ // not selectable. Return before calling mPickCallback().
+ return;
+ }
+
+ // Fudge the land focus a little bit above ground.
+ mPosGlobal = land_pos + LLVector3d::z_axis * 0.1f;
+ }
+ else
+ {
+ if(isFlora(objectp))
+ {
+ mPickType = PICK_FLORA;
+ }
+ else
+ {
+ mPickType = PICK_OBJECT;
+ }
+ mObjectOffset = gAgentCamera.calcFocusOffset(objectp, intersection, mPickPt.mX, mPickPt.mY);
+ mObjectID = objectp->mID;
+ mObjectFace = (te_offset == NO_FACE) ? -1 : (S32)te_offset;
+
+ mPosGlobal = gAgent.getPosGlobalFromAgent(intersection);
+
+ if (mWantSurfaceInfo)
+ {
+ getSurfaceInfo();
+ }
+ }
+ }
+
+ if (mPickCallback)
+ {
+ mPickCallback(*this);
+ }
+}
+
+LLPointer<LLViewerObject> LLPickInfo::getObject() const
+{
+ return gObjectList.findObject( mObjectID );
+}
+
+void LLPickInfo::updateXYCoords()
+{
+ if (mObjectFace > -1)
+ {
+ const LLTextureEntry* tep = getObject()->getTE(mObjectFace);
+ LLPointer<LLViewerTexture> imagep = LLViewerTextureManager::getFetchedTexture(tep->getID());
+ if(mUVCoords.mV[VX] >= 0.f && mUVCoords.mV[VY] >= 0.f && imagep.notNull())
+ {
+ mXYCoords.mX = llround(mUVCoords.mV[VX] * (F32)imagep->getWidth());
+ mXYCoords.mY = llround((1.f - mUVCoords.mV[VY]) * (F32)imagep->getHeight());
+ }
+ }
+}
+
+void LLPickInfo::getSurfaceInfo()
+{
+ // set values to uninitialized - this is what we return if no intersection is found
+ mObjectFace = -1;
+ mUVCoords = LLVector2(-1, -1);
+ mSTCoords = LLVector2(-1, -1);
+ mXYCoords = LLCoordScreen(-1, -1);
+ mIntersection = LLVector3(0,0,0);
+ mNormal = LLVector3(0,0,0);
+ mBinormal = LLVector3(0,0,0);
+
+ LLViewerObject* objectp = getObject();
+
+ if (objectp)
+ {
+ if (gViewerWindow->cursorIntersect(llround((F32)mMousePt.mX), llround((F32)mMousePt.mY), 1024.f,
+ objectp, -1, mPickTransparent,
+ &mObjectFace,
+ &mIntersection,
+ &mSTCoords,
+ &mNormal,
+ &mBinormal))
+ {
+ // if we succeeded with the intersect above, compute the texture coordinates:
+
+ if (objectp->mDrawable.notNull() && mObjectFace > -1)
+ {
+ LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
+
+ mUVCoords = facep->surfaceToTexture(mSTCoords, mIntersection, mNormal);
+ }
+
+ // and XY coords:
+ updateXYCoords();
+
+ }
+ }
+}
+
+
+/* code to get UV via a special UV render - removed in lieu of raycast method
+LLVector2 LLPickInfo::pickUV()
+{
+ LLVector2 result(-1.f, -1.f);
+
+ LLViewerObject* objectp = getObject();
+ if (!objectp)
+ {
+ return result;
+ }
+
+ if (mObjectFace > -1 &&
+ objectp->mDrawable.notNull() && objectp->getPCode() == LL_PCODE_VOLUME &&
+ mObjectFace < objectp->mDrawable->getNumFaces())
+ {
+ S32 scaled_x = llround((F32)mPickPt.mX * gViewerWindow->getDisplayScale().mV[VX]);
+ S32 scaled_y = llround((F32)mPickPt.mY * gViewerWindow->getDisplayScale().mV[VY]);
+ const S32 UV_PICK_WIDTH = 5;
+ const S32 UV_PICK_HALF_WIDTH = (UV_PICK_WIDTH - 1) / 2;
+ U8 uv_pick_buffer[UV_PICK_WIDTH * UV_PICK_WIDTH * 4];
+ LLFace* facep = objectp->mDrawable->getFace(mObjectFace);
+ if (facep)
+ {
+ LLGLState scissor_state(GL_SCISSOR_TEST);
+ scissor_state.enable();
+ LLViewerCamera::getInstance()->setPerspective(FOR_SELECTION, scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, FALSE);
+ //glViewport(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
+ glScissor(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH);
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ facep->renderSelectedUV();
+
+ glReadPixels(scaled_x - UV_PICK_HALF_WIDTH, scaled_y - UV_PICK_HALF_WIDTH, UV_PICK_WIDTH, UV_PICK_WIDTH, GL_RGBA, GL_UNSIGNED_BYTE, uv_pick_buffer);
+ U8* center_pixel = &uv_pick_buffer[4 * ((UV_PICK_WIDTH * UV_PICK_HALF_WIDTH) + UV_PICK_HALF_WIDTH + 1)];
+
+ result.mV[VX] = (F32)((center_pixel[VGREEN] & 0xf) + (16.f * center_pixel[VRED])) / 4095.f;
+ result.mV[VY] = (F32)((center_pixel[VGREEN] >> 4) + (16.f * center_pixel[VBLUE])) / 4095.f;
+ }
+ }
+
+ return result;
+} */
+
+
+//static
+bool LLPickInfo::isFlora(LLViewerObject* object)
+{
+ if (!object) return false;
+
+ LLPCode pcode = object->getPCode();
+
+ if( (LL_PCODE_LEGACY_GRASS == pcode)
+ || (LL_PCODE_LEGACY_TREE == pcode)
+ || (LL_PCODE_TREE_NEW == pcode))
+ {
+ return true;
+ }
+ return false;
+}
diff --git a/indra/newview/llvoicecallhandler.cpp b/indra/newview/llvoicecallhandler.cpp
index 274bd75208..2050dab689 100644
--- a/indra/newview/llvoicecallhandler.cpp
+++ b/indra/newview/llvoicecallhandler.cpp
@@ -27,6 +27,8 @@
#include "llviewerprecompiledheaders.h"
#include "llcommandhandler.h"
#include "llavataractions.h"
+#include "llnotificationsutil.h"
+#include "llui.h"
class LLVoiceCallAvatarHandler : public LLCommandHandler
{
@@ -38,6 +40,12 @@ public:
bool handle(const LLSD& params, const LLSD& query_map, LLMediaCtrl* web)
{
+ if (!LLUI::sSettingGroups["config"]->getBOOL("EnableVoiceCall"))
+ {
+ LLNotificationsUtil::add("NoVoiceCall", LLSD(), LLSD(), std::string("SwitchToStandardSkinAndQuit"));
+ return true;
+ }
+
//Make sure we have some parameters
if (params.size() == 0)
{
diff --git a/indra/newview/pipeline.cpp b/indra/newview/pipeline.cpp
index 13e537fae5..99feb9a061 100644
--- a/indra/newview/pipeline.cpp
+++ b/indra/newview/pipeline.cpp
@@ -1,9025 +1,9024 @@
-/**
- * @file pipeline.cpp
- * @brief Rendering pipeline.
- *
- * $LicenseInfo:firstyear=2005&license=viewerlgpl$
- * Second Life Viewer Source Code
- * Copyright (C) 2010, Linden Research, Inc.
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation;
- * version 2.1 of the License only.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- *
- * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
- * $/LicenseInfo$
- */
-
-#include "llviewerprecompiledheaders.h"
-
-#include "pipeline.h"
-
-// library includes
-#include "llaudioengine.h" // For debugging.
-#include "imageids.h"
-#include "llerror.h"
-#include "llviewercontrol.h"
-#include "llfasttimer.h"
-#include "llfontgl.h"
-#include "llmemtype.h"
-#include "llnamevalue.h"
-#include "llpointer.h"
-#include "llprimitive.h"
-#include "llvolume.h"
-#include "material_codes.h"
-#include "timing.h"
-#include "v3color.h"
-#include "llui.h"
-#include "llglheaders.h"
-#include "llrender.h"
-#include "llwindow.h" // swapBuffers()
-
-// newview includes
-#include "llagent.h"
-#include "llagentcamera.h"
-#include "lldrawable.h"
-#include "lldrawpoolalpha.h"
-#include "lldrawpoolavatar.h"
-#include "lldrawpoolground.h"
-#include "lldrawpoolbump.h"
-#include "lldrawpooltree.h"
-#include "lldrawpoolwater.h"
-#include "llface.h"
-#include "llfeaturemanager.h"
-#include "llfloatertelehub.h"
-#include "llfloaterreg.h"
-#include "llgldbg.h"
-#include "llhudmanager.h"
-#include "llhudnametag.h"
-#include "llhudtext.h"
-#include "lllightconstants.h"
-#include "llresmgr.h"
-#include "llselectmgr.h"
-#include "llsky.h"
-#include "lltracker.h"
-#include "lltool.h"
-#include "lltoolmgr.h"
-#include "llviewercamera.h"
-#include "llviewertexturelist.h"
-#include "llviewerobject.h"
-#include "llviewerobjectlist.h"
-#include "llviewerparcelmgr.h"
-#include "llviewerregion.h" // for audio debugging.
-#include "llviewerwindow.h" // For getSpinAxis
-#include "llvoavatarself.h"
-#include "llvoground.h"
-#include "llvosky.h"
-#include "llvotree.h"
-#include "llvovolume.h"
-#include "llvosurfacepatch.h"
-#include "llvowater.h"
-#include "llvotree.h"
-#include "llvopartgroup.h"
-#include "llworld.h"
-#include "llcubemap.h"
-#include "llviewershadermgr.h"
-#include "llviewerstats.h"
-#include "llviewerjoystick.h"
-#include "llviewerdisplay.h"
-#include "llwlparammanager.h"
-#include "llwaterparammanager.h"
-#include "llspatialpartition.h"
-#include "llmutelist.h"
-#include "lltoolpie.h"
-
-
-#ifdef _DEBUG
-// Debug indices is disabled for now for debug performance - djs 4/24/02
-//#define DEBUG_INDICES
-#else
-//#define DEBUG_INDICES
-#endif
-
-const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f;
-const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f;
-const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f;
-const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f;
-const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10;
-const U32 REFLECTION_MAP_RES = 128;
-
-// Max number of occluders to search for. JC
-const S32 MAX_OCCLUDER_COUNT = 2;
-
-extern S32 gBoxFrame;
-//extern BOOL gHideSelectedObjects;
-extern BOOL gDisplaySwapBuffers;
-extern BOOL gDebugGL;
-
-// hack counter for rendering a fixed number of frames after toggling
-// fullscreen to work around DEV-5361
-static S32 sDelayedVBOEnable = 0;
-
-BOOL gAvatarBacklight = FALSE;
-
-BOOL gDebugPipeline = FALSE;
-LLPipeline gPipeline;
-const LLMatrix4* gGLLastMatrix = NULL;
-
-LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry");
-LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass");
-LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible");
-LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion");
-LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny");
-LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple");
-LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain");
-LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees");
-LLFastTimer::DeclareTimer FTM_RENDER_UI("UI");
-LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water");
-LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky");
-LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects");
-LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars");
-LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump");
-LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright");
-LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow");
-LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update");
-LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool");
-LLFastTimer::DeclareTimer FTM_POOLS("Pools");
-LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO");
-LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State");
-LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline");
-LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy");
-LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading");
-
-
-static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables");
-static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort");
-
-//----------------------------------------
-std::string gPoolNames[] =
-{
- // Correspond to LLDrawpool enum render type
- "NONE",
- "POOL_SIMPLE",
- "POOL_TERRAIN",
- "POOL_BUMP",
- "POOL_TREE",
- "POOL_SKY",
- "POOL_WL_SKY",
- "POOL_GROUND",
- "POOL_INVISIBLE",
- "POOL_AVATAR",
- "POOL_WATER",
- "POOL_GRASS",
- "POOL_FULLBRIGHT",
- "POOL_GLOW",
- "POOL_ALPHA",
-};
-
-void drawBox(const LLVector3& c, const LLVector3& r);
-void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
-
-U32 nhpo2(U32 v)
-{
- U32 r = 1;
- while (r < v) {
- r *= 2;
- }
- return r;
-}
-
-glh::matrix4f glh_copy_matrix(GLdouble* src)
-{
- glh::matrix4f ret;
- for (U32 i = 0; i < 16; i++)
- {
- ret.m[i] = (F32) src[i];
- }
- return ret;
-}
-
-glh::matrix4f glh_get_current_modelview()
-{
- return glh_copy_matrix(gGLModelView);
-}
-
-glh::matrix4f glh_get_current_projection()
-{
- return glh_copy_matrix(gGLProjection);
-}
-
-void glh_copy_matrix(const glh::matrix4f& src, GLdouble* dst)
-{
- for (U32 i = 0; i < 16; i++)
- {
- dst[i] = src.m[i];
- }
-}
-
-void glh_set_current_modelview(const glh::matrix4f& mat)
-{
- glh_copy_matrix(mat, gGLModelView);
-}
-
-void glh_set_current_projection(glh::matrix4f& mat)
-{
- glh_copy_matrix(mat, gGLProjection);
-}
-
-glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar)
-{
- glh::matrix4f ret(
- 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left),
- 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom),
- 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear),
- 0.f, 0.f, 0.f, 1.f);
-
- return ret;
-}
-
-void display_update_camera();
-//----------------------------------------
-
-S32 LLPipeline::sCompiles = 0;
-
-BOOL LLPipeline::sPickAvatar = TRUE;
-BOOL LLPipeline::sDynamicLOD = TRUE;
-BOOL LLPipeline::sShowHUDAttachments = TRUE;
-BOOL LLPipeline::sRenderPhysicalBeacons = TRUE;
-BOOL LLPipeline::sRenderScriptedBeacons = FALSE;
-BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE;
-BOOL LLPipeline::sRenderParticleBeacons = FALSE;
-BOOL LLPipeline::sRenderSoundBeacons = FALSE;
-BOOL LLPipeline::sRenderBeacons = FALSE;
-BOOL LLPipeline::sRenderHighlight = TRUE;
-BOOL LLPipeline::sForceOldBakedUpload = FALSE;
-S32 LLPipeline::sUseOcclusion = 0;
-BOOL LLPipeline::sDelayVBUpdate = TRUE;
-BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE;
-BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE;
-BOOL LLPipeline::sDisableShaders = FALSE;
-BOOL LLPipeline::sRenderBump = TRUE;
-BOOL LLPipeline::sUseTriStrips = TRUE;
-BOOL LLPipeline::sUseFarClip = TRUE;
-BOOL LLPipeline::sShadowRender = FALSE;
-BOOL LLPipeline::sWaterReflections = FALSE;
-BOOL LLPipeline::sRenderGlow = FALSE;
-BOOL LLPipeline::sReflectionRender = FALSE;
-BOOL LLPipeline::sImpostorRender = FALSE;
-BOOL LLPipeline::sUnderWaterRender = FALSE;
-BOOL LLPipeline::sTextureBindTest = FALSE;
-BOOL LLPipeline::sRenderFrameTest = FALSE;
-BOOL LLPipeline::sRenderAttachedLights = TRUE;
-BOOL LLPipeline::sRenderAttachedParticles = TRUE;
-BOOL LLPipeline::sRenderDeferred = FALSE;
-BOOL LLPipeline::sAllowRebuildPriorityGroup = FALSE ;
-S32 LLPipeline::sVisibleLightCount = 0;
-F32 LLPipeline::sMinRenderSize = 0.f;
-
-
-static LLCullResult* sCull = NULL;
-
-static const U32 gl_cube_face[] =
-{
- GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
- GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
- GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
-};
-
-void validate_framebuffer_object();
-
-
-void addDeferredAttachments(LLRenderTarget& target)
-{
- target.addColorAttachment(GL_RGBA); //specular
- target.addColorAttachment(GL_RGBA); //normal+z
-}
-
-LLPipeline::LLPipeline() :
- mBackfaceCull(FALSE),
- mBatchCount(0),
- mMatrixOpCount(0),
- mTextureMatrixOps(0),
- mMaxBatchSize(0),
- mMinBatchSize(0),
- mMeanBatchSize(0),
- mTrianglesDrawn(0),
- mNumVisibleNodes(0),
- mVerticesRelit(0),
- mLightingChanges(0),
- mGeometryChanges(0),
- mNumVisibleFaces(0),
-
- mInitialized(FALSE),
- mVertexShadersEnabled(FALSE),
- mVertexShadersLoaded(0),
- mRenderDebugFeatureMask(0),
- mRenderDebugMask(0),
- mOldRenderDebugMask(0),
- mLastRebuildPool(NULL),
- mAlphaPool(NULL),
- mSkyPool(NULL),
- mTerrainPool(NULL),
- mWaterPool(NULL),
- mGroundPool(NULL),
- mSimplePool(NULL),
- mFullbrightPool(NULL),
- mInvisiblePool(NULL),
- mGlowPool(NULL),
- mBumpPool(NULL),
- mWLSkyPool(NULL),
- mLightMask(0),
- mLightMovingMask(0),
- mLightingDetail(0),
- mScreenWidth(0),
- mScreenHeight(0)
-{
- mNoiseMap = 0;
- mTrueNoiseMap = 0;
- mLightFunc = 0;
-}
-
-void LLPipeline::init()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT);
-
- sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
- sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
- sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
- LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
- sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
- sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
-
- mInitialized = TRUE;
-
- stop_glerror();
-
- //create render pass pools
- getPool(LLDrawPool::POOL_ALPHA);
- getPool(LLDrawPool::POOL_SIMPLE);
- getPool(LLDrawPool::POOL_GRASS);
- getPool(LLDrawPool::POOL_FULLBRIGHT);
- getPool(LLDrawPool::POOL_INVISIBLE);
- getPool(LLDrawPool::POOL_BUMP);
- getPool(LLDrawPool::POOL_GLOW);
-
- LLViewerStats::getInstance()->mTrianglesDrawnStat.reset();
- resetFrameStats();
-
- for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
- {
- mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled
- }
-
- mRenderDebugFeatureMask = 0xffffffff; // All debugging features on
- mRenderDebugMask = 0; // All debug starts off
-
- // Don't turn on ground when this is set
- // Mac Books with intel 950s need this
- if(!gSavedSettings.getBOOL("RenderGround"))
- {
- toggleRenderType(RENDER_TYPE_GROUND);
- }
-
- mOldRenderDebugMask = mRenderDebugMask;
-
- mBackfaceCull = TRUE;
-
- stop_glerror();
-
- // Enable features
-
- LLViewerShaderMgr::instance()->setShaders();
-
- stop_glerror();
-
- for (U32 i = 0; i < 2; ++i)
- {
- mSpotLightFade[i] = 1.f;
- }
-
- setLightingDetail(-1);
-}
-
-LLPipeline::~LLPipeline()
-{
-
-}
-
-void LLPipeline::cleanup()
-{
- assertInitialized();
-
- mGroupQ1.clear() ;
- mGroupQ2.clear() ;
-
- for(pool_set_t::iterator iter = mPools.begin();
- iter != mPools.end(); )
- {
- pool_set_t::iterator curiter = iter++;
- LLDrawPool* poolp = *curiter;
- if (poolp->isFacePool())
- {
- LLFacePool* face_pool = (LLFacePool*) poolp;
- if (face_pool->mReferences.empty())
- {
- mPools.erase(curiter);
- removeFromQuickLookup( poolp );
- delete poolp;
- }
- }
- else
- {
- mPools.erase(curiter);
- removeFromQuickLookup( poolp );
- delete poolp;
- }
- }
-
- if (!mTerrainPools.empty())
- {
- llwarns << "Terrain Pools not cleaned up" << llendl;
- }
- if (!mTreePools.empty())
- {
- llwarns << "Tree Pools not cleaned up" << llendl;
- }
-
- delete mAlphaPool;
- mAlphaPool = NULL;
- delete mSkyPool;
- mSkyPool = NULL;
- delete mTerrainPool;
- mTerrainPool = NULL;
- delete mWaterPool;
- mWaterPool = NULL;
- delete mGroundPool;
- mGroundPool = NULL;
- delete mSimplePool;
- mSimplePool = NULL;
- delete mFullbrightPool;
- mFullbrightPool = NULL;
- delete mInvisiblePool;
- mInvisiblePool = NULL;
- delete mGlowPool;
- mGlowPool = NULL;
- delete mBumpPool;
- mBumpPool = NULL;
- // don't delete wl sky pool it was handled above in the for loop
- //delete mWLSkyPool;
- mWLSkyPool = NULL;
-
- releaseGLBuffers();
-
- mFaceSelectImagep = NULL;
-
- mMovedBridge.clear();
-
- mInitialized = FALSE;
-}
-
-//============================================================================
-
-void LLPipeline::destroyGL()
-{
- stop_glerror();
- unloadShaders();
- mHighlightFaces.clear();
-
- resetDrawOrders();
-
- resetVertexBuffers();
-
- releaseGLBuffers();
-
- if (LLVertexBuffer::sEnableVBOs)
- {
- // render 30 frames after switching to work around DEV-5361
- sDelayedVBOEnable = 30;
- LLVertexBuffer::sEnableVBOs = FALSE;
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
-
-void LLPipeline::resizeScreenTexture()
-{
- LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE);
- if (gPipeline.canUseVertexShaders() && assertInitialized())
- {
- GLuint resX = gViewerWindow->getWorldViewWidthRaw();
- GLuint resY = gViewerWindow->getWorldViewHeightRaw();
-
- allocateScreenBuffer(resX,resY);
- }
-}
-
-void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
-{
- // remember these dimensions
- mScreenWidth = resX;
- mScreenHeight = resY;
-
- //never use more than 4 samples for render targets
- U32 samples = llmin(gSavedSettings.getU32("RenderFSAASamples"), (U32) 4);
- U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
-
- if (res_mod > 1 && res_mod < resX && res_mod < resY)
- {
- resX /= res_mod;
- resY /= res_mod;
- }
-
- if (gSavedSettings.getBOOL("RenderUIBuffer"))
- {
- mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- }
-
- if (LLPipeline::sRenderDeferred)
- {
- //allocate deferred rendering color buffers
- mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- addDeferredAttachments(mDeferredScreen);
-
- mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- mEdgeMap.allocate(resX, resY, GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
-
- for (U32 i = 0; i < 3; i++)
- {
- mDeferredLight[i].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
- }
-
- for (U32 i = 0; i < 2; i++)
- {
- mGIMapPost[i].allocate(resX,resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
- }
-
- F32 scale = gSavedSettings.getF32("RenderShadowResolutionScale");
-
- //HACK: make alpha masking work on ATI depth shadows (work around for ATI driver bug)
- U32 shadow_fmt = gGLManager.mIsATI ? GL_ALPHA : 0;
-
- for (U32 i = 0; i < 4; i++)
- {
- mShadow[i].allocate(U32(resX*scale),U32(resY*scale), shadow_fmt, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
- }
-
-
- U32 width = nhpo2(U32(resX*scale))/2;
- U32 height = width;
-
- for (U32 i = 4; i < 6; i++)
- {
- mShadow[i].allocate(width, height, shadow_fmt, TRUE, FALSE);
- }
-
- width = nhpo2(resX)/2;
- height = nhpo2(resY)/2;
- mLuminanceMap.allocate(width,height, GL_RGBA, FALSE, FALSE);
- }
- else
- {
- mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
- }
-
-
- if (LLRenderTarget::sUseFBO && gGLManager.mHasFramebufferMultisample && samples > 1)
- {
- mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples);
- if (LLPipeline::sRenderDeferred)
- {
- addDeferredAttachments(mSampleBuffer);
- mDeferredScreen.setSampleBuffer(&mSampleBuffer);
- }
-
- mScreen.setSampleBuffer(&mSampleBuffer);
-
- stop_glerror();
- }
-
- if (LLPipeline::sRenderDeferred)
- { //share depth buffer between deferred targets
- mDeferredScreen.shareDepthBuffer(mScreen);
- for (U32 i = 0; i < 3; i++)
- { //share stencil buffer with screen space lightmap to stencil out sky
- mDeferredScreen.shareDepthBuffer(mDeferredLight[i]);
- }
- }
-
- gGL.getTexUnit(0)->disable();
-
- stop_glerror();
-
-}
-
-//static
-void LLPipeline::updateRenderDeferred()
-{
- BOOL deferred = ((gSavedSettings.getBOOL("RenderDeferred") &&
- LLRenderTarget::sUseFBO &&
- LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
- gSavedSettings.getBOOL("VertexShaderEnable") &&
- gSavedSettings.getBOOL("RenderAvatarVP") &&
- gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE) &&
- !gUseWireframe;
-
- sRenderDeferred = deferred;
-}
-
-void LLPipeline::releaseGLBuffers()
-{
- assertInitialized();
-
- if (mNoiseMap)
- {
- LLImageGL::deleteTextures(1, &mNoiseMap);
- mNoiseMap = 0;
- }
-
- if (mTrueNoiseMap)
- {
- LLImageGL::deleteTextures(1, &mTrueNoiseMap);
- mTrueNoiseMap = 0;
- }
-
- if (mLightFunc)
- {
- LLImageGL::deleteTextures(1, &mLightFunc);
- mLightFunc = 0;
- }
-
- mWaterRef.release();
- mWaterDis.release();
- mScreen.release();
- mUIScreen.release();
- mSampleBuffer.releaseSampleBuffer();
- mDeferredScreen.release();
- mDeferredDepth.release();
- for (U32 i = 0; i < 3; i++)
- {
- mDeferredLight[i].release();
- }
-
- mEdgeMap.release();
- mGIMap.release();
- mGIMapPost[0].release();
- mGIMapPost[1].release();
- mHighlight.release();
- mLuminanceMap.release();
-
- for (U32 i = 0; i < 6; i++)
- {
- mShadow[i].release();
- }
-
- for (U32 i = 0; i < 3; i++)
- {
- mGlow[i].release();
- }
-
- LLVOAvatar::resetImpostors();
-}
-
-void LLPipeline::createGLBuffers()
-{
- LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS);
- assertInitialized();
-
- updateRenderDeferred();
-
- if (LLPipeline::sWaterReflections)
- { //water reflection texture
- U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution");
-
- mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE);
- mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE);
- }
-
- mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE);
-
- stop_glerror();
-
- GLuint resX = gViewerWindow->getWorldViewWidthRaw();
- GLuint resY = gViewerWindow->getWorldViewHeightRaw();
-
- if (LLPipeline::sRenderGlow)
- { //screen space glow buffers
- const U32 glow_res = llmax(1,
- llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow")));
-
- for (U32 i = 0; i < 3; i++)
- {
- mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE);
- }
-
- allocateScreenBuffer(resX,resY);
- mScreenWidth = 0;
- mScreenHeight = 0;
-
- }
-
- if (sRenderDeferred)
- {
- if (!mNoiseMap)
- {
- const U32 noiseRes = 128;
- LLVector3 noise[noiseRes*noiseRes];
-
- F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f;
- for (U32 i = 0; i < noiseRes*noiseRes; ++i)
- {
- noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f);
- noise[i].normVec();
- noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f;
- }
-
- LLImageGL::generateTextures(1, &mNoiseMap);
-
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
- LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- if (!mTrueNoiseMap)
- {
- const U32 noiseRes = 128;
- F32 noise[noiseRes*noiseRes*3];
- for (U32 i = 0; i < noiseRes*noiseRes*3; i++)
- {
- noise[i] = ll_frand()*2.0-1.0;
- }
-
- LLImageGL::generateTextures(1, &mTrueNoiseMap);
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap);
- LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- if (!mLightFunc)
- {
- U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
- U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
- U8* lg = new U8[lightResX*lightResY];
-
- for (U32 y = 0; y < lightResY; ++y)
- {
- for (U32 x = 0; x < lightResX; ++x)
- {
- //spec func
- F32 sa = (F32) x/(lightResX-1);
- F32 spec = (F32) y/(lightResY-1);
- //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255);
-
- //F32 sp = acosf(sa)/(1.f-spec);
-
- sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent"));
- F32 a = acosf(sa*0.25f+0.75f);
- F32 m = llmax(0.5f-spec*0.5f, 0.001f);
- F32 t2 = tanf(a)/m;
- t2 *= t2;
-
- F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f;
- F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2);
-
- lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255);
- }
- }
-
- LLImageGL::generateTextures(1, &mLightFunc);
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
- LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_ALPHA, lightResX, lightResY, GL_ALPHA, GL_UNSIGNED_BYTE, lg);
- gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
-
- delete [] lg;
- }
-
- if (gSavedSettings.getBOOL("RenderDeferredGI"))
- {
- mGIMap.allocate(512,512,GL_RGBA, TRUE, FALSE);
- addDeferredAttachments(mGIMap);
- }
- }
-}
-
-void LLPipeline::restoreGL()
-{
- LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL);
- assertInitialized();
-
- if (mVertexShadersEnabled)
- {
- LLViewerShaderMgr::instance()->setShaders();
- }
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->restoreGL();
- }
- }
- }
-}
-
-
-BOOL LLPipeline::canUseVertexShaders()
-{
- if (sDisableShaders ||
- !gGLManager.mHasVertexShader ||
- !gGLManager.mHasFragmentShader ||
- !LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") ||
- (assertInitialized() && mVertexShadersLoaded != 1) )
- {
- return FALSE;
- }
- else
- {
- return TRUE;
- }
-}
-
-BOOL LLPipeline::canUseWindLightShaders() const
-{
- return (!LLPipeline::sDisableShaders &&
- gWLSkyProgram.mProgramObject != 0 &&
- LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1);
-}
-
-BOOL LLPipeline::canUseWindLightShadersOnObjects() const
-{
- return (canUseWindLightShaders()
- && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0);
-}
-
-BOOL LLPipeline::canUseAntiAliasing() const
-{
- return TRUE; //(gSavedSettings.getBOOL("RenderUseFBO"));
-}
-
-void LLPipeline::unloadShaders()
-{
- LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS);
- LLViewerShaderMgr::instance()->unloadShaders();
-
- mVertexShadersLoaded = 0;
-}
-
-void LLPipeline::assertInitializedDoError()
-{
- llerrs << "LLPipeline used when uninitialized." << llendl;
-}
-
-//============================================================================
-
-void LLPipeline::enableShadows(const BOOL enable_shadows)
-{
- //should probably do something here to wrangle shadows....
-}
-
-S32 LLPipeline::getMaxLightingDetail() const
-{
- /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS)
- {
- return 3;
- }
- else*/
- {
- return 1;
- }
-}
-
-S32 LLPipeline::setLightingDetail(S32 level)
-{
- LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL);
- assertInitialized();
-
- if (level < 0)
- {
- if (gSavedSettings.getBOOL("VertexShaderEnable"))
- {
- level = 1;
- }
- else
- {
- level = 0;
- }
- }
- level = llclamp(level, 0, getMaxLightingDetail());
- if (level != mLightingDetail)
- {
- mLightingDetail = level;
-
- if (mVertexShadersLoaded == 1)
- {
- LLViewerShaderMgr::instance()->setShaders();
- }
- }
- return mLightingDetail;
-}
-
-class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable>
-{
-public:
- const std::set<LLViewerFetchedTexture*>& mTextures;
-
- LLOctreeDirtyTexture(const std::set<LLViewerFetchedTexture*>& textures) : mTextures(textures) { }
-
- virtual void visit(const LLOctreeNode<LLDrawable>* node)
- {
- LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
-
- if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty())
- {
- for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
- {
- for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
- {
- LLDrawInfo* params = *j;
- LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture);
- if (tex && mTextures.find(tex) != mTextures.end())
- {
- group->setState(LLSpatialGroup::GEOM_DIRTY);
- }
- }
- }
- }
-
- for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
- {
- LLSpatialBridge* bridge = *i;
- traverse(bridge->mOctree);
- }
- }
-};
-
-// Called when a texture changes # of channels (causes faces to move to alpha pool)
-void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures)
-{
- assertInitialized();
-
- // *TODO: This is inefficient and causes frame spikes; need a better way to do this
- // Most of the time is spent in dirty.traverse.
-
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (poolp->isFacePool())
- {
- ((LLFacePool*) poolp)->dirtyTextures(textures);
- }
- }
-
- LLOctreeDirtyTexture dirty(textures);
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- dirty.traverse(part->mOctree);
- }
- }
- }
-}
-
-LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
-{
- assertInitialized();
-
- LLDrawPool *poolp = NULL;
- switch( type )
- {
- case LLDrawPool::POOL_SIMPLE:
- poolp = mSimplePool;
- break;
-
- case LLDrawPool::POOL_GRASS:
- poolp = mGrassPool;
- break;
-
- case LLDrawPool::POOL_FULLBRIGHT:
- poolp = mFullbrightPool;
- break;
-
- case LLDrawPool::POOL_INVISIBLE:
- poolp = mInvisiblePool;
- break;
-
- case LLDrawPool::POOL_GLOW:
- poolp = mGlowPool;
- break;
-
- case LLDrawPool::POOL_TREE:
- poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 );
- break;
-
- case LLDrawPool::POOL_TERRAIN:
- poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 );
- break;
-
- case LLDrawPool::POOL_BUMP:
- poolp = mBumpPool;
- break;
-
- case LLDrawPool::POOL_ALPHA:
- poolp = mAlphaPool;
- break;
-
- case LLDrawPool::POOL_AVATAR:
- break; // Do nothing
-
- case LLDrawPool::POOL_SKY:
- poolp = mSkyPool;
- break;
-
- case LLDrawPool::POOL_WATER:
- poolp = mWaterPool;
- break;
-
- case LLDrawPool::POOL_GROUND:
- poolp = mGroundPool;
- break;
-
- case LLDrawPool::POOL_WL_SKY:
- poolp = mWLSkyPool;
- break;
-
- default:
- llassert(0);
- llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl;
- break;
- }
-
- return poolp;
-}
-
-
-LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
- LLDrawPool *poolp = findPool(type, tex0);
- if (poolp)
- {
- return poolp;
- }
-
- LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0);
- addPool( new_poolp );
-
- return new_poolp;
-}
-
-
-// static
-LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
- U32 type = getPoolTypeFromTE(te, imagep);
- return gPipeline.getPool(type, imagep);
-}
-
-//static
-U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
-{
- LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE);
-
- if (!te || !imagep)
- {
- return 0;
- }
-
- bool alpha = te->getColor().mV[3] < 0.999f;
- if (imagep)
- {
- alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2);
- }
-
- if (alpha)
- {
- return LLDrawPool::POOL_ALPHA;
- }
- else if ((te->getBumpmap() || te->getShiny()))
- {
- return LLDrawPool::POOL_BUMP;
- }
- else
- {
- return LLDrawPool::POOL_SIMPLE;
- }
-}
-
-
-void LLPipeline::addPool(LLDrawPool *new_poolp)
-{
- LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL);
- assertInitialized();
- mPools.insert(new_poolp);
- addToQuickLookup( new_poolp );
-}
-
-void LLPipeline::allocDrawable(LLViewerObject *vobj)
-{
- LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE);
- LLDrawable *drawable = new LLDrawable();
- vobj->mDrawable = drawable;
-
- drawable->mVObjp = vobj;
-
- //encompass completely sheared objects by taking
- //the most extreme point possible (<1,1,0.5>)
- drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length());
- if (vobj->isOrphaned())
- {
- drawable->setState(LLDrawable::FORCE_INVISIBLE);
- }
- drawable->updateXform(TRUE);
-}
-
-
-void LLPipeline::unlinkDrawable(LLDrawable *drawable)
-{
- LLFastTimer t(FTM_PIPELINE);
-
- assertInitialized();
-
- LLPointer<LLDrawable> drawablep = drawable; // make sure this doesn't get deleted before we are done
-
- // Based on flags, remove the drawable from the queues that it's on.
- if (drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep);
- if (iter != mMovedList.end())
- {
- mMovedList.erase(iter);
- }
- }
-
- if (drawablep->getSpatialGroup())
- {
- if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup()))
- {
-#ifdef LL_RELEASE_FOR_DOWNLOAD
- llwarns << "Couldn't remove object from spatial group!" << llendl;
-#else
- llerrs << "Couldn't remove object from spatial group!" << llendl;
-#endif
- }
- }
-
- mLights.erase(drawablep);
- for (light_set_t::iterator iter = mNearbyLights.begin();
- iter != mNearbyLights.end(); iter++)
- {
- if (iter->drawable == drawablep)
- {
- mNearbyLights.erase(iter);
- break;
- }
- }
-
- {
- HighlightItem item(drawablep);
- mHighlightSet.erase(item);
-
- if (mHighlightObject == drawablep)
- {
- mHighlightObject = NULL;
- }
- }
-
- for (U32 i = 0; i < 2; ++i)
- {
- if (mShadowSpotLight[i] == drawablep)
- {
- mShadowSpotLight[i] = NULL;
- }
-
- if (mTargetShadowSpotLight[i] == drawablep)
- {
- mTargetShadowSpotLight[i] = NULL;
- }
- }
-
-
-}
-
-U32 LLPipeline::addObject(LLViewerObject *vobj)
-{
- LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT);
- if (gNoRender)
- {
- return 0;
- }
-
- if (gSavedSettings.getBOOL("RenderDelayCreation"))
- {
- mCreateQ.push_back(vobj);
- }
- else
- {
- createObject(vobj);
- }
-
- return 1;
-}
-
-void LLPipeline::createObjects(F32 max_dtime)
-{
- LLFastTimer ftm(FTM_GEO_UPDATE);
- LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS);
-
- LLTimer update_timer;
-
- while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime)
- {
- LLViewerObject* vobj = mCreateQ.front();
- if (!vobj->isDead())
- {
- createObject(vobj);
- }
- mCreateQ.pop_front();
- }
-
- //for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter)
- //{
- // createObject(*iter);
- //}
-
- //mCreateQ.clear();
-}
-
-void LLPipeline::createObject(LLViewerObject* vobj)
-{
- LLDrawable* drawablep = vobj->mDrawable;
-
- if (!drawablep)
- {
- drawablep = vobj->createDrawable(this);
- }
- else
- {
- llerrs << "Redundant drawable creation!" << llendl;
- }
-
- llassert(drawablep);
-
- if (vobj->getParent())
- {
- vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1
- }
- else
- {
- vobj->setDrawableParent(NULL); // LLPipeline::addObject 2
- }
-
- markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE);
-
- if (drawablep->getVOVolume() && gSavedSettings.getBOOL("RenderAnimateRes"))
- {
- // fun animated res
- drawablep->updateXform(TRUE);
- drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
- drawablep->setScale(LLVector3(0,0,0));
- drawablep->makeActive();
- }
-}
-
-
-void LLPipeline::resetFrameStats()
-{
- assertInitialized();
-
- LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f);
-
- if (mBatchCount > 0)
- {
- mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount;
- }
- mTrianglesDrawn = 0;
- sCompiles = 0;
- mVerticesRelit = 0;
- mLightingChanges = 0;
- mGeometryChanges = 0;
- mNumVisibleFaces = 0;
-
- if (mOldRenderDebugMask != mRenderDebugMask)
- {
- gObjectList.clearDebugText();
- mOldRenderDebugMask = mRenderDebugMask;
- }
-
-}
-
-//external functions for asynchronous updating
-void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
-{
- if (gSavedSettings.getBOOL("FreezeTime"))
- {
- return;
- }
- if (!drawablep)
- {
- llerrs << "updateMove called with NULL drawablep" << llendl;
- return;
- }
- if (drawablep->isState(LLDrawable::EARLY_MOVE))
- {
- return;
- }
-
- assertInitialized();
-
- // update drawable now
- drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED
- drawablep->updateMove(); // returns done
- drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
- // Put on move list so that EARLY_MOVE gets cleared
- if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- mMovedList.push_back(drawablep);
- drawablep->setState(LLDrawable::ON_MOVE_LIST);
- }
-}
-
-void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
-{
- if (gSavedSettings.getBOOL("FreezeTime"))
- {
- return;
- }
- if (!drawablep)
- {
- llerrs << "updateMove called with NULL drawablep" << llendl;
- return;
- }
- if (drawablep->isState(LLDrawable::EARLY_MOVE))
- {
- return;
- }
-
- assertInitialized();
-
- // update drawable now
- drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED
- drawablep->updateMove();
- drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
- // Put on move list so that EARLY_MOVE gets cleared
- if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- mMovedList.push_back(drawablep);
- drawablep->setState(LLDrawable::ON_MOVE_LIST);
- }
-}
-
-void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
-{
- for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin();
- iter != moved_list.end(); )
- {
- LLDrawable::drawable_vector_t::iterator curiter = iter++;
- LLDrawable *drawablep = *curiter;
- BOOL done = TRUE;
- if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE)))
- {
- done = drawablep->updateMove();
- }
- drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED);
- if (done)
- {
- drawablep->clearState(LLDrawable::ON_MOVE_LIST);
- iter = moved_list.erase(curiter);
- }
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree");
-static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move");
-
-void LLPipeline::updateMove()
-{
- LLFastTimer t(FTM_UPDATE_MOVE);
- LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE);
-
- if (gSavedSettings.getBOOL("FreezeTime"))
- {
- return;
- }
-
- assertInitialized();
-
- {
- static LLFastTimer::DeclareTimer ftm("Retexture");
- LLFastTimer t(ftm);
-
- for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
- iter != mRetexturedList.end(); ++iter)
- {
- LLDrawable* drawablep = *iter;
- if (drawablep && !drawablep->isDead())
- {
- drawablep->updateTexture();
- }
- }
- mRetexturedList.clear();
- }
-
- {
- static LLFastTimer::DeclareTimer ftm("Moved List");
- LLFastTimer t(ftm);
- updateMovedList(mMovedList);
- }
-
- //balance octrees
- {
- LLFastTimer ot(FTM_OCTREE_BALANCE);
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->mOctree->balance();
- }
- }
- }
- }
-}
-
-/////////////////////////////////////////////////////////////////////////////
-// Culling and occlusion testing
-/////////////////////////////////////////////////////////////////////////////
-
-//static
-F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera)
-{
- LLVector3 lookAt = center - camera.getOrigin();
- F32 dist = lookAt.length();
-
- //ramp down distance for nearby objects
- //shrink dist by dist/16.
- if (dist < 16.f)
- {
- dist /= 16.f;
- dist *= dist;
- dist *= 16.f;
- }
-
- //get area of circle around node
- F32 app_angle = atanf(size.length()/dist);
- F32 radius = app_angle*LLDrawable::sCurPixelAngle;
- return radius*radius * F_PI;
-}
-
-void LLPipeline::grabReferences(LLCullResult& result)
-{
- sCull = &result;
-}
-
-BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera)
-{
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- if (part->visibleObjectsInFrustum(camera))
- {
- return TRUE;
- }
- }
- }
- }
- }
-
- return FALSE;
-}
-
-BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max)
-{
- const F32 X = 65536.f;
-
- min = LLVector3(X,X,X);
- max = LLVector3(-X,-X,-X);
-
- U32 saved_camera_id = LLViewerCamera::sCurCameraID;
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
-
- BOOL res = TRUE;
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- if (!part->getVisibleExtents(camera, min, max))
- {
- res = FALSE;
- }
- }
- }
- }
- }
-
- LLViewerCamera::sCurCameraID = saved_camera_id;
-
- return res;
-}
-
-static LLFastTimer::DeclareTimer FTM_CULL("Object Culling");
-
-void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip)
-{
- LLFastTimer t(FTM_CULL);
- LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL);
-
- grabReferences(result);
-
- sCull->clear();
-
- BOOL to_texture = LLPipeline::sUseOcclusion > 1 &&
- !hasRenderType(LLPipeline::RENDER_TYPE_HUD) &&
- LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
- gPipeline.canUseVertexShaders() &&
- sRenderGlow;
-
- if (to_texture)
- {
- mScreen.bindTarget();
- }
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixd(gGLLastProjection);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLLastModelView);
-
-
- LLVertexBuffer::unbind();
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- if (sUseOcclusion > 1)
- {
- gGL.setColorMask(false, false);
- }
-
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- if (water_clip != 0)
- {
- LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight());
- camera.setUserClipPlane(plane);
- }
- else
- {
- camera.disableUserClipPlane();
- }
-
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- part->cull(camera);
- }
- }
- }
- }
-
- camera.disableUserClipPlane();
-
- if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) &&
- gSky.mVOSkyp.notNull() &&
- gSky.mVOSkyp->mDrawable.notNull())
- {
- gSky.mVOSkyp->mDrawable->setVisible(camera);
- sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
- gSky.updateCull();
- stop_glerror();
- }
-
- if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) &&
- !gPipeline.canUseWindLightShaders() &&
- gSky.mVOGroundp.notNull() &&
- gSky.mVOGroundp->mDrawable.notNull() &&
- !LLPipeline::sWaterReflections)
- {
- gSky.mVOGroundp->mDrawable->setVisible(camera);
- sCull->pushDrawable(gSky.mVOGroundp->mDrawable);
- }
-
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- if (sUseOcclusion > 1)
- {
- gGL.setColorMask(true, false);
- }
-
- if (to_texture)
- {
- mScreen.flush();
- }
-}
-
-void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
-{
- if (group->getData().empty())
- {
- return;
- }
-
- group->setVisible();
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- group->updateDistance(camera);
- }
-
- const F32 MINIMUM_PIXEL_AREA = 16.f;
-
- if (group->mPixelArea < MINIMUM_PIXEL_AREA)
- {
- return;
- }
-
- if (sMinRenderSize > 0.f &&
- llmax(llmax(group->mBounds[1].mV[0], group->mBounds[1].mV[1]), group->mBounds[1].mV[2]) < sMinRenderSize)
- {
- return;
- }
-
- assertInitialized();
-
- if (!group->mSpatialPartition->mRenderByGroup)
- { //render by drawable
- sCull->pushDrawableGroup(group);
- }
- else
- { //render by group
- sCull->pushVisibleGroup(group);
- }
-
- mNumVisibleNodes++;
-}
-
-void LLPipeline::markOccluder(LLSpatialGroup* group)
-{
- if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION))
- {
- LLSpatialGroup* parent = group->getParent();
-
- if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
- { //only mark top most occluders as active occlusion
- sCull->pushOcclusionGroup(group);
- group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
-
- if (parent &&
- !parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) &&
- parent->getElementCount() == 0 &&
- parent->needsUpdate())
- {
- sCull->pushOcclusionGroup(group);
- parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
- }
- }
- }
-}
-
-void LLPipeline::doOcclusion(LLCamera& camera)
-{
- LLVertexBuffer::unbind();
-
- if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
- {
- gGL.setColorMask(true, false, false, false);
- }
- else
- {
- gGL.setColorMask(false, false);
- }
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
-
- LLGLDisable cull(GL_CULL_FACE);
- if (LLPipeline::sUseOcclusion > 1)
- {
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->doOcclusion(&camera);
- group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
- }
- }
-
- gGL.setColorMask(true, false);
-}
-
-BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
-{
- BOOL update_complete = drawablep->updateGeometry(priority);
- if (update_complete && assertInitialized())
- {
- drawablep->setState(LLDrawable::BUILT);
- mGeometryChanges++;
- }
- return update_complete;
-}
-
-void LLPipeline::updateGL()
-{
- while (!LLGLUpdate::sGLQ.empty())
- {
- LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
- glu->updateGL();
- glu->mInQ = FALSE;
- LLGLUpdate::sGLQ.pop_front();
- }
-}
-
-void LLPipeline::rebuildPriorityGroups()
-{
- if(!sAllowRebuildPriorityGroup)
- {
- return ;
- }
- sAllowRebuildPriorityGroup = FALSE ;
-
- LLTimer update_timer;
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
-
- assertInitialized();
-
- // Iterate through all drawables on the priority build queue,
- for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin();
- iter != mGroupQ1.end(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->rebuildGeom();
- group->clearState(LLSpatialGroup::IN_BUILD_Q1);
- }
-
- mGroupQ1.clear();
-}
-
-void LLPipeline::rebuildGroups()
-{
- // Iterate through some drawables on the non-priority build queue
- S32 size = (S32) mGroupQ2.size();
- S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size);
-
- S32 count = 0;
-
- std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency());
-
- LLSpatialGroup::sg_vector_t::iterator iter;
- for (iter = mGroupQ2.begin();
- iter != mGroupQ2.end(); ++iter)
- {
- LLSpatialGroup* group = *iter;
-
- if (group->isDead())
- {
- continue;
- }
-
- group->rebuildGeom();
-
- if (group->mSpatialPartition->mRenderByGroup)
- {
- count++;
- }
-
- group->clearState(LLSpatialGroup::IN_BUILD_Q2);
-
- if (count > min_count)
- {
- ++iter;
- break;
- }
- }
-
- mGroupQ2.erase(mGroupQ2.begin(), iter);
-
- updateMovedList(mMovedBridge);
-}
-
-void LLPipeline::updateGeom(F32 max_dtime)
-{
- LLTimer update_timer;
- LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM);
- LLPointer<LLDrawable> drawablep;
-
- LLFastTimer t(FTM_GEO_UPDATE);
-
- assertInitialized();
-
- if (sDelayedVBOEnable > 0)
- {
- if (--sDelayedVBOEnable <= 0)
- {
- resetVertexBuffers();
- LLVertexBuffer::sEnableVBOs = TRUE;
- }
- }
-
- // notify various object types to reset internal cost metrics, etc.
- // for now, only LLVOVolume does this to throttle LOD changes
- LLVOVolume::preUpdateGeom();
-
- // Iterate through all drawables on the priority build queue,
- for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin();
- iter != mBuildQ1.end();)
- {
- LLDrawable::drawable_list_t::iterator curiter = iter++;
- LLDrawable* drawablep = *curiter;
- if (drawablep && !drawablep->isDead())
- {
- if (drawablep->isState(LLDrawable::IN_REBUILD_Q2))
- {
- drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
- LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep);
- if (find != mBuildQ2.end())
- {
- mBuildQ2.erase(find);
- }
- }
-
- if (updateDrawableGeom(drawablep, TRUE))
- {
- drawablep->clearState(LLDrawable::IN_REBUILD_Q1);
- mBuildQ1.erase(curiter);
- }
- }
- else
- {
- mBuildQ1.erase(curiter);
- }
- }
-
- // Iterate through some drawables on the non-priority build queue
- S32 min_count = 16;
- S32 size = (S32) mBuildQ2.size();
- if (size > 1024)
- {
- min_count = llclamp((S32) (size * (F32) size/4096), 16, size);
- }
-
- S32 count = 0;
-
- max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime);
- LLSpatialGroup* last_group = NULL;
- LLSpatialBridge* last_bridge = NULL;
-
- for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin();
- iter != mBuildQ2.end(); )
- {
- LLDrawable::drawable_list_t::iterator curiter = iter++;
- LLDrawable* drawablep = *curiter;
-
- LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() :
- drawablep->getParent()->getSpatialBridge();
-
- if (drawablep->getSpatialGroup() != last_group &&
- (!last_bridge || bridge != last_bridge) &&
- (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count)
- {
- break;
- }
-
- //make sure updates don't stop in the middle of a spatial group
- //to avoid thrashing (objects are enqueued by group)
- last_group = drawablep->getSpatialGroup();
- last_bridge = bridge;
-
- BOOL update_complete = TRUE;
- if (!drawablep->isDead())
- {
- update_complete = updateDrawableGeom(drawablep, FALSE);
- count++;
- }
- if (update_complete)
- {
- drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
- mBuildQ2.erase(curiter);
- }
- }
-
- updateMovedList(mMovedBridge);
-}
-
-void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE);
-
- if(drawablep && !drawablep->isDead())
- {
- if (drawablep->isSpatialBridge())
- {
- const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable;
- llassert(root); // trying to catch a bad assumption
- if (root && // // this test may not be needed, see above
- root->getVObj()->isAttachment())
- {
- LLDrawable* rootparent = root->getParent();
- if (rootparent) // this IS sometimes NULL
- {
- LLViewerObject *vobj = rootparent->getVObj();
- llassert(vobj); // trying to catch a bad assumption
- if (vobj) // this test may not be needed, see above
- {
- const LLVOAvatar* av = vobj->asAvatar();
- if (av && av->isImpostor())
- {
- return;
- }
- }
- }
- }
- sCull->pushBridge((LLSpatialBridge*) drawablep);
- }
- else
- {
- sCull->pushDrawable(drawablep);
- }
-
- drawablep->setVisible(camera);
- }
-}
-
-void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
-{
- LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED);
-
- if (!drawablep)
- {
- //llerrs << "Sending null drawable to moved list!" << llendl;
- return;
- }
-
- if (drawablep->isDead())
- {
- llwarns << "Marking NULL or dead drawable moved!" << llendl;
- return;
- }
-
- if (drawablep->getParent())
- {
- //ensure that parent drawables are moved first
- markMoved(drawablep->getParent(), damped_motion);
- }
-
- assertInitialized();
-
- if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
- {
- if (drawablep->isSpatialBridge())
- {
- mMovedBridge.push_back(drawablep);
- }
- else
- {
- mMovedList.push_back(drawablep);
- }
- drawablep->setState(LLDrawable::ON_MOVE_LIST);
- }
- if (damped_motion == FALSE)
- {
- drawablep->setState(LLDrawable::MOVE_UNDAMPED); // UNDAMPED trumps DAMPED
- }
- else if (drawablep->isState(LLDrawable::MOVE_UNDAMPED))
- {
- drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
- }
-}
-
-void LLPipeline::markShift(LLDrawable *drawablep)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT);
-
- if (!drawablep || drawablep->isDead())
- {
- return;
- }
-
- assertInitialized();
-
- if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST))
- {
- drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE);
- if (drawablep->getParent())
- {
- markShift(drawablep->getParent());
- }
- mShiftList.push_back(drawablep);
- drawablep->setState(LLDrawable::ON_SHIFT_LIST);
- }
-}
-
-void LLPipeline::shiftObjects(const LLVector3 &offset)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS);
-
- assertInitialized();
-
- glClear(GL_DEPTH_BUFFER_BIT);
- gDepthDirty = TRUE;
-
- for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
- iter != mShiftList.end(); iter++)
- {
- LLDrawable *drawablep = *iter;
- if (drawablep->isDead())
- {
- continue;
- }
- drawablep->shiftPos(offset);
- drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
- }
- mShiftList.resize(0);
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->shift(offset);
- }
- }
- }
-
- LLHUDText::shiftAll(offset);
- LLHUDNameTag::shiftAll(offset);
- display_update_camera();
-}
-
-void LLPipeline::markTextured(LLDrawable *drawablep)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED);
-
- if (drawablep && !drawablep->isDead() && assertInitialized())
- {
- mRetexturedList.insert(drawablep);
- }
-}
-
-void LLPipeline::markGLRebuild(LLGLUpdate* glu)
-{
- if (glu && !glu->mInQ)
- {
- LLGLUpdate::sGLQ.push_back(glu);
- glu->mInQ = TRUE;
- }
-}
-
-void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
- //assert_main_thread();
-
- if (group && !group->isDead() && group->mSpatialPartition)
- {
- if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD)
- {
- priority = TRUE;
- }
-
- if (priority)
- {
- if (!group->isState(LLSpatialGroup::IN_BUILD_Q1))
- {
- mGroupQ1.push_back(group);
- group->setState(LLSpatialGroup::IN_BUILD_Q1);
-
- if (group->isState(LLSpatialGroup::IN_BUILD_Q2))
- {
- LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group);
- if (iter != mGroupQ2.end())
- {
- mGroupQ2.erase(iter);
- }
- group->clearState(LLSpatialGroup::IN_BUILD_Q2);
- }
- }
- }
- else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))
- {
- //llerrs << "Non-priority updates not yet supported!" << llendl;
- if (std::find(mGroupQ2.begin(), mGroupQ2.end(), group) != mGroupQ2.end())
- {
- llerrs << "WTF?" << llendl;
- }
- mGroupQ2.push_back(group);
- group->setState(LLSpatialGroup::IN_BUILD_Q2);
-
- }
- }
-}
-
-void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD);
-
- if (drawablep && !drawablep->isDead() && assertInitialized())
- {
- if (!drawablep->isState(LLDrawable::BUILT))
- {
- priority = TRUE;
- }
- if (priority)
- {
- if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1))
- {
- mBuildQ1.push_back(drawablep);
- drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue
- }
- }
- else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2))
- {
- mBuildQ2.push_back(drawablep);
- drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list
- }
- if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
- {
- drawablep->getVObj()->setChanged(LLXform::SILHOUETTE);
- }
- drawablep->setState(flag);
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order");
-
-void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
-{
- if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_GROUND,
- LLPipeline::RENDER_TYPE_TERRAIN,
- LLPipeline::RENDER_TYPE_TREE,
- LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::END_RENDER_TYPES))
- {
- //clear faces from face pools
- LLFastTimer t(FTM_RESET_DRAWORDER);
- gPipeline.resetDrawOrders();
- }
-
- LLFastTimer ftm(FTM_STATESORT);
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
-
- //LLVertexBuffer::unbind();
-
- grabReferences(result);
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->checkOcclusion();
- if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- markOccluder(group);
- }
- else
- {
- group->setVisible();
- for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
- {
- markVisible(*i, camera);
- }
- }
- }
- for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- group->checkOcclusion();
- if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- markOccluder(group);
- }
- else
- {
- group->setVisible();
- stateSort(group, camera);
- }
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
- {
- LLCullResult::bridge_list_t::iterator cur_iter = i;
- LLSpatialBridge* bridge = *cur_iter;
- LLSpatialGroup* group = bridge->getSpatialGroup();
- if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- stateSort(bridge, camera);
- }
- }
- }
- {
- LLFastTimer ftm(FTM_STATESORT_DRAWABLE);
- for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList();
- iter != sCull->endVisibleList(); ++iter)
- {
- LLDrawable *drawablep = *iter;
- if (!drawablep->isDead())
- {
- stateSort(drawablep, camera);
- }
- }
- }
- {
- LLFastTimer ftm(FTM_CLIENT_COPY);
- LLVertexBuffer::clientCopy();
- }
-
- postSort(camera);
-}
-
-void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
- if (group->changeLOD())
- {
- for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
- {
- LLDrawable* drawablep = *i;
- stateSort(drawablep, camera);
- }
- }
-
-}
-
-void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
- if (!sShadowRender && bridge->getSpatialGroup()->changeLOD())
- {
- bool force_update = false;
- bridge->updateDistance(camera, force_update);
- }
-}
-
-void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
-
- if (!drawablep
- || drawablep->isDead()
- || !hasRenderType(drawablep->getRenderType()))
- {
- return;
- }
-
- if (LLSelectMgr::getInstance()->mHideSelectedObjects)
- {
- if (drawablep->getVObj().notNull() &&
- drawablep->getVObj()->isSelected())
- {
- return;
- }
- }
-
- if (drawablep->isAvatar())
- { //don't draw avatars beyond render distance or if we don't have a spatial group.
- if ((drawablep->getSpatialGroup() == NULL) ||
- (drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance))
- {
- return;
- }
-
- LLVOAvatar* avatarp = (LLVOAvatar*) drawablep->getVObj().get();
- if (!avatarp->isVisible())
- {
- return;
- }
- }
-
- assertInitialized();
-
- if (hasRenderType(drawablep->mRenderType))
- {
- if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE))
- {
- drawablep->setVisible(camera, NULL, FALSE);
- }
- else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE))
- {
- // clear invisible flag here to avoid single frame glitch
- drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE);
- }
- }
-
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- LLSpatialGroup* group = drawablep->getSpatialGroup();
- if (!group || group->changeLOD())
- {
- if (drawablep->isVisible())
- {
- if (!drawablep->isActive())
- {
- bool force_update = false;
- drawablep->updateDistance(camera, force_update);
- }
- else if (drawablep->isAvatar())
- {
- bool force_update = false;
- drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility()
- }
- }
- }
- }
-
- if (!drawablep->getVOVolume())
- {
- for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin();
- iter != drawablep->mFaces.end(); iter++)
- {
- LLFace* facep = *iter;
-
- if (facep->hasGeometry())
- {
- if (facep->getPool())
- {
- facep->getPool()->enqueue(facep);
- }
- else
- {
- break;
- }
- }
- }
- }
-
-
- mNumVisibleFaces += drawablep->getNumFaces();
-}
-
-
-void forAllDrawables(LLCullResult::sg_list_t::iterator begin,
- LLCullResult::sg_list_t::iterator end,
- void (*func)(LLDrawable*))
-{
- for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i)
- {
- for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j)
- {
- func(*j);
- }
- }
-}
-
-void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*))
-{
- forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func);
- forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func);
-}
-
-//function for creating scripted beacons
-void renderScriptedBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && !vobj->isAvatar()
- && !vobj->getParent()
- && vobj->flagScripted())
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderScriptedTouchBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && !vobj->isAvatar()
- && !vobj->getParent()
- && vobj->flagScripted()
- && vobj->flagHandleTouch())
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderPhysicalBeacons(LLDrawable* drawablep)
-{
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && !vobj->isAvatar()
- //&& !vobj->getParent()
- && vobj->usePhysics())
- {
- if (gPipeline.sRenderBeacons)
- {
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderParticleBeacons(LLDrawable* drawablep)
-{
- // Look for attachments, objects, etc.
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj
- && vobj->isParticleSource())
- {
- if (gPipeline.sRenderBeacons)
- {
- LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f);
- gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
-
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void renderSoundHighlights(LLDrawable* drawablep)
-{
- // Look for attachments, objects, etc.
- LLViewerObject *vobj = drawablep->getVObj();
- if (vobj && vobj->isAudioSource())
- {
- if (gPipeline.sRenderHighlight)
- {
- S32 face_id;
- S32 count = drawablep->getNumFaces();
- for (face_id = 0; face_id < count; face_id++)
- {
- gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
- }
- }
- }
-}
-
-void LLPipeline::postSort(LLCamera& camera)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT);
- LLFastTimer ftm(FTM_STATESORT_POSTSORT);
-
- assertInitialized();
-
- llpushcallstacks ;
- //rebuild drawable geometry
- for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (!sUseOcclusion ||
- !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- group->rebuildGeom();
- }
- }
- llpushcallstacks ;
- //rebuild groups
- sCull->assertDrawMapsEmpty();
-
- /*LLSpatialGroup::sNoDelete = FALSE;
- for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (sUseOcclusion &&
- group->isState(LLSpatialGroup::OCCLUDED))
- {
- continue;
- }
-
- group->rebuildGeom();
- }
- LLSpatialGroup::sNoDelete = TRUE;*/
-
-
- rebuildPriorityGroups();
- llpushcallstacks ;
-
- const S32 bin_count = 1024*8;
-
- static LLCullResult::drawinfo_list_t alpha_bins[bin_count];
- static U32 bin_size[bin_count];
-
- //clear one bin per frame to avoid memory bloat
- static S32 clear_idx = 0;
- clear_idx = (1+clear_idx)%bin_count;
- alpha_bins[clear_idx].clear();
-
- for (U32 j = 0; j < bin_count; j++)
- {
- bin_size[j] = 0;
- }
-
- //build render map
- for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (sUseOcclusion &&
- group->isOcclusionState(LLSpatialGroup::OCCLUDED))
- {
- continue;
- }
-
- if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY))
- { //no way this group is going to be drawable without a rebuild
- group->rebuildGeom();
- }
-
- for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j)
- {
- LLSpatialGroup::drawmap_elem_t& src_vec = j->second;
- if (!hasRenderType(j->first))
- {
- continue;
- }
-
- for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k)
- {
- if (sMinRenderSize > 0.f)
- {
- LLVector3 bounds = (*k)->mExtents[1]-(*k)->mExtents[0];
- if (llmax(llmax(bounds.mV[0], bounds.mV[1]), bounds.mV[2]) > sMinRenderSize)
- {
- sCull->pushDrawInfo(j->first, *k);
- }
- }
- else
- {
- sCull->pushDrawInfo(j->first, *k);
- }
- }
- }
-
- if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA))
- {
- LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA);
-
- if (alpha != group->mDrawMap.end())
- { //store alpha groups for sorting
- LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
- if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
- {
- if (bridge)
- {
- LLCamera trans_camera = bridge->transformCamera(camera);
- group->updateDistance(trans_camera);
- }
- else
- {
- group->updateDistance(camera);
- }
- }
-
- if (hasRenderType(LLDrawPool::POOL_ALPHA))
- {
- sCull->pushAlphaGroup(group);
- }
- }
- }
- }
-
- if (!sShadowRender)
- {
- //sort by texture or bump map
- for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; ++i)
- {
- if (i == LLRenderPass::PASS_BUMP)
- {
- std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareBump());
- }
- else
- {
- std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareTexturePtrMatrix());
- }
- }
-
- std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater());
- }
- llpushcallstacks ;
- // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus
- if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender)
- {
- if (sRenderScriptedTouchBeacons)
- {
- // Only show the beacon on the root object.
- forAllVisibleDrawables(renderScriptedTouchBeacons);
- }
- else
- if (sRenderScriptedBeacons)
- {
- // Only show the beacon on the root object.
- forAllVisibleDrawables(renderScriptedBeacons);
- }
-
- if (sRenderPhysicalBeacons)
- {
- // Only show the beacon on the root object.
- forAllVisibleDrawables(renderPhysicalBeacons);
- }
-
- if (sRenderParticleBeacons)
- {
- forAllVisibleDrawables(renderParticleBeacons);
- }
-
- // If god mode, also show audio cues
- if (sRenderSoundBeacons && gAudiop)
- {
- // Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible.
- LLAudioEngine::source_map::iterator iter;
- for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter)
- {
- LLAudioSource *sourcep = iter->second;
-
- LLVector3d pos_global = sourcep->getPositionGlobal();
- LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global);
- if (gPipeline.sRenderBeacons)
- {
- //pos += LLVector3(0.f, 0.f, 0.2f);
- gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
- }
- }
- // now deal with highlights for all those seeable sound sources
- forAllVisibleDrawables(renderSoundHighlights);
- }
- }
- llpushcallstacks ;
- // If managing your telehub, draw beacons at telehub and currently selected spawnpoint.
- if (LLFloaterTelehub::renderBeacons())
- {
- LLFloaterTelehub::addBeacons();
- }
-
- if (!sShadowRender)
- {
- mSelectedFaces.clear();
-
- // Draw face highlights for selected faces.
- if (LLSelectMgr::getInstance()->getTEMode())
- {
- struct f : public LLSelectedTEFunctor
- {
- virtual bool apply(LLViewerObject* object, S32 te)
- {
- if (object->mDrawable)
- {
- gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te));
- }
- return true;
- }
- } func;
- LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
- }
- }
-
- //LLSpatialGroup::sNoDelete = FALSE;
- llpushcallstacks ;
-}
-
-
-void render_hud_elements()
-{
- LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS);
- LLFastTimer t(FTM_RENDER_UI);
- gPipeline.disableLights();
-
- LLGLDisable fog(GL_FOG);
- LLGLSUIDefault gls_ui;
-
- LLGLEnable stencil(GL_STENCIL_TEST);
- glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF);
- glStencilMask(0xFFFFFFFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
-
- gGL.color4f(1,1,1,1);
- if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
- gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d()
-
- // Draw the tracking overlays
- LLTracker::render3D();
-
- // Show the property lines
- LLWorld::getInstance()->renderPropertyLines();
- LLViewerParcelMgr::getInstance()->render();
- LLViewerParcelMgr::getInstance()->renderParcelCollision();
-
- // Render name tags.
- LLHUDObject::renderAll();
- }
- else if (gForceRenderLandFence)
- {
- // This is only set when not rendering the UI, for parcel snapshots
- LLViewerParcelMgr::getInstance()->render();
- }
- else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- LLHUDText::renderAllHUD();
- }
- gGL.flush();
-}
-
-void LLPipeline::renderHighlights()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL);
-
- assertInitialized();
-
- // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD)
- // Render highlighted faces.
- LLGLSPipelineAlpha gls_pipeline_alpha;
- LLColor4 color(1.f, 1.f, 1.f, 0.5f);
- LLGLEnable color_mat(GL_COLOR_MATERIAL);
- disableLights();
-
- if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty())
- { //draw blurry highlight image over screen
- LLGLEnable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- LLGLDisable test(GL_ALPHA_TEST);
-
- LLGLEnable stencil(GL_STENCIL_TEST);
- gGL.flush();
- glStencilMask(0xFFFFFFFF);
- glClearStencil(1);
- glClear(GL_STENCIL_BUFFER_BIT);
-
- glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
- glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
-
- gGL.setColorMask(false, false);
- for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter)
- {
- renderHighlight(iter->mItem->getVObj(), 1.f);
- }
- gGL.setColorMask(true, false);
-
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
-
- //gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
-
- gGL.pushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- gGL.pushMatrix();
- glLoadIdentity();
-
- gGL.getTexUnit(0)->bind(&mHighlight);
-
- LLVector2 tc1;
- LLVector2 tc2;
-
- tc1.setVec(0,0);
- tc2.setVec(2,2);
-
- gGL.begin(LLRender::TRIANGLES);
-
- F32 scale = gSavedSettings.getF32("RenderHighlightBrightness");
- LLColor4 color = gSavedSettings.getColor4("RenderHighlightColor");
- F32 thickness = gSavedSettings.getF32("RenderHighlightThickness");
-
- for (S32 pass = 0; pass < 2; ++pass)
- {
- if (pass == 0)
- {
- gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
- }
- else
- {
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
-
- for (S32 i = 0; i < 8; ++i)
- {
- for (S32 j = 0; j < 8; ++j)
- {
- LLVector2 tc(i-4+0.5f, j-4+0.5f);
-
- F32 dist = 1.f-(tc.length()/sqrtf(32.f));
- dist *= scale/64.f;
-
- tc *= thickness;
- tc.mV[0] = (tc.mV[0])/mHighlight.getWidth();
- tc.mV[1] = (tc.mV[1])/mHighlight.getHeight();
-
- gGL.color4f(color.mV[0],
- color.mV[1],
- color.mV[2],
- color.mV[3]*dist);
-
- gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]);
- gGL.vertex2f(3,-1);
- }
- }
- }
-
- gGL.end();
-
- gGL.popMatrix();
- glMatrixMode(GL_MODELVIEW);
- gGL.popMatrix();
-
- //gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
-
- if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
- {
- gHighlightProgram.bind();
- gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,1,1,0.5f);
- }
-
- if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
- {
- // Make sure the selection image gets downloaded and decoded
- if (!mFaceSelectImagep)
- {
- mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT);
- }
- mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA);
-
- U32 count = mSelectedFaces.size();
- for (U32 i = 0; i < count; i++)
- {
- LLFace *facep = mSelectedFaces[i];
- if (!facep || facep->getDrawable()->isDead())
- {
- llerrs << "Bad face on selection" << llendl;
- return;
- }
-
- facep->renderSelected(mFaceSelectImagep, color);
- }
- }
-
- if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
- {
- // Paint 'em red!
- color.setVec(1.f, 0.f, 0.f, 0.5f);
- if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
- {
- gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,0,0,0.5f);
- }
- int count = mHighlightFaces.size();
- for (S32 i = 0; i < count; i++)
- {
- LLFace* facep = mHighlightFaces[i];
- facep->renderSelected(LLViewerTexture::sNullImagep, color);
- }
- }
-
- // Contains a list of the faces of objects that are physical or
- // have touch-handlers.
- mHighlightFaces.clear();
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)
- {
- gHighlightProgram.unbind();
- }
-}
-
-//debug use
-U32 LLPipeline::sCurRenderPoolType = 0 ;
-
-void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM);
- LLFastTimer t(FTM_RENDER_GEOMETRY);
-
- assertInitialized();
-
- F64 saved_modelview[16];
- F64 saved_projection[16];
-
- //HACK: preserve/restore matrices around HUD render
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- for (U32 i = 0; i < 16; i++)
- {
- saved_modelview[i] = gGLModelView[i];
- saved_projection[i] = gGLProjection[i];
- }
- }
-
- ///////////////////////////////////////////
- //
- // Sync and verify GL state
- //
- //
-
- stop_glerror();
-
- LLVertexBuffer::unbind();
-
- // Do verification of GL state
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- if (mRenderDebugMask & RENDER_DEBUG_VERIFY)
- {
- if (!verify())
- {
- llerrs << "Pipeline verification failed!" << llendl;
- }
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO");
-
- // Initialize lots of GL state to "safe" values
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
-
- LLGLSPipeline gls_pipeline;
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
-
- LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2);
-
- // Toggle backface culling for debugging
- LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0);
- // Set fog
- BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG);
- LLGLEnable fog_enable(use_fog &&
- !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0);
- gSky.updateFog(camera.getFar());
- if (!use_fog)
- {
- sUnderWaterRender = FALSE;
- }
-
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep);
- LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP);
-
- //////////////////////////////////////////////
- //
- // Actually render all of the geometry
- //
- //
- stop_glerror();
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools");
-
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (hasRenderType(poolp->getType()))
- {
- poolp->prerender();
- }
- }
-
- {
- LLFastTimer t(FTM_POOLS);
-
- // HACK: don't calculate local lights if we're rendering the HUD!
- // Removing this check will cause bad flickering when there are
- // HUD elements being rendered AND the user is in flycam mode -nyx
- if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- calcNearbyLights(camera);
- setupHWLights(NULL);
- }
-
- BOOL occlude = sUseOcclusion > 1;
- U32 cur_type = 0;
-
- pool_set_t::iterator iter1 = mPools.begin();
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- //debug use
- sCurRenderPoolType = cur_type ;
-
- if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- doOcclusion(camera);
- }
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
- {
- LLFastTimer t(FTM_POOLRENDER);
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginRenderPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->render(i);
- }
- poolp->endRenderPass(i);
- LLVertexBuffer::unbind();
- if (gDebugGL || gDebugPipeline)
- {
- GLint depth;
- glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
- if (depth > 3)
- {
- if (gDebugSession)
- {
- ll_fail("GL matrix stack corrupted.");
- }
- llerrs << "GL matrix stack corrupted!" << llendl;
- }
- std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i);
- LLGLState::checkStates(msg);
- LLGLState::checkTextureChannels(msg);
- LLGLState::checkClientArrays(msg);
- }
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd");
-
- LLVertexBuffer::unbind();
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- if (occlude)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- doOcclusion(camera);
- }
- }
-
- LLVertexBuffer::unbind();
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
-
-
- stop_glerror();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights");
-
- if (!sReflectionRender)
- {
- renderHighlights();
- }
-
- // Contains a list of the faces of objects that are physical or
- // have touch-handlers.
- mHighlightFaces.clear();
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug");
-
- renderDebug();
-
- LLVertexBuffer::unbind();
-
- if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred)
- {
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- // Render debugging beacons.
- gObjectList.renderObjectBeacons();
- gObjectList.resetObjectBeacons();
- }
- else
- {
- // Make sure particle effects disappear
- LLHUDObject::renderAllForTimer();
- }
- }
- else
- {
- // Make sure particle effects disappear
- LLHUDObject::renderAllForTimer();
- }
-
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd");
-
- //HACK: preserve/restore matrices around HUD render
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- for (U32 i = 0; i < 16; i++)
- {
- gGLModelView[i] = saved_modelview[i];
- gGLProjection[i] = saved_projection[i];
- }
- }
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-}
-
-void LLPipeline::renderGeomDeferred(LLCamera& camera)
-{
- LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
-
- LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED);
- LLFastTimer t(FTM_RENDER_GEOMETRY);
-
- LLFastTimer t2(FTM_POOLS);
-
- LLGLEnable cull(GL_CULL_FACE);
-
- LLGLEnable stencil(GL_STENCIL_TEST);
- glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
- stop_glerror();
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
- stop_glerror();
-
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (hasRenderType(poolp->getType()))
- {
- poolp->prerender();
- }
- }
-
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- U32 cur_type = 0;
-
- gGL.setColorMask(true, true);
-
- pool_set_t::iterator iter1 = mPools.begin();
-
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
- {
- LLFastTimer t(FTM_POOLRENDER);
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginDeferredPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->renderDeferred(i);
- }
- poolp->endDeferredPass(i);
- LLVertexBuffer::unbind();
-
- if (gDebugGL || gDebugPipeline)
- {
- GLint depth;
- glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
- if (depth > 3)
- {
- llerrs << "GL matrix stack corrupted!" << llendl;
- }
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- }
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- gGL.setColorMask(true, false);
-}
-
-void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
-{
- LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF);
- LLFastTimer t(FTM_POOLS);
- U32 cur_type = 0;
-
- LLGLEnable cull(GL_CULL_FACE);
-
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
-
- calcNearbyLights(camera);
- setupHWLights(NULL);
-
- gGL.setColorMask(true, false);
-
- pool_set_t::iterator iter1 = mPools.begin();
- BOOL occlude = LLPipeline::sUseOcclusion > 1;
-
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- doOcclusion(camera);
- gGL.setColorMask(true, false);
- }
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
- {
- LLFastTimer t(FTM_POOLRENDER);
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginPostDeferredPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->renderPostDeferred(i);
- }
- poolp->endPostDeferredPass(i);
- LLVertexBuffer::unbind();
-
- if (gDebugGL || gDebugPipeline)
- {
- GLint depth;
- glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
- if (depth > 3)
- {
- llerrs << "GL matrix stack corrupted!" << llendl;
- }
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- }
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- if (occlude)
- {
- occlude = FALSE;
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- doOcclusion(camera);
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- }
-}
-
-void LLPipeline::renderGeomShadow(LLCamera& camera)
-{
- LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW);
- U32 cur_type = 0;
-
- LLGLEnable cull(GL_CULL_FACE);
-
- LLVertexBuffer::unbind();
-
- pool_set_t::iterator iter1 = mPools.begin();
-
- while ( iter1 != mPools.end() )
- {
- LLDrawPool *poolp = *iter1;
-
- cur_type = poolp->getType();
-
- pool_set_t::iterator iter2 = iter1;
- if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0)
- {
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-
- for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ )
- {
- LLVertexBuffer::unbind();
- poolp->beginShadowPass(i);
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
-
- p->renderShadow(i);
- }
- poolp->endShadowPass(i);
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
- }
- }
- else
- {
- // Skip all pools of this type
- for (iter2 = iter1; iter2 != mPools.end(); iter2++)
- {
- LLDrawPool *p = *iter2;
- if (p->getType() != cur_type)
- {
- break;
- }
- }
- }
- iter1 = iter2;
- stop_glerror();
- }
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
-}
-
-
-void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
-{
- assertInitialized();
- S32 count = 0;
- if (render_type == LLRender::TRIANGLE_STRIP)
- {
- count = index_count-2;
- }
- else
- {
- count = index_count/3;
- }
-
- mTrianglesDrawn += count;
- mBatchCount++;
- mMaxBatchSize = llmax(mMaxBatchSize, count);
- mMinBatchSize = llmin(mMinBatchSize, count);
-
- if (LLPipeline::sRenderFrameTest)
- {
- gViewerWindow->getWindow()->swapBuffers();
- ms_sleep(16);
- }
-}
-
-void LLPipeline::renderDebug()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
-
- assertInitialized();
-
- gGL.color4f(1,1,1,1);
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- gGL.setColorMask(true, false);
-
- // Debug stuff.
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- part->renderDebug();
- }
- }
- }
- }
-
- for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
- {
- LLSpatialBridge* bridge = *i;
- if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
- {
- glPushMatrix();
- glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
- bridge->renderDebug();
- glPopMatrix();
- }
- }
-
- if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- LLGLEnable blend(GL_BLEND);
- LLGLDepthTest depth(TRUE, FALSE);
- LLGLDisable cull(GL_CULL_FACE);
-
- gGL.color4f(1,1,1,1);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- F32 a = 0.1f;
-
- F32 col[] =
- {
- 1,0,0,a,
- 0,1,0,a,
- 0,0,1,a,
- 1,0,1,a,
-
- 1,1,0,a,
- 0,1,1,a,
- 1,1,1,a,
- 1,0,1,a,
- };
-
- for (U32 i = 0; i < 8; i++)
- {
- LLVector3* frust = mShadowCamera[i].mAgentFrustum;
-
- if (i > 3)
- { //render shadow frusta as volumes
- if (mShadowFrustPoints[i-4].empty())
- {
- continue;
- }
-
- gGL.color4fv(col+(i-4)*4);
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
- gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
- gGL.end();
-
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex3fv(frust[0].mV);
- gGL.vertex3fv(frust[1].mV);
- gGL.vertex3fv(frust[3].mV);
- gGL.vertex3fv(frust[2].mV);
- gGL.end();
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[7].mV);
- gGL.vertex3fv(frust[6].mV);
- gGL.end();
- }
-
-
- if (i < 4)
- {
-
- if (i == 0 || !mShadowFrustPoints[i].empty())
- {
- //render visible point cloud
- gGL.flush();
- glPointSize(8.f);
- gGL.begin(LLRender::POINTS);
-
- F32* c = col+i*4;
- gGL.color3fv(c);
-
- for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j)
- {
- gGL.vertex3fv(mShadowFrustPoints[i][j].mV);
-
- }
- gGL.end();
-
- gGL.flush();
- glPointSize(1.f);
-
- LLVector3* ext = mShadowExtents[i];
- LLVector3 pos = (ext[0]+ext[1])*0.5f;
- LLVector3 size = (ext[1]-ext[0])*0.5f;
- drawBoxOutline(pos, size);
-
- //render camera frustum splits as outlines
- gGL.begin(LLRender::LINES);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV);
- gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV);
- gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV);
- gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV);
- gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV);
- gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV);
- gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
- gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
- gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
- gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
- gGL.end();
- }
-
- }
-
- /*for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(j);
- if (part)
- {
- if (hasRenderType(part->mDrawableType))
- {
- part->renderIntersectingBBoxes(&mShadowCamera[i]);
- }
- }
- }
- }*/
- }
- }
-
- if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION)
- {
- // Debug composition layers
- F32 x, y;
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- if (gAgent.getRegion())
- {
- gGL.begin(LLRender::POINTS);
- // Draw the composition layer for the region that I'm in.
- for (x = 0; x <= 260; x++)
- {
- for (y = 0; y <= 260; y++)
- {
- if ((x > 255) || (y > 255))
- {
- gGL.color4f(1.f, 0.f, 0.f, 1.f);
- }
- else
- {
- gGL.color4f(0.f, 0.f, 1.f, 1.f);
- }
- F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y);
- z *= 5.f;
- z += 50.f;
- gGL.vertex3f(x, y, z);
- }
- }
- gGL.end();
- }
- }
-
- if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE)
- {
- U32 count = 0;
- U32 size = mBuildQ2.size();
- LLColor4 col;
-
- LLGLEnable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
-
- for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter)
- {
- LLSpatialGroup* group = *iter;
- if (group->isDead())
- {
- continue;
- }
-
- LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
-
- if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead()))
- {
- continue;
- }
-
- if (bridge)
- {
- gGL.pushMatrix();
- glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
- }
-
- F32 alpha = (F32) (size-count)/size;
-
-
- LLVector2 c(1.f-alpha, alpha);
- c.normVec();
-
-
- ++count;
- col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.1f);
- group->drawObjectBox(col);
-
- if (bridge)
- {
- gGL.popMatrix();
- }
- }
- }
-
- gGL.flush();
-}
-
-void LLPipeline::rebuildPools()
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS);
-
- assertInitialized();
-
- S32 max_count = mPools.size();
- pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool);
- while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS)
- {
- if (iter1 == mPools.end())
- {
- iter1 = mPools.begin();
- }
- LLDrawPool* poolp = *iter1;
-
- if (poolp->isDead())
- {
- mPools.erase(iter1++);
- removeFromQuickLookup( poolp );
- if (poolp == mLastRebuildPool)
- {
- mLastRebuildPool = NULL;
- }
- delete poolp;
- }
- else
- {
- mLastRebuildPool = poolp;
- iter1++;
- }
- max_count--;
- }
-
- if (isAgentAvatarValid())
- {
- gAgentAvatarp->rebuildHUD();
- }
-}
-
-void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
-{
- LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP);
-
- assertInitialized();
-
- switch( new_poolp->getType() )
- {
- case LLDrawPool::POOL_SIMPLE:
- if (mSimplePool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate simple pool." << llendl;
- }
- else
- {
- mSimplePool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_GRASS:
- if (mGrassPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate grass pool." << llendl;
- }
- else
- {
- mGrassPool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_FULLBRIGHT:
- if (mFullbrightPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate simple pool." << llendl;
- }
- else
- {
- mFullbrightPool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_INVISIBLE:
- if (mInvisiblePool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate simple pool." << llendl;
- }
- else
- {
- mInvisiblePool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_GLOW:
- if (mGlowPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate glow pool." << llendl;
- }
- else
- {
- mGlowPool = (LLRenderPass*) new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_TREE:
- mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
- break;
-
- case LLDrawPool::POOL_TERRAIN:
- mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
- break;
-
- case LLDrawPool::POOL_BUMP:
- if (mBumpPool)
- {
- llassert(0);
- llwarns << "Ignoring duplicate bump pool." << llendl;
- }
- else
- {
- mBumpPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_ALPHA:
- if( mAlphaPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl;
- }
- else
- {
- mAlphaPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_AVATAR:
- break; // Do nothing
-
- case LLDrawPool::POOL_SKY:
- if( mSkyPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl;
- }
- else
- {
- mSkyPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_WATER:
- if( mWaterPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl;
- }
- else
- {
- mWaterPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_GROUND:
- if( mGroundPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl;
- }
- else
- {
- mGroundPool = new_poolp;
- }
- break;
-
- case LLDrawPool::POOL_WL_SKY:
- if( mWLSkyPool )
- {
- llassert(0);
- llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl;
- }
- else
- {
- mWLSkyPool = new_poolp;
- }
- break;
-
- default:
- llassert(0);
- llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl;
- break;
- }
-}
-
-void LLPipeline::removePool( LLDrawPool* poolp )
-{
- assertInitialized();
- removeFromQuickLookup(poolp);
- mPools.erase(poolp);
- delete poolp;
-}
-
-void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
-{
- assertInitialized();
- LLMemType mt(LLMemType::MTYPE_PIPELINE);
- switch( poolp->getType() )
- {
- case LLDrawPool::POOL_SIMPLE:
- llassert(mSimplePool == poolp);
- mSimplePool = NULL;
- break;
-
- case LLDrawPool::POOL_GRASS:
- llassert(mGrassPool == poolp);
- mGrassPool = NULL;
- break;
-
- case LLDrawPool::POOL_FULLBRIGHT:
- llassert(mFullbrightPool == poolp);
- mFullbrightPool = NULL;
- break;
-
- case LLDrawPool::POOL_INVISIBLE:
- llassert(mInvisiblePool == poolp);
- mInvisiblePool = NULL;
- break;
-
- case LLDrawPool::POOL_WL_SKY:
- llassert(mWLSkyPool == poolp);
- mWLSkyPool = NULL;
- break;
-
- case LLDrawPool::POOL_GLOW:
- llassert(mGlowPool == poolp);
- mGlowPool = NULL;
- break;
-
- case LLDrawPool::POOL_TREE:
- #ifdef _DEBUG
- {
- BOOL found = mTreePools.erase( (uintptr_t)poolp->getTexture() );
- llassert( found );
- }
- #else
- mTreePools.erase( (uintptr_t)poolp->getTexture() );
- #endif
- break;
-
- case LLDrawPool::POOL_TERRAIN:
- #ifdef _DEBUG
- {
- BOOL found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
- llassert( found );
- }
- #else
- mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
- #endif
- break;
-
- case LLDrawPool::POOL_BUMP:
- llassert( poolp == mBumpPool );
- mBumpPool = NULL;
- break;
-
- case LLDrawPool::POOL_ALPHA:
- llassert( poolp == mAlphaPool );
- mAlphaPool = NULL;
- break;
-
- case LLDrawPool::POOL_AVATAR:
- break; // Do nothing
-
- case LLDrawPool::POOL_SKY:
- llassert( poolp == mSkyPool );
- mSkyPool = NULL;
- break;
-
- case LLDrawPool::POOL_WATER:
- llassert( poolp == mWaterPool );
- mWaterPool = NULL;
- break;
-
- case LLDrawPool::POOL_GROUND:
- llassert( poolp == mGroundPool );
- mGroundPool = NULL;
- break;
-
- default:
- llassert(0);
- llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl;
- break;
- }
-}
-
-void LLPipeline::resetDrawOrders()
-{
- assertInitialized();
- // Iterate through all of the draw pools and rebuild them.
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- poolp->resetDrawOrders();
- }
-}
-
-//============================================================================
-// Once-per-frame setup of hardware lights,
-// including sun/moon, avatar backlight, and up to 6 local lights
-
-void LLPipeline::setupAvatarLights(BOOL for_edit)
-{
- assertInitialized();
-
- if (for_edit)
- {
- LLColor4 diffuse(1.f, 1.f, 1.f, 0.f);
- LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light
- LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview();
- LLMatrix4 camera_rot(camera_mat.getMat3());
- camera_rot.invert();
- LLVector4 light_pos = light_pos_cam * camera_rot;
-
- light_pos.normalize();
-
- mHWLightColors[1] = diffuse;
- glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse.mV);
- glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
- glLightfv(GL_LIGHT1, GL_POSITION, light_pos.mV);
- glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0f);
- glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.0f);
- glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 180.0f);
- }
- else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini)
- {
- LLVector3 opposite_pos = -1.f * mSunDir;
- LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis;
- LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f);
- backlight_pos.normalize();
-
- LLColor4 light_diffuse = mSunDiffuse;
- LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f);
- F32 max_component = 0.001f;
- for (S32 i = 0; i < 3; i++)
- {
- if (backlight_diffuse.mV[i] > max_component)
- {
- max_component = backlight_diffuse.mV[i];
- }
- }
- F32 backlight_mag;
- if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
- {
- backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT;
- }
- else
- {
- backlight_mag = BACKLIGHT_NIGHT_MAGNITUDE_OBJECT;
- }
- backlight_diffuse *= backlight_mag / max_component;
-
- mHWLightColors[1] = backlight_diffuse;
- glLightfv(GL_LIGHT1, GL_POSITION, backlight_pos.mV); // this is just sun/moon direction
- glLightfv(GL_LIGHT1, GL_DIFFUSE, backlight_diffuse.mV);
- glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
- glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0f);
- glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.0f);
- glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 180.0f);
- }
- else
- {
- mHWLightColors[1] = LLColor4::black;
- glLightfv(GL_LIGHT1, GL_DIFFUSE, LLColor4::black.mV);
- glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
- }
-}
-
-static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist)
-{
- F32 inten = light->getLightIntensity();
- if (inten < .001f)
- {
- return max_dist;
- }
- F32 radius = light->getLightRadius();
- BOOL selected = light->isSelected();
- LLVector3 dpos = light->getRenderPosition() - cam_pos;
- F32 dist2 = dpos.lengthSquared();
- if (!selected && dist2 > (max_dist + radius)*(max_dist + radius))
- {
- return max_dist;
- }
- F32 dist = fsqrtf(dist2);
- dist *= 1.f / inten;
- dist -= radius;
- if (selected)
- {
- dist -= 10000.f; // selected lights get highest priority
- }
- if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE))
- {
- // moving lights get a little higher priority (too much causes artifacts)
- dist -= light->getLightRadius()*0.25f;
- }
- return dist;
-}
-
-void LLPipeline::calcNearbyLights(LLCamera& camera)
-{
- assertInitialized();
-
- if (LLPipeline::sReflectionRender)
- {
- return;
- }
-
- if (mLightingDetail >= 1)
- {
- // mNearbyLight (and all light_set_t's) are sorted such that
- // begin() == the closest light and rbegin() == the farthest light
- const S32 MAX_LOCAL_LIGHTS = 6;
-// LLVector3 cam_pos = gAgentCamera.getCameraPositionAgent();
- LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ?
- camera.getOrigin() :
- gAgent.getPositionAgent();
-
- F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad
-
- // UPDATE THE EXISTING NEARBY LIGHTS
- light_set_t cur_nearby_lights;
- for (light_set_t::iterator iter = mNearbyLights.begin();
- iter != mNearbyLights.end(); iter++)
- {
- const Light* light = &(*iter);
- LLDrawable* drawable = light->drawable;
- LLVOVolume* volight = drawable->getVOVolume();
- if (!volight || !drawable->isState(LLDrawable::LIGHT))
- {
- drawable->clearState(LLDrawable::NEARBY_LIGHT);
- continue;
- }
- if (light->fade <= -LIGHT_FADE_TIME)
- {
- drawable->clearState(LLDrawable::NEARBY_LIGHT);
- continue;
- }
- if (!sRenderAttachedLights && volight && volight->isAttachment())
- {
- drawable->clearState(LLDrawable::NEARBY_LIGHT);
- continue;
- }
-
- F32 dist = calc_light_dist(volight, cam_pos, max_dist);
- cur_nearby_lights.insert(Light(drawable, dist, light->fade));
- }
- mNearbyLights = cur_nearby_lights;
-
- // FIND NEW LIGHTS THAT ARE IN RANGE
- light_set_t new_nearby_lights;
- for (LLDrawable::drawable_set_t::iterator iter = mLights.begin();
- iter != mLights.end(); ++iter)
- {
- LLDrawable* drawable = *iter;
- LLVOVolume* light = drawable->getVOVolume();
- if (!light || drawable->isState(LLDrawable::NEARBY_LIGHT))
- {
- continue;
- }
- if (light->isHUDAttachment())
- {
- continue; // no lighting from HUD objects
- }
- F32 dist = calc_light_dist(light, cam_pos, max_dist);
- if (dist >= max_dist)
- {
- continue;
- }
- if (!sRenderAttachedLights && light && light->isAttachment())
- {
- continue;
- }
- new_nearby_lights.insert(Light(drawable, dist, 0.f));
- if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS)
- {
- new_nearby_lights.erase(--new_nearby_lights.end());
- const Light& last = *new_nearby_lights.rbegin();
- max_dist = last.dist;
- }
- }
-
- // INSERT ANY NEW LIGHTS
- for (light_set_t::iterator iter = new_nearby_lights.begin();
- iter != new_nearby_lights.end(); iter++)
- {
- const Light* light = &(*iter);
- if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS)
- {
- mNearbyLights.insert(*light);
- ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT);
- }
- else
- {
- // crazy cast so that we can overwrite the fade value
- // even though gcc enforces sets as const
- // (fade value doesn't affect sort so this is safe)
- Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin()))));
- if (light->dist < farthest_light->dist)
- {
- if (farthest_light->fade >= 0.f)
- {
- farthest_light->fade = -gFrameIntervalSeconds;
- }
- }
- else
- {
- break; // none of the other lights are closer
- }
- }
- }
-
- }
-}
-
-void LLPipeline::setupHWLights(LLDrawPool* pool)
-{
- assertInitialized();
-
- // Ambient
- LLColor4 ambient = gSky.getTotalAmbientColor();
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV);
-
- // Light 0 = Sun or Moon (All objects)
- {
- if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
- {
- mSunDir.setVec(gSky.getSunDirection());
- mSunDiffuse.setVec(gSky.getSunDiffuseColor());
- }
- else
- {
- mSunDir.setVec(gSky.getMoonDirection());
- mSunDiffuse.setVec(gSky.getMoonDiffuseColor());
- }
-
- F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]);
- if (max_color > 1.f)
- {
- mSunDiffuse *= 1.f/max_color;
- }
- mSunDiffuse.clamp();
-
- LLVector4 light_pos(mSunDir, 0.0f);
- LLColor4 light_diffuse = mSunDiffuse;
- mHWLightColors[0] = light_diffuse;
- glLightfv(GL_LIGHT0, GL_POSITION, light_pos.mV); // this is just sun/moon direction
- glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse.mV);
- glLightfv(GL_LIGHT0, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(GL_LIGHT0, GL_SPECULAR, LLColor4::black.mV);
- glLightf (GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f);
- glLightf (GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0f);
- glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 0.0f);
- glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 180.0f);
- }
-
- // Light 1 = Backlight (for avatars)
- // (set by enableLightsAvatar)
-
- S32 cur_light = 2;
-
- // Nearby lights = LIGHT 2-7
-
- mLightMovingMask = 0;
-
- if (mLightingDetail >= 1)
- {
- for (light_set_t::iterator iter = mNearbyLights.begin();
- iter != mNearbyLights.end(); ++iter)
- {
- LLDrawable* drawable = iter->drawable;
- LLVOVolume* light = drawable->getVOVolume();
- if (!light)
- {
- continue;
- }
- if (drawable->isState(LLDrawable::ACTIVE))
- {
- mLightMovingMask |= (1<<cur_light);
- }
-
- LLColor4 light_color = light->getLightColor();
- light_color.mV[3] = 0.0f;
-
- F32 fade = iter->fade;
- if (fade < LIGHT_FADE_TIME)
- {
- // fade in/out light
- if (fade >= 0.f)
- {
- fade = fade / LIGHT_FADE_TIME;
- ((Light*) (&(*iter)))->fade += gFrameIntervalSeconds;
- }
- else
- {
- fade = 1.f + fade / LIGHT_FADE_TIME;
- ((Light*) (&(*iter)))->fade -= gFrameIntervalSeconds;
- }
- fade = llclamp(fade,0.f,1.f);
- light_color *= fade;
- }
-
- LLVector3 light_pos(light->getRenderPosition());
- LLVector4 light_pos_gl(light_pos, 1.0f);
-
- F32 light_radius = llmax(light->getLightRadius(), 0.001f);
-
- F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior.
- float linatten = x / (light_radius); // % of brightness at radius
-
- mHWLightColors[cur_light] = light_color;
- S32 gllight = GL_LIGHT0+cur_light;
- glLightfv(gllight, GL_POSITION, light_pos_gl.mV);
- glLightfv(gllight, GL_DIFFUSE, light_color.mV);
- glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV);
- glLightf (gllight, GL_CONSTANT_ATTENUATION, 0.0f);
- glLightf (gllight, GL_LINEAR_ATTENUATION, linatten);
- glLightf (gllight, GL_QUADRATIC_ATTENUATION, 0.0f);
- if (light->isLightSpotlight() // directional (spot-)light
- && (LLPipeline::sRenderDeferred || gSavedSettings.getBOOL("RenderSpotLightsInNondeferred"))) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on
- {
- LLVector3 spotparams = light->getSpotLightParams();
- LLQuaternion quat = light->getRenderRotation();
- LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction
- at_axis *= quat;
- //llinfos << "SPOT!!!!!!! fov: " << spotparams.mV[0] << " focus: " << spotparams.mV[1] << " dir: " << at_axis << llendl;
- glLightfv(gllight, GL_SPOT_DIRECTION, at_axis.mV);
- glLightf (gllight, GL_SPOT_EXPONENT, 2.0f); // 2.0 = good old dot product ^ 2
- glLightf (gllight, GL_SPOT_CUTOFF, 90.0f); // hemisphere
- const float specular[] = {0.f, 0.f, 0.f, 0.f};
- glLightfv(gllight, GL_SPECULAR, specular);
- }
- else // omnidirectional (point) light
- {
- glLightf (gllight, GL_SPOT_EXPONENT, 0.0f);
- glLightf (gllight, GL_SPOT_CUTOFF, 180.0f);
-
- // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight
- const float specular[] = {0.f, 0.f, 0.f, 1.f};
- glLightfv(gllight, GL_SPECULAR, specular);
- //llinfos << "boring light" << llendl;
- }
- cur_light++;
- if (cur_light >= 8)
- {
- break; // safety
- }
- }
- }
- for ( ; cur_light < 8 ; cur_light++)
- {
- mHWLightColors[cur_light] = LLColor4::black;
- S32 gllight = GL_LIGHT0+cur_light;
- glLightfv(gllight, GL_DIFFUSE, LLColor4::black.mV);
- glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
- }
-
- if (isAgentAvatarValid() &&
- gAgentAvatarp->mSpecialRenderMode == 3)
- {
- LLColor4 light_color = LLColor4::white;
- light_color.mV[3] = 0.0f;
-
- LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin());
- LLVector4 light_pos_gl(light_pos, 1.0f);
-
- F32 light_radius = 16.f;
-
- F32 x = 3.f;
- float linatten = x / (light_radius); // % of brightness at radius
-
- mHWLightColors[2] = light_color;
- S32 gllight = GL_LIGHT2;
- glLightfv(gllight, GL_POSITION, light_pos_gl.mV);
- glLightfv(gllight, GL_DIFFUSE, light_color.mV);
- glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV);
- glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
- glLightf (gllight, GL_CONSTANT_ATTENUATION, 0.0f);
- glLightf (gllight, GL_LINEAR_ATTENUATION, linatten);
- glLightf (gllight, GL_QUADRATIC_ATTENUATION, 0.0f);
- glLightf (gllight, GL_SPOT_EXPONENT, 0.0f);
- glLightf (gllight, GL_SPOT_CUTOFF, 180.0f);
- }
-
- // Init GL state
- glDisable(GL_LIGHTING);
- for (S32 gllight=GL_LIGHT0; gllight<=GL_LIGHT7; gllight++)
- {
- glDisable(gllight);
- }
- mLightMask = 0;
-}
-
-void LLPipeline::enableLights(U32 mask)
-{
- assertInitialized();
-
- if (mLightingDetail == 0)
- {
- mask &= 0xf003; // sun and backlight only (and fullbright bit)
- }
- if (mLightMask != mask)
- {
- stop_glerror();
- if (!mLightMask)
- {
- glEnable(GL_LIGHTING);
- }
- if (mask)
- {
- stop_glerror();
- for (S32 i=0; i<8; i++)
- {
- if (mask & (1<<i))
- {
- glEnable(GL_LIGHT0 + i);
- glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, mHWLightColors[i].mV);
- }
- else
- {
- glDisable(GL_LIGHT0 + i);
- glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, LLColor4::black.mV);
- }
- }
- stop_glerror();
- }
- else
- {
- glDisable(GL_LIGHTING);
- }
- stop_glerror();
- mLightMask = mask;
- LLColor4 ambient = gSky.getTotalAmbientColor();
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV);
- stop_glerror();
- }
-}
-
-void LLPipeline::enableLightsStatic()
-{
- assertInitialized();
- U32 mask = 0x01; // Sun
- if (mLightingDetail >= 2)
- {
- mask |= mLightMovingMask; // Hardware moving lights
- glColor4f(0.f, 0.f, 0.f, 1.0f); // no local lighting by default
- }
- else
- {
- mask |= 0xff & (~2); // Hardware local lights
- }
- enableLights(mask);
-}
-
-void LLPipeline::enableLightsDynamic()
-{
- assertInitialized();
- U32 mask = 0xff & (~2); // Local lights
- enableLights(mask);
- if (mLightingDetail >= 2)
- {
- glColor4f(0.f, 0.f, 0.f, 1.f); // no local lighting by default
- }
-
- if (isAgentAvatarValid() && getLightingDetail() <= 0)
- {
- if (gAgentAvatarp->mSpecialRenderMode == 0) // normal
- {
- gPipeline.enableLightsAvatar();
- }
- else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview
- {
- gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f));
- }
- }
-}
-
-void LLPipeline::enableLightsAvatar()
-{
- U32 mask = 0xff; // All lights
- setupAvatarLights(FALSE);
- enableLights(mask);
-}
-
-void LLPipeline::enableLightsAvatarEdit(const LLColor4& color)
-{
- U32 mask = 0x2002; // Avatar backlight only, set ambient
- setupAvatarLights(TRUE);
- enableLights(mask);
-
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
-}
-
-void LLPipeline::enableLightsFullbright(const LLColor4& color)
-{
- assertInitialized();
- U32 mask = 0x1000; // Non-0 mask, set ambient
- enableLights(mask);
-
- glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
- /*if (mLightingDetail >= 2)
- {
- glColor4f(0.f, 0.f, 0.f, 1.f); // no local lighting by default
- }*/
-}
-
-void LLPipeline::disableLights()
-{
- enableLights(0); // no lighting (full bright)
- glColor4f(1.f, 1.f, 1.f, 1.f); // lighting color = white by default
-}
-
-//============================================================================
-
-class LLMenuItemGL;
-class LLInvFVBridge;
-struct cat_folder_pair;
-class LLVOBranch;
-class LLVOLeaf;
-
-void LLPipeline::findReferences(LLDrawable *drawablep)
-{
- assertInitialized();
- if (mLights.find(drawablep) != mLights.end())
- {
- llinfos << "In mLights" << llendl;
- }
- if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end())
- {
- llinfos << "In mMovedList" << llendl;
- }
- if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end())
- {
- llinfos << "In mShiftList" << llendl;
- }
- if (mRetexturedList.find(drawablep) != mRetexturedList.end())
- {
- llinfos << "In mRetexturedList" << llendl;
- }
-
- if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end())
- {
- llinfos << "In mBuildQ1" << llendl;
- }
- if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end())
- {
- llinfos << "In mBuildQ2" << llendl;
- }
-
- S32 count;
-
- count = gObjectList.findReferences(drawablep);
- if (count)
- {
- llinfos << "In other drawables: " << count << " references" << llendl;
- }
-}
-
-BOOL LLPipeline::verify()
-{
- BOOL ok = assertInitialized();
- if (ok)
- {
- for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
- {
- LLDrawPool *poolp = *iter;
- if (!poolp->verify())
- {
- ok = FALSE;
- }
- }
- }
-
- if (!ok)
- {
- llwarns << "Pipeline verify failed!" << llendl;
- }
- return ok;
-}
-
-//////////////////////////////
-//
-// Collision detection
-//
-//
-
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-/**
- * A method to compute a ray-AABB intersection.
- * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990
- * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500)
- * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only)
- *
- * Hence this version is faster as well as more robust than the original one.
- *
- * Should work provided:
- * 1) the integer representation of 0.0f is 0x00000000
- * 2) the sign bit of the float is the most significant one
- *
- * Report bugs: p.terdiman@codercorner.com
- *
- * \param aabb [in] the axis-aligned bounding box
- * \param origin [in] ray origin
- * \param dir [in] ray direction
- * \param coord [out] impact coordinates
- * \return true if ray intersects AABB
- */
-///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-//#define RAYAABB_EPSILON 0.00001f
-#define IR(x) ((U32&)x)
-
-bool LLRayAABB(const LLVector3 &center, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon)
-{
- BOOL Inside = TRUE;
- LLVector3 MinB = center - size;
- LLVector3 MaxB = center + size;
- LLVector3 MaxT;
- MaxT.mV[VX]=MaxT.mV[VY]=MaxT.mV[VZ]=-1.0f;
-
- // Find candidate planes.
- for(U32 i=0;i<3;i++)
- {
- if(origin.mV[i] < MinB.mV[i])
- {
- coord.mV[i] = MinB.mV[i];
- Inside = FALSE;
-
- // Calculate T distances to candidate planes
- if(IR(dir.mV[i])) MaxT.mV[i] = (MinB.mV[i] - origin.mV[i]) / dir.mV[i];
- }
- else if(origin.mV[i] > MaxB.mV[i])
- {
- coord.mV[i] = MaxB.mV[i];
- Inside = FALSE;
-
- // Calculate T distances to candidate planes
- if(IR(dir.mV[i])) MaxT.mV[i] = (MaxB.mV[i] - origin.mV[i]) / dir.mV[i];
- }
- }
-
- // Ray origin inside bounding box
- if(Inside)
- {
- coord = origin;
- return true;
- }
-
- // Get largest of the maxT's for final choice of intersection
- U32 WhichPlane = 0;
- if(MaxT.mV[1] > MaxT.mV[WhichPlane]) WhichPlane = 1;
- if(MaxT.mV[2] > MaxT.mV[WhichPlane]) WhichPlane = 2;
-
- // Check final candidate actually inside box
- if(IR(MaxT.mV[WhichPlane])&0x80000000) return false;
-
- for(U32 i=0;i<3;i++)
- {
- if(i!=WhichPlane)
- {
- coord.mV[i] = origin.mV[i] + MaxT.mV[WhichPlane] * dir.mV[i];
- if (epsilon > 0)
- {
- if(coord.mV[i] < MinB.mV[i] - epsilon || coord.mV[i] > MaxB.mV[i] + epsilon) return false;
- }
- else
- {
- if(coord.mV[i] < MinB.mV[i] || coord.mV[i] > MaxB.mV[i]) return false;
- }
- }
- }
- return true; // ray hits box
-}
-
-//////////////////////////////
-//
-// Macros, functions, and inline methods from other classes
-//
-//
-
-void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
-{
- if (drawablep && assertInitialized())
- {
- if (is_light)
- {
- mLights.insert(drawablep);
- drawablep->setState(LLDrawable::LIGHT);
- }
- else
- {
- drawablep->clearState(LLDrawable::LIGHT);
- mLights.erase(drawablep);
- }
- }
-}
-
-//static
-void LLPipeline::toggleRenderType(U32 type)
-{
- gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type];
- if (type == LLPipeline::RENDER_TYPE_WATER)
- {
- gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER];
- }
-}
-
-//static
-void LLPipeline::toggleRenderTypeControl(void* data)
-{
- U32 type = (U32)(intptr_t)data;
- U32 bit = (1<<type);
- if (gPipeline.hasRenderType(type))
- {
- llinfos << "Toggling render type mask " << std::hex << bit << " off" << std::dec << llendl;
- }
- else
- {
- llinfos << "Toggling render type mask " << std::hex << bit << " on" << std::dec << llendl;
- }
- gPipeline.toggleRenderType(type);
-}
-
-//static
-BOOL LLPipeline::hasRenderTypeControl(void* data)
-{
- U32 type = (U32)(intptr_t)data;
- return gPipeline.hasRenderType(type);
-}
-
-// Allows UI items labeled "Hide foo" instead of "Show foo"
-//static
-BOOL LLPipeline::toggleRenderTypeControlNegated(void* data)
-{
- S32 type = (S32)(intptr_t)data;
- return !gPipeline.hasRenderType(type);
-}
-
-//static
-void LLPipeline::toggleRenderDebug(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- if (gPipeline.hasRenderDebugMask(bit))
- {
- llinfos << "Toggling render debug mask " << std::hex << bit << " off" << std::dec << llendl;
- }
- else
- {
- llinfos << "Toggling render debug mask " << std::hex << bit << " on" << std::dec << llendl;
- }
- gPipeline.mRenderDebugMask ^= bit;
-}
-
-
-//static
-BOOL LLPipeline::toggleRenderDebugControl(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- return gPipeline.hasRenderDebugMask(bit);
-}
-
-//static
-void LLPipeline::toggleRenderDebugFeature(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- gPipeline.mRenderDebugFeatureMask ^= bit;
-}
-
-
-//static
-BOOL LLPipeline::toggleRenderDebugFeatureControl(void* data)
-{
- U32 bit = (U32)(intptr_t)data;
- return gPipeline.hasRenderDebugFeatureMask(bit);
-}
-
-// static
-void LLPipeline::setRenderScriptedBeacons(BOOL val)
-{
- sRenderScriptedBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderScriptedBeacons(void*)
-{
- sRenderScriptedBeacons = !sRenderScriptedBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderScriptedBeacons(void*)
-{
- return sRenderScriptedBeacons;
-}
-
-// static
-void LLPipeline::setRenderScriptedTouchBeacons(BOOL val)
-{
- sRenderScriptedTouchBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderScriptedTouchBeacons(void*)
-{
- sRenderScriptedTouchBeacons = !sRenderScriptedTouchBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderScriptedTouchBeacons(void*)
-{
- return sRenderScriptedTouchBeacons;
-}
-
-// static
-void LLPipeline::setRenderPhysicalBeacons(BOOL val)
-{
- sRenderPhysicalBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderPhysicalBeacons(void*)
-{
- sRenderPhysicalBeacons = !sRenderPhysicalBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderPhysicalBeacons(void*)
-{
- return sRenderPhysicalBeacons;
-}
-
-// static
-void LLPipeline::setRenderParticleBeacons(BOOL val)
-{
- sRenderParticleBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderParticleBeacons(void*)
-{
- sRenderParticleBeacons = !sRenderParticleBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderParticleBeacons(void*)
-{
- return sRenderParticleBeacons;
-}
-
-// static
-void LLPipeline::setRenderSoundBeacons(BOOL val)
-{
- sRenderSoundBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderSoundBeacons(void*)
-{
- sRenderSoundBeacons = !sRenderSoundBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderSoundBeacons(void*)
-{
- return sRenderSoundBeacons;
-}
-
-// static
-void LLPipeline::setRenderBeacons(BOOL val)
-{
- sRenderBeacons = val;
-}
-
-// static
-void LLPipeline::toggleRenderBeacons(void*)
-{
- sRenderBeacons = !sRenderBeacons;
-}
-
-// static
-BOOL LLPipeline::getRenderBeacons(void*)
-{
- return sRenderBeacons;
-}
-
-// static
-void LLPipeline::setRenderHighlights(BOOL val)
-{
- sRenderHighlight = val;
-}
-
-// static
-void LLPipeline::toggleRenderHighlights(void*)
-{
- sRenderHighlight = !sRenderHighlight;
-}
-
-// static
-BOOL LLPipeline::getRenderHighlights(void*)
-{
- return sRenderHighlight;
-}
-
-LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end,
- BOOL pick_transparent,
- S32* face_hit,
- LLVector3* intersection, // return the intersection point
- LLVector2* tex_coord, // return the texture coordinates of the intersection point
- LLVector3* normal, // return the surface normal at the intersection point
- LLVector3* bi_normal // return the surface bi-normal at the intersection point
- )
-{
- LLDrawable* drawable = NULL;
-
- LLVector3 local_end = end;
-
- LLVector3 position;
-
- sPickAvatar = FALSE; //LLToolMgr::getInstance()->inBuildMode() ? FALSE : TRUE;
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
- {
- if ((j == LLViewerRegion::PARTITION_VOLUME) ||
- (j == LLViewerRegion::PARTITION_BRIDGE) ||
- (j == LLViewerRegion::PARTITION_TERRAIN) ||
- (j == LLViewerRegion::PARTITION_TREE) ||
- (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now
- {
- LLSpatialPartition* part = region->getSpatialPartition(j);
- if (part && hasRenderType(part->mDrawableType))
- {
- LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
- if (hit)
- {
- drawable = hit;
- local_end = position;
- }
- }
- }
- }
- }
-
- if (!sPickAvatar)
- {
- //save hit info in case we need to restore
- //due to attachment override
- LLVector3 local_normal;
- LLVector3 local_binormal;
- LLVector2 local_texcoord;
- S32 local_face_hit = -1;
-
- if (face_hit)
- {
- local_face_hit = *face_hit;
- }
- if (tex_coord)
- {
- local_texcoord = *tex_coord;
- }
- if (bi_normal)
- {
- local_binormal = *bi_normal;
- }
- if (normal)
- {
- local_normal = *normal;
- }
-
- const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f;
-
- //check against avatars
- sPickAvatar = TRUE;
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE);
- if (part && hasRenderType(part->mDrawableType))
- {
- LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
- if (hit)
- {
- if (!drawable ||
- !drawable->getVObj()->isAttachment() ||
- (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST)
- { //avatar overrides if previously hit drawable is not an attachment or
- //attachment is far enough away from detected intersection
- drawable = hit;
- local_end = position;
- }
- else
- { //prioritize attachments over avatars
- position = local_end;
-
- if (face_hit)
- {
- *face_hit = local_face_hit;
- }
- if (tex_coord)
- {
- *tex_coord = local_texcoord;
- }
- if (bi_normal)
- {
- *bi_normal = local_binormal;
- }
- if (normal)
- {
- *normal = local_normal;
- }
- }
- }
- }
- }
- }
-
- //check all avatar nametags (silly, isn't it?)
- for (std::vector< LLCharacter* >::iterator iter = LLCharacter::sInstances.begin();
- iter != LLCharacter::sInstances.end();
- ++iter)
- {
- LLVOAvatar* av = (LLVOAvatar*) *iter;
- if (av->mNameText.notNull()
- && av->mNameText->lineSegmentIntersect(start, local_end, position))
- {
- drawable = av->mDrawable;
- local_end = position;
- }
- }
-
- if (intersection)
- {
- *intersection = position;
- }
-
- return drawable ? drawable->getVObj().get() : NULL;
-}
-
-LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end,
- BOOL pick_transparent,
- S32* face_hit,
- LLVector3* intersection, // return the intersection point
- LLVector2* tex_coord, // return the texture coordinates of the intersection point
- LLVector3* normal, // return the surface normal at the intersection point
- LLVector3* bi_normal // return the surface bi-normal at the intersection point
- )
-{
- LLDrawable* drawable = NULL;
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
-
- BOOL toggle = FALSE;
- if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- toggle = TRUE;
- }
-
- LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD);
- if (part)
- {
- LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
- if (hit)
- {
- drawable = hit;
- }
- }
-
- if (toggle)
- {
- toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- }
- }
- return drawable ? drawable->getVObj().get() : NULL;
-}
-
-LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj)
-{
- if (vobj)
- {
- LLViewerRegion* region = vobj->getRegion();
- if (region)
- {
- return region->getSpatialPartition(vobj->getPartitionType());
- }
- }
- return NULL;
-}
-
-
-void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
-{
- if (!drawable || drawable->isDead())
- {
- return;
- }
-
- for (S32 i = 0; i < drawable->getNumFaces(); i++)
- {
- LLFace* facep = drawable->getFace(i);
- facep->mVertexBuffer = NULL;
- facep->mLastVertexBuffer = NULL;
- }
-}
-
-void LLPipeline::resetVertexBuffers()
-{
- sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
- sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
- LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
-
- for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
- iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
- {
- LLViewerRegion* region = *iter;
- for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
- {
- LLSpatialPartition* part = region->getSpatialPartition(i);
- if (part)
- {
- part->resetVertexBuffers();
- }
- }
- }
-
- resetDrawOrders();
-
- gSky.resetVertexBuffers();
-
- if (LLVertexBuffer::sGLCount > 0)
- {
- LLVertexBuffer::cleanupClass();
- }
-
- //delete all name pool caches
- LLGLNamePool::cleanupPools();
-
- if (LLVertexBuffer::sGLCount > 0)
- {
- llwarns << "VBO wipe failed." << llendl;
- }
-
- if (!LLVertexBuffer::sStreamIBOPool.mNameList.empty() ||
- !LLVertexBuffer::sStreamVBOPool.mNameList.empty() ||
- !LLVertexBuffer::sDynamicIBOPool.mNameList.empty() ||
- !LLVertexBuffer::sDynamicVBOPool.mNameList.empty())
- {
- llwarns << "VBO name pool cleanup failed." << llendl;
- }
-
- LLVertexBuffer::unbind();
-
- LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind");
-}
-
-void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture)
-{
- LLMemType mt_ro(LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS);
- assertInitialized();
- glLoadMatrixd(gGLModelView);
- gGLLastMatrix = NULL;
- mSimplePool->pushBatches(type, mask);
- glLoadMatrixd(gGLModelView);
- gGLLastMatrix = NULL;
-}
-
-void LLPipeline::setUseVBO(BOOL use_vbo)
-{
- if (use_vbo != LLVertexBuffer::sEnableVBOs)
- {
- if (use_vbo)
- {
- llinfos << "Enabling VBO." << llendl;
- }
- else
- {
- llinfos << "Disabling VBO." << llendl;
- }
-
- resetVertexBuffers();
- LLVertexBuffer::initClass(use_vbo, gSavedSettings.getBOOL("RenderVBOMappingDisable"));
- }
-}
-
-void LLPipeline::setDisableVBOMapping(BOOL no_vbo_mapping)
-{
- if (LLVertexBuffer::sEnableVBOs && no_vbo_mapping != LLVertexBuffer::sDisableVBOMapping)
- {
- if (no_vbo_mapping)
- {
- llinfos << "Disabling VBO glMapBufferARB." << llendl;
- }
- else
- {
- llinfos << "Enabling VBO glMapBufferARB." << llendl;
- }
-
- resetVertexBuffers();
- LLVertexBuffer::initClass(true, no_vbo_mapping);
- }
-}
-
-void apply_cube_face_rotation(U32 face)
-{
- switch (face)
- {
- case 0:
- glRotatef(90.f, 0, 1, 0);
- glRotatef(180.f, 1, 0, 0);
- break;
- case 2:
- glRotatef(-90.f, 1, 0, 0);
- break;
- case 4:
- glRotatef(180.f, 0, 1, 0);
- glRotatef(180.f, 0, 0, 1);
- break;
- case 1:
- glRotatef(-90.f, 0, 1, 0);
- glRotatef(180.f, 1, 0, 0);
- break;
- case 3:
- glRotatef(90, 1, 0, 0);
- break;
- case 5:
- glRotatef(180, 0, 0, 1);
- break;
- }
-}
-
-void validate_framebuffer_object()
-{
- GLenum status;
- status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
- switch(status)
- {
- case GL_FRAMEBUFFER_COMPLETE_EXT:
- //framebuffer OK, no error.
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
- // frame buffer not OK: probably means unsupported depth buffer format
- llerrs << "Framebuffer Incomplete Dimensions." << llendl;
- break;
- case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
- // frame buffer not OK: probably means unsupported depth buffer format
- llerrs << "Framebuffer Incomplete Attachment." << llendl;
- break;
- case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
- /* choose different formats */
- llerrs << "Framebuffer unsupported." << llendl;
- break;
- default:
- llerrs << "Unknown framebuffer status." << llendl;
- break;
- }
-}
-
-void LLPipeline::bindScreenToTexture()
-{
-
-}
-
-static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom");
-
-void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
-{
- LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM);
- if (!(gPipeline.canUseVertexShaders() &&
- sRenderGlow))
- {
- return;
- }
-
- LLVertexBuffer::unbind();
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
- assertInitialized();
-
- if (gUseWireframe)
- {
- glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
- }
-
- U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
-
- LLVector2 tc1(0,0);
- LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2,
- (F32) gViewerWindow->getWorldViewHeightRaw()*2);
-
- if (res_mod > 1)
- {
- tc2 /= (F32) res_mod;
- }
-
- gGL.setColorMask(true, true);
-
- LLFastTimer ftm(FTM_RENDER_BLOOM);
- gGL.color4f(1,1,1,1);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable blend(GL_BLEND);
- LLGLDisable cull(GL_CULL_FACE);
-
- enableLightsFullbright(LLColor4(1,1,1,1));
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
-
- LLGLDisable test(GL_ALPHA_TEST);
-
- gGL.setColorMask(true, true);
- glClearColor(0,0,0,0);
-
- /*if (for_snapshot)
- {
- gGL.getTexUnit(0)->bind(&mGlow[1]);
- {
- //LLGLEnable stencil(GL_STENCIL_TEST);
- //glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF);
- //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- //LLGLDisable blend(GL_BLEND);
-
- // If the snapshot is constructed from tiles, calculate which
- // tile we're in.
-
- //from LLViewerCamera::setPerpsective
- if (zoom_factor > 1.f)
- {
- int pos_y = subfield / llceil(zoom_factor);
- int pos_x = subfield - (pos_y*llceil(zoom_factor));
- F32 size = 1.f/zoom_factor;
-
- tc1.set(pos_x*size, pos_y*size);
- tc2 = tc1 + LLVector2(size,size);
- }
- else
- {
- tc2.set(1,1);
- }
-
- LLGLEnable blend(GL_BLEND);
- gGL.setSceneBlendType(LLRender::BT_ADD);
-
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.color4f(1,1,1,1);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,1);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(1,-1);
-
- gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
- gGL.vertex2f(1,1);
-
- gGL.end();
-
- gGL.flush();
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
-
- gGL.flush();
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- return;
- }*/
-
- {
- {
- LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
- mGlow[2].bindTarget();
- mGlow[2].clear();
- }
-
- gGlowExtractProgram.bind();
- F32 minLum = llmax(gSavedSettings.getF32("RenderGlowMinLuminance"), 0.0f);
- F32 maxAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha");
- F32 warmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount");
- LLVector3 lumWeights = gSavedSettings.getVector3("RenderGlowLumWeights");
- LLVector3 warmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights");
- gGlowExtractProgram.uniform1f("minLuminance", minLum);
- gGlowExtractProgram.uniform1f("maxExtractAlpha", maxAlpha);
- gGlowExtractProgram.uniform3f("lumWeights", lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]);
- gGlowExtractProgram.uniform3f("warmthWeights", warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]);
- gGlowExtractProgram.uniform1f("warmthAmount", warmthAmount);
- LLGLEnable blend_on(GL_BLEND);
- LLGLEnable test(GL_ALPHA_TEST);
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
- gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.getTexUnit(0)->disable();
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
- gGL.getTexUnit(0)->bind(&mScreen);
-
- gGL.color4f(1,1,1,1);
- gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
-
- mGlow[2].flush();
- }
-
- tc1.setVec(0,0);
- tc2.setVec(2,2);
-
- // power of two between 1 and 1024
- U32 glowResPow = gSavedSettings.getS32("RenderGlowResolutionPow");
- const U32 glow_res = llmax(1,
- llmin(1024, 1 << glowResPow));
-
- S32 kernel = gSavedSettings.getS32("RenderGlowIterations")*2;
- F32 delta = gSavedSettings.getF32("RenderGlowWidth") / glow_res;
- // Use half the glow width if we have the res set to less than 9 so that it looks
- // almost the same in either case.
- if (glowResPow < 9)
- {
- delta *= 0.5f;
- }
- F32 strength = gSavedSettings.getF32("RenderGlowStrength");
-
- gGlowProgram.bind();
- gGlowProgram.uniform1f("glowStrength", strength);
-
- for (S32 i = 0; i < kernel; i++)
- {
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- {
- LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
- mGlow[i%2].bindTarget();
- mGlow[i%2].clear();
- }
-
- if (i == 0)
- {
- gGL.getTexUnit(0)->bind(&mGlow[2]);
- }
- else
- {
- gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]);
- }
-
- if (i%2 == 0)
- {
- gGlowProgram.uniform2f("glowDelta", delta, 0);
- }
- else
- {
- gGlowProgram.uniform2f("glowDelta", 0, delta);
- }
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- mGlow[i%2].flush();
- }
-
- gGlowProgram.unbind();
-
- if (LLRenderTarget::sUseFBO)
- {
- LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
- glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
- }
-
- gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
- gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
- gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
- gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
- glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
-
- tc2.setVec((F32) gViewerWindow->getWorldViewWidthRaw(),
- (F32) gViewerWindow->getWorldViewHeightRaw());
-
- gGL.flush();
-
- LLVertexBuffer::unbind();
-
- if (LLPipeline::sRenderDeferred && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
- {
- LLGLDisable blend(GL_BLEND);
- bindDeferredShader(gDeferredGIFinalProgram);
-
- S32 channel = gDeferredGIFinalProgram.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mScreen.bindTexture(0, channel);
- }
-
- gGL.begin(LLRender::TRIANGLE_STRIP);
- gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
- gGL.vertex2f(-1,-1);
-
- gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
- gGL.vertex2f(-1,3);
-
- gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
- gGL.vertex2f(3,-1);
-
- gGL.end();
-
- unbindDeferredShader(gDeferredGIFinalProgram);
- }
- else
- {
-
- if (res_mod > 1)
- {
- tc2 /= (F32) res_mod;
- }
-
- U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
- LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0);
- buff->allocateBuffer(3,0,TRUE);
-
- LLStrider<LLVector3> v;
- LLStrider<LLVector2> uv1;
- LLStrider<LLVector2> uv2;
-
- buff->getVertexStrider(v);
- buff->getTexCoord0Strider(uv1);
- buff->getTexCoord1Strider(uv2);
-
- uv1[0] = LLVector2(0, 0);
- uv1[1] = LLVector2(0, 2);
- uv1[2] = LLVector2(2, 0);
-
- uv2[0] = LLVector2(0, 0);
- uv2[1] = LLVector2(0, tc2.mV[1]*2.f);
- uv2[2] = LLVector2(tc2.mV[0]*2.f, 0);
-
- v[0] = LLVector3(-1,-1,0);
- v[1] = LLVector3(-1,3,0);
- v[2] = LLVector3(3,-1,0);
-
- buff->setBuffer(0);
-
- LLGLDisable blend(GL_BLEND);
-
- //tex unit 0
- gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
-
- gGL.getTexUnit(0)->bind(&mGlow[1]);
- gGL.getTexUnit(1)->activate();
- gGL.getTexUnit(1)->enable(LLTexUnit::TT_RECT_TEXTURE);
-
-
- //tex unit 1
- gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
-
- gGL.getTexUnit(1)->bind(&mScreen);
- gGL.getTexUnit(1)->activate();
-
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
-
- buff->setBuffer(mask);
- buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
-
- gGL.getTexUnit(1)->disable();
- gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- gGL.getTexUnit(0)->activate();
- gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
-
- if (LLRenderTarget::sUseFBO)
- { //copy depth buffer from mScreen to framebuffer
- LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(),
- 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- }
- }
-
-
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
-
-}
-
-static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred");
-
-void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRenderTarget* gi_source, LLRenderTarget* last_gi_post, U32 noise_map)
-{
- LLFastTimer t(FTM_BIND_DEFERRED);
-
- if (noise_map == 0xFFFFFFFF)
- {
- noise_map = mNoiseMap;
- }
-
- LLGLState::checkTextureChannels();
-
- shader.bind();
- S32 channel = 0;
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(0,channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(1, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(2, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- if (gi_source)
- {
- BOOL has_gi = FALSE;
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE);
- if (channel > -1)
- {
- has_gi = TRUE;
- gi_source->bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR);
- if (channel > -1)
- {
- has_gi = TRUE;
- gi_source->bindTexture(1, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL);
- if (channel > -1)
- {
- has_gi = TRUE;
- gi_source->bindTexture(2, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS);
- if (channel > -1)
- {
- has_gi = TRUE;
- gi_source->bindTexture(1, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS);
- if (channel > -1)
- {
- has_gi = TRUE;
- gi_source->bindTexture(3, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE);
- if (channel > -1)
- {
- has_gi = TRUE;
- last_gi_post->bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL);
- if (channel > -1)
- {
- has_gi = TRUE;
- last_gi_post->bindTexture(2, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS);
- if (channel > -1)
- {
- has_gi = TRUE;
- last_gi_post->bindTexture(1, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS);
- if (channel > -1)
- {
- has_gi = TRUE;
- last_gi_post->bindTexture(3, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH);
- if (channel > -1)
- {
- has_gi = TRUE;
- gGL.getTexUnit(channel)->bind(gi_source, TRUE);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- stop_glerror();
-
- glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
-
- stop_glerror();
- }
-
- if (has_gi)
- {
- F32 range_x = llmin(mGIRange.mV[0], 1.f);
- F32 range_y = llmin(mGIRange.mV[1], 1.f);
-
- LLVector2 scale(range_x,range_y);
-
- LLVector2 kern[25];
-
- for (S32 i = 0; i < 5; ++i)
- {
- for (S32 j = 0; j < 5; ++j)
- {
- S32 idx = i*5+j;
- kern[idx].mV[0] = (i-2)*0.5f;
- kern[idx].mV[1] = (j-2)*0.5f;
- kern[idx].scaleVec(scale);
- }
- }
-
- shader.uniform2fv("gi_kern", 25, (F32*) kern);
- shader.uniformMatrix4fv("gi_mat", 1, FALSE, mGIMatrix.m);
- shader.uniformMatrix4fv("gi_mat_proj", 1, FALSE, mGIMatrixProj.m);
- shader.uniformMatrix4fv("gi_inv_proj", 1, FALSE, mGIInvProj.m);
- shader.uniformMatrix4fv("gi_norm_mat", 1, FALSE, mGINormalMatrix.m);
- }
- }
-
- /*channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredScreen.bindTexture(3, channel);
- }*/
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- stop_glerror();
-
- glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
-
- stop_glerror();
-
- glh::matrix4f projection = glh_get_current_projection();
- glh::matrix4f inv_proj = projection.inverse();
-
- shader.uniformMatrix4fv("inv_proj", 1, FALSE, inv_proj.m);
- shader.uniform4f("viewport", (F32) gGLViewport[0],
- (F32) gGLViewport[1],
- (F32) gGLViewport[2],
- (F32) gGLViewport[3]);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
- }
-
- stop_glerror();
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredLight[light_index].bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE);
- if (channel > -1)
- {
- gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_BLOOM);
- if (channel > -1)
- {
- mGlow[1].bindTexture(0, channel);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- gi_source->bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mEdgeMap.bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredLight[1].bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- if (channel > -1)
- {
- mDeferredLight[2].bindTexture(0, channel);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- }
-
-
- stop_glerror();
-
- for (U32 i = 0; i < 4; i++)
- {
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE);
- stop_glerror();
- if (channel > -1)
- {
- stop_glerror();
- gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- stop_glerror();
-
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- stop_glerror();
- }
- }
-
- for (U32 i = 4; i < 6; i++)
- {
- channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i);
- stop_glerror();
- if (channel > -1)
- {
- stop_glerror();
- gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
- gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
- gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
- stop_glerror();
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
- stop_glerror();
- }
- }
-
- stop_glerror();
-
- F32 mat[16*6];
- for (U32 i = 0; i < 16; i++)
- {
- mat[i] = mSunShadowMatrix[0].m[i];
- mat[i+16] = mSunShadowMatrix[1].m[i];
- mat[i+32] = mSunShadowMatrix[2].m[i];
- mat[i+48] = mSunShadowMatrix[3].m[i];
- mat[i+64] = mSunShadowMatrix[4].m[i];
- mat[i+80] = mSunShadowMatrix[5].m[i];
- }
-
- shader.uniformMatrix4fv("shadow_matrix[0]", 6, FALSE, mat);
- shader.uniformMatrix4fv("shadow_matrix", 6, FALSE, mat);
-
- stop_glerror();
-
- channel = shader.enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
- if (channel > -1)
- {
- LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
- if (cube_map)
- {
- cube_map->enable(channel);
- cube_map->bind();
- F64* m = gGLModelView;
-
-
- F32 mat[] = { m[0], m[1], m[2],
- m[4], m[5], m[6],
- m[8], m[9], m[10] };
-
- shader.uniform3fv("env_mat[0]", 3, mat);
- shader.uniform3fv("env_mat", 3, mat);
- }
- }
-
- shader.uniform4fv("shadow_clip", 1, mSunClipPlanes.mV);
- shader.uniform1f("sun_wash", gSavedSettings.getF32("RenderDeferredSunWash"));
- shader.uniform1f("shadow_noise", gSavedSettings.getF32("RenderShadowNoise"));
- shader.uniform1f("blur_size", gSavedSettings.getF32("RenderShadowBlurSize"));
-
- shader.uniform1f("ssao_radius", gSavedSettings.getF32("RenderSSAOScale"));
- shader.uniform1f("ssao_max_radius", gSavedSettings.getU32("RenderSSAOMaxScale"));
-
- F32 ssao_factor = gSavedSettings.getF32("RenderSSAOFactor");
- shader.uniform1f("ssao_factor", ssao_factor);
- shader.uniform1f("ssao_factor_inv", 1.0/ssao_factor);
-
- LLVector3 ssao_effect = gSavedSettings.getVector3("RenderSSAOEffect");
- F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0;
- F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0;
- // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by
- // value factor, and scales remainder by saturation factor
- F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag,
- matrix_nondiag, matrix_diag, matrix_nondiag,
- matrix_nondiag, matrix_nondiag, matrix_diag};
- shader.uniformMatrix3fv("ssao_effect_mat", 1, GL_FALSE, ssao_effect_mat);
-
- F32 shadow_offset_error = 1.f + gSavedSettings.getF32("RenderShadowOffsetError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
- F32 shadow_bias_error = 1.f + gSavedSettings.getF32("RenderShadowBiasError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
-
- shader.uniform2f("screen_res", mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
- shader.uniform1f("near_clip", LLViewerCamera::getInstance()->getNear()*2.f);
- shader.uniform1f ("shadow_offset", gSavedSettings.getF32("RenderShadowOffset")*shadow_offset_error);
- shader.uniform1f("shadow_bias", gSavedSettings.getF32("RenderShadowBias")*shadow_bias_error);
- shader.uniform1f ("spot_shadow_offset", gSavedSettings.getF32("RenderSpotShadowOffset"));
- shader.uniform1f("spot_shadow_bias", gSavedSettings.getF32("RenderSpotShadowBias"));
-
- shader.uniform1f("lum_scale", gSavedSettings.getF32("RenderLuminanceScale"));
- shader.uniform1f("sun_lum_scale", gSavedSettings.getF32("RenderSunLuminanceScale"));
- shader.uniform1f("sun_lum_offset", gSavedSettings.getF32("RenderSunLuminanceOffset"));
- shader.uniform1f("lum_lod", gSavedSettings.getF32("RenderLuminanceDetail"));
- shader.uniform1f("gi_range", gSavedSettings.getF32("RenderGIRange"));
- shader.uniform1f("gi_brightness", gSavedSettings.getF32("RenderGIBrightness"));
- shader.uniform1f("gi_luminance", gSavedSettings.getF32("RenderGILuminance"));
- shader.uniform1f("gi_edge_weight", gSavedSettings.getF32("RenderGIBlurEdgeWeight"));
- shader.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness"));
- shader.uniform1f("gi_sample_width", mGILightRadius);
- shader.uniform1f("gi_noise", gSavedSettings.getF32("RenderGINoise"));
- shader.uniform1f("gi_attenuation", gSavedSettings.getF32("RenderGIAttenuation"));
- shader.uniform1f("gi_ambiance", gSavedSettings.getF32("RenderGIAmbiance"));
- shader.uniform2f("shadow_res", mShadow[0].getWidth(), mShadow[0].getHeight());
- shader.uniform2f("proj_shadow_res", mShadow[4].getWidth(), mShadow[4].getHeight());
- shader.uniform1f("depth_cutoff", gSavedSettings.getF32("RenderEdgeDepthCutoff"));
- shader.uniform1f("norm_cutoff", gSavedSettings.getF32("RenderEdgeNormCutoff"));
-
- if (shader.getUniformLocation("norm_mat") >= 0)
- {
- glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose();
- shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m);
- }
-}
-
-static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace");
-static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather");
-static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map");
-static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften");
-static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges");
-static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights");
-static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics");
-static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights");
-static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors");
-static LLFastTimer::DeclareTimer FTM_POST("Post");
-
-
-void LLPipeline::renderDeferredLighting()
-{
- if (!sCull)
- {
- return;
- }
-
- {
- LLFastTimer ftm(FTM_RENDER_DEFERRED);
-
- LLViewerCamera* camera = LLViewerCamera::getInstance();
- {
- LLGLDepthTest depth(GL_TRUE);
- mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
- 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
- }
-
- LLGLEnable multisample(GL_MULTISAMPLE_ARB);
-
- if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
- {
- gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
- }
-
- //ati doesn't seem to love actually using the stencil buffer on FBO's
- LLGLEnable stencil(GL_STENCIL_TEST);
- glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
-
- gGL.setColorMask(true, true);
-
- //draw a cube around every light
- LLVertexBuffer::unbind();
-
- LLGLEnable cull(GL_CULL_FACE);
- LLGLEnable blend(GL_BLEND);
-
- glh::matrix4f mat = glh_copy_matrix(gGLModelView);
-
- F32 vert[] =
- {
- -1,1,
- -1,-3,
- 3,1,
- };
- glVertexPointer(2, GL_FLOAT, 0, vert);
- glColor3f(1,1,1);
-
- {
- setupHWLights(NULL); //to set mSunDir;
- LLVector4 dir(mSunDir, 0.f);
- glh::vec4f tc(dir.mV);
- mat.mult_matrix_vec(tc);
- glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0);
- }
-
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- mDeferredLight[0].bindTarget();
-
- if (gSavedSettings.getBOOL("RenderDeferredSSAO") || gSavedSettings.getS32("RenderShadowDetail") > 0)
- {
- { //paint shadow/SSAO light map (direct lighting lightmap)
- LLFastTimer ftm(FTM_SUN_SHADOW);
- bindDeferredShader(gDeferredSunProgram, 0);
-
- glClearColor(1,1,1,1);
- mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0,0,0,0);
-
- glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
-
- const U32 slice = 32;
- F32 offset[slice*3];
- for (U32 i = 0; i < 4; i++)
- {
- for (U32 j = 0; j < 8; j++)
- {
- glh::vec3f v;
- v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
- v.normalize();
- inv_trans.mult_matrix_vec(v);
- v.normalize();
- offset[(i*8+j)*3+0] = v.v[0];
- offset[(i*8+j)*3+1] = v.v[2];
- offset[(i*8+j)*3+2] = v.v[1];
- }
- }
-
- gDeferredSunProgram.uniform3fv("offset", slice, offset);
- gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- stop_glerror();
- }
-
- unbindDeferredShader(gDeferredSunProgram);
- }
- }
- else
- {
- glClearColor(1,1,1,1);
- mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0,0,0,0);
- }
-
- mDeferredLight[0].flush();
-
- { //global illumination specific block (still experimental)
- if (gSavedSettings.getBOOL("RenderDeferredBlurLight") &&
- gSavedSettings.getBOOL("RenderDeferredGI"))
- {
- LLFastTimer ftm(FTM_EDGE_DETECTION);
- //generate edge map
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable stencil(GL_STENCIL_TEST);
-
- {
- gDeferredEdgeProgram.bind();
- mEdgeMap.bindTarget();
- bindDeferredShader(gDeferredEdgeProgram);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- unbindDeferredShader(gDeferredEdgeProgram);
- mEdgeMap.flush();
- }
- }
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
- {
- { //get luminance map from previous frame's light map
- LLGLEnable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable stencil(GL_STENCIL_TEST);
-
- //static F32 fade = 1.f;
-
- {
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- gLuminanceGatherProgram.bind();
- gLuminanceGatherProgram.uniform2f("screen_res", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
- mLuminanceMap.bindTarget();
- bindDeferredShader(gLuminanceGatherProgram);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- unbindDeferredShader(gLuminanceGatherProgram);
- mLuminanceMap.flush();
- gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
- glGenerateMipmapEXT(GL_TEXTURE_2D);
- }
- }
-
- { //paint noisy GI map (bounce lighting lightmap)
- LLFastTimer ftm(FTM_GI_TRACE);
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable test(GL_ALPHA_TEST);
-
- mGIMapPost[0].bindTarget();
-
- bindDeferredShader(gDeferredGIProgram, 0, &mGIMap, 0, mTrueNoiseMap);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- unbindDeferredShader(gDeferredGIProgram);
- mGIMapPost[0].flush();
- }
-
- U32 pass_count = 0;
- if (gSavedSettings.getBOOL("RenderDeferredBlurLight"))
- {
- pass_count = llclamp(gSavedSettings.getU32("RenderGIBlurPasses"), (U32) 1, (U32) 128);
- }
-
- for (U32 i = 0; i < pass_count; ++i)
- { //gather/soften indirect lighting map
- LLFastTimer ftm(FTM_GI_GATHER);
- bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[0], NULL, mTrueNoiseMap);
- F32 blur_size = gSavedSettings.getF32("RenderGIBlurSize")/((F32) i * gSavedSettings.getF32("RenderGIBlurIncrement")+1.f);
- gDeferredPostGIProgram.uniform2f("delta", 1.f, 0.f);
- gDeferredPostGIProgram.uniform1f("kern_scale", blur_size);
- gDeferredPostGIProgram.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness"));
-
- mGIMapPost[1].bindTarget();
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_FALSE);
- stop_glerror();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- stop_glerror();
- }
-
- mGIMapPost[1].flush();
- unbindDeferredShader(gDeferredPostGIProgram);
- bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[1], NULL, mTrueNoiseMap);
- mGIMapPost[0].bindTarget();
-
- gDeferredPostGIProgram.uniform2f("delta", 0.f, 1.f);
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_FALSE);
- stop_glerror();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
- stop_glerror();
- }
- mGIMapPost[0].flush();
- unbindDeferredShader(gDeferredPostGIProgram);
- }
- }
- }
-
- if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
- { //soften direct lighting lightmap
- LLFastTimer ftm(FTM_SOFTEN_SHADOW);
- //blur lightmap
- mDeferredLight[1].bindTarget();
-
- glClearColor(1,1,1,1);
- mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT);
- glClearColor(0,0,0,0);
-
- bindDeferredShader(gDeferredBlurLightProgram);
-
- LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian");
- const U32 kern_length = 4;
- F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize");
- F32 dist_factor = gSavedSettings.getF32("RenderShadowBlurDistFactor");
-
- // sample symmetrically with the middle sample falling exactly on 0.0
- F32 x = 0.f;
-
- LLVector3 gauss[32]; // xweight, yweight, offset
-
- for (U32 i = 0; i < kern_length; i++)
- {
- gauss[i].mV[0] = llgaussian(x, go.mV[0]);
- gauss[i].mV[1] = llgaussian(x, go.mV[1]);
- gauss[i].mV[2] = x;
- x += 1.f;
- }
-
- gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
- gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor);
- gDeferredBlurLightProgram.uniform3fv("kern[0]", kern_length, gauss[0].mV);
- gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
- gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- stop_glerror();
- }
-
- mDeferredLight[1].flush();
- unbindDeferredShader(gDeferredBlurLightProgram);
-
- bindDeferredShader(gDeferredBlurLightProgram, 1);
- mDeferredLight[0].bindTarget();
-
- gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
-
- {
- LLGLDisable blend(GL_BLEND);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
- stop_glerror();
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- stop_glerror();
- }
- mDeferredLight[0].flush();
- unbindDeferredShader(gDeferredBlurLightProgram);
- }
-
- stop_glerror();
- glPopMatrix();
- stop_glerror();
- glMatrixMode(GL_MODELVIEW);
- stop_glerror();
- glPopMatrix();
- stop_glerror();
-
- //copy depth and stencil from deferred screen
- //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
- // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
- {
- mDeferredLight[1].bindTarget();
- // clear color buffer here (GI) - zeroing alpha (glow) is important or it will accumulate against sky
- glClearColor(0,0,0,0);
- mScreen.clear(GL_COLOR_BUFFER_BIT);
- }
- else
- {
- mScreen.bindTarget();
- // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky
- glClearColor(0,0,0,0);
- mScreen.clear(GL_COLOR_BUFFER_BIT);
- }
-
- if (gSavedSettings.getBOOL("RenderDeferredAtmospheric"))
- { //apply sunlight contribution
- LLFastTimer ftm(FTM_ATMOSPHERICS);
- bindDeferredShader(gDeferredSoftenProgram, 0, &mGIMapPost[0]);
- {
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
-
- //full screen blit
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- glVertexPointer(2, GL_FLOAT, 0, vert);
-
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
-
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
-
- unbindDeferredShader(gDeferredSoftenProgram);
- }
-
- { //render sky
- LLGLDisable blend(GL_BLEND);
- LLGLDisable stencil(GL_STENCIL_TEST);
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- gPipeline.pushRenderTypeMask();
-
- gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::RENDER_TYPE_WL_SKY,
- LLPipeline::END_RENDER_TYPES);
-
-
- renderGeomPostDeferred(*LLViewerCamera::getInstance());
- gPipeline.popRenderTypeMask();
- }
-
- BOOL render_local = gSavedSettings.getBOOL("RenderDeferredLocalLights");
- BOOL render_fullscreen = gSavedSettings.getBOOL("RenderDeferredFullscreenLights");
-
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
- {
- mDeferredLight[1].flush();
- mDeferredLight[2].bindTarget();
- mDeferredLight[2].clear(GL_COLOR_BUFFER_BIT);
- }
-
- if (render_local || render_fullscreen)
- {
- gGL.setSceneBlendType(LLRender::BT_ADD);
- std::list<LLVector4> fullscreen_lights;
- LLDrawable::drawable_list_t spot_lights;
- LLDrawable::drawable_list_t fullscreen_spot_lights;
-
- for (U32 i = 0; i < 2; i++)
- {
- mTargetShadowSpotLight[i] = NULL;
- }
-
- std::list<LLVector4> light_colors;
-
- F32 v[24];
- glVertexPointer(3, GL_FLOAT, 0, v);
- BOOL render_local = gSavedSettings.getBOOL("RenderDeferredLocalLights");
-
- {
- bindDeferredShader(gDeferredLightProgram);
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
- for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
- {
- LLDrawable* drawablep = *iter;
-
- LLVOVolume* volume = drawablep->getVOVolume();
- if (!volume)
- {
- continue;
- }
-
- if (volume->isAttachment())
- {
- if (!sRenderAttachedLights)
- {
- continue;
- }
- }
-
-
- LLVector3 center = drawablep->getPositionAgent();
- F32* c = center.mV;
- F32 s = volume->getLightRadius()*1.5f;
-
- LLColor3 col = volume->getLightColor();
- col *= volume->getLightIntensity();
-
- if (col.magVecSquared() < 0.001f)
- {
- continue;
- }
-
- if (s <= 0.001f)
- {
- continue;
- }
-
- if (camera->AABBInFrustumNoFarClip(center, LLVector3(s,s,s)) == 0)
- {
- continue;
- }
-
- sVisibleLightCount++;
-
- glh::vec3f tc(c);
- mat.mult_matrix_vec(tc);
-
- //vertex positions are encoded so the 3 bits of their vertex index
- //correspond to their axis facing, with bit position 3,2,1 matching
- //axis facing x,y,z, bit set meaning positive facing, bit clear
- //meaning negative facing
- v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000
- v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001
- v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010
- v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011
-
- v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
- v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
- v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
- v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
-
- if (camera->getOrigin().mV[0] > c[0] + s + 0.2f ||
- camera->getOrigin().mV[0] < c[0] - s - 0.2f ||
- camera->getOrigin().mV[1] > c[1] + s + 0.2f ||
- camera->getOrigin().mV[1] < c[1] - s - 0.2f ||
- camera->getOrigin().mV[2] > c[2] + s + 0.2f ||
- camera->getOrigin().mV[2] < c[2] - s - 0.2f)
- { //draw box if camera is outside box
- if (render_local)
- {
- if (volume->isLightSpotlight())
- {
- drawablep->getVOVolume()->updateSpotLightPriority();
- spot_lights.push_back(drawablep);
- continue;
- }
-
- LLFastTimer ftm(FTM_LOCAL_LIGHTS);
- glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
- glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_BYTE, get_box_fan_indices(camera, center));
- stop_glerror();
- }
- }
- else if (render_fullscreen)
- {
- if (volume->isLightSpotlight())
- {
- drawablep->getVOVolume()->updateSpotLightPriority();
- fullscreen_spot_lights.push_back(drawablep);
- continue;
- }
-
- fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
- light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
- }
- }
- unbindDeferredShader(gDeferredLightProgram);
- }
-
- if (!spot_lights.empty())
- {
- LLGLDepthTest depth(GL_TRUE, GL_FALSE);
- bindDeferredShader(gDeferredSpotLightProgram);
-
- gDeferredSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
-
- for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
- {
- LLFastTimer ftm(FTM_PROJECTORS);
- LLDrawable* drawablep = *iter;
-
- LLVOVolume* volume = drawablep->getVOVolume();
-
- LLVector3 center = drawablep->getPositionAgent();
- F32* c = center.mV;
- F32 s = volume->getLightRadius()*1.5f;
-
- sVisibleLightCount++;
-
- glh::vec3f tc(c);
- mat.mult_matrix_vec(tc);
-
- setupSpotLight(gDeferredSpotLightProgram, drawablep);
-
- LLColor3 col = volume->getLightColor();
- col *= volume->getLightIntensity();
-
- //vertex positions are encoded so the 3 bits of their vertex index
- //correspond to their axis facing, with bit position 3,2,1 matching
- //axis facing x,y,z, bit set meaning positive facing, bit clear
- //meaning negative facing
- v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000
- v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001
- v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010
- v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011
-
- v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
- v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
- v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
- v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
-
- glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
- glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
- glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
- GL_UNSIGNED_BYTE, get_box_fan_indices(camera, center));
- }
- gDeferredSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
- unbindDeferredShader(gDeferredSpotLightProgram);
- }
-
- {
- bindDeferredShader(gDeferredMultiLightProgram);
-
- LLGLDepthTest depth(GL_FALSE);
-
- //full screen blit
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- U32 count = 0;
-
- const U32 max_count = 8;
- LLVector4 light[max_count];
- LLVector4 col[max_count];
-
- glVertexPointer(2, GL_FLOAT, 0, vert);
-
- F32 far_z = 0.f;
-
- while (!fullscreen_lights.empty())
- {
- LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS);
- light[count] = fullscreen_lights.front();
- fullscreen_lights.pop_front();
- col[count] = light_colors.front();
- light_colors.pop_front();
-
- far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z);
-
- count++;
- if (count == max_count || fullscreen_lights.empty())
- {
- gDeferredMultiLightProgram.uniform1i("light_count", count);
- gDeferredMultiLightProgram.uniform4fv("light[0]", count, (GLfloat*) light);
- gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light);
- gDeferredMultiLightProgram.uniform4fv("light_col[0]", count, (GLfloat*) col);
- gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col);
- gDeferredMultiLightProgram.uniform1f("far_z", far_z);
- far_z = 0.f;
- count = 0;
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- }
- }
-
- unbindDeferredShader(gDeferredMultiLightProgram);
-
- bindDeferredShader(gDeferredMultiSpotLightProgram);
-
- gDeferredMultiSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
-
- for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
- {
- LLFastTimer ftm(FTM_PROJECTORS);
- LLDrawable* drawablep = *iter;
-
- LLVOVolume* volume = drawablep->getVOVolume();
-
- LLVector3 center = drawablep->getPositionAgent();
- F32* c = center.mV;
- F32 s = volume->getLightRadius()*1.5f;
-
- sVisibleLightCount++;
-
- glh::vec3f tc(c);
- mat.mult_matrix_vec(tc);
-
- setupSpotLight(gDeferredMultiSpotLightProgram, drawablep);
-
- LLColor3 col = volume->getLightColor();
- col *= volume->getLightIntensity();
-
- glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
- glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
- glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
- }
-
- gDeferredMultiSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
- unbindDeferredShader(gDeferredMultiSpotLightProgram);
-
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- }
- }
-
- gGL.setColorMask(true, true);
-
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
- {
- mDeferredLight[2].flush();
-
- mScreen.bindTarget();
- mScreen.clear(GL_COLOR_BUFFER_BIT);
-
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
-
- { //mix various light maps (local, sun, gi)
- LLFastTimer ftm(FTM_POST);
- LLGLDisable blend(GL_BLEND);
- LLGLDisable test(GL_ALPHA_TEST);
- LLGLDepthTest depth(GL_FALSE);
- LLGLDisable stencil(GL_STENCIL_TEST);
-
- bindDeferredShader(gDeferredPostProgram, 0, &mGIMapPost[0]);
-
- gDeferredPostProgram.bind();
-
- LLVertexBuffer::unbind();
-
- glVertexPointer(2, GL_FLOAT, 0, vert);
- glColor3f(1,1,1);
-
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadIdentity();
-
- glDrawArrays(GL_TRIANGLES, 0, 3);
-
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- unbindDeferredShader(gDeferredPostProgram);
- }
- }
- }
-
- { //render non-deferred geometry (alpha, fullbright, glow)
- LLGLDisable blend(GL_BLEND);
- LLGLDisable stencil(GL_STENCIL_TEST);
-
- pushRenderTypeMask();
- andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_GLOW,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_ALPHA,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_BUMP,
- LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
- LLPipeline::RENDER_TYPE_PASS_GLOW,
- LLPipeline::RENDER_TYPE_PASS_GRASS,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
- LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
- LLPipeline::RENDER_TYPE_AVATAR,
- END_RENDER_TYPES);
-
- renderGeomPostDeferred(*LLViewerCamera::getInstance());
- popRenderTypeMask();
- }
-
- {
- //render highlights, etc.
- renderHighlights();
- mHighlightFaces.clear();
-
- renderDebug();
-
- LLVertexBuffer::unbind();
-
- if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
- {
- // Render debugging beacons.
- gObjectList.renderObjectBeacons();
- LLHUDObject::renderAll();
- gObjectList.resetObjectBeacons();
- }
- }
-
- mScreen.flush();
-
-}
-
-void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
-{
- //construct frustum
- LLVOVolume* volume = drawablep->getVOVolume();
- LLVector3 params = volume->getSpotLightParams();
-
- F32 fov = params.mV[0];
- F32 focus = params.mV[1];
-
- LLVector3 pos = drawablep->getPositionAgent();
- LLQuaternion quat = volume->getRenderRotation();
- LLVector3 scale = volume->getScale();
-
- //get near clip plane
- LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
- at_axis *= quat;
-
- LLVector3 np = pos+at_axis;
- at_axis.normVec();
-
- //get origin that has given fov for plane np, at_axis, and given scale
- F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
-
- LLVector3 origin = np - at_axis*dist;
-
- //matrix from volume space to agent space
- LLMatrix4 light_mat(quat, LLVector4(origin,1.f));
-
- glh::matrix4f light_to_agent((F32*) light_mat.mMatrix);
- glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent;
-
- glh::matrix4f screen_to_light = light_to_screen.inverse();
-
- F32 s = volume->getLightRadius()*1.5f;
- F32 near_clip = dist;
- F32 width = scale.mV[VX];
- F32 height = scale.mV[VY];
- F32 far_clip = s+dist-scale.mV[VZ];
-
- F32 fovy = fov * RAD_TO_DEG;
- F32 aspect = width/height;
-
- glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- glh::vec3f p1(0, 0, -(near_clip+0.01f));
- glh::vec3f p2(0, 0, -(near_clip+1.f));
-
- glh::vec3f screen_origin(0, 0, 0);
-
- light_to_screen.mult_matrix_vec(p1);
- light_to_screen.mult_matrix_vec(p2);
- light_to_screen.mult_matrix_vec(screen_origin);
-
- glh::vec3f n = p2-p1;
- n.normalize();
-
- F32 proj_range = far_clip - near_clip;
- glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip);
- screen_to_light = trans * light_proj * screen_to_light;
- shader.uniformMatrix4fv("proj_mat", 1, FALSE, screen_to_light.m);
- shader.uniform1f("proj_near", near_clip);
- shader.uniform3fv("proj_p", 1, p1.v);
- shader.uniform3fv("proj_n", 1, n.v);
- shader.uniform3fv("proj_origin", 1, screen_origin.v);
- shader.uniform1f("proj_range", proj_range);
- shader.uniform1f("proj_ambiance", params.mV[2]);
- S32 s_idx = -1;
-
- for (U32 i = 0; i < 2; i++)
- {
- if (mShadowSpotLight[i] == drawablep)
- {
- s_idx = i;
- }
- }
-
- shader.uniform1i("proj_shadow_idx", s_idx);
-
- if (s_idx >= 0)
- {
- shader.uniform1f("shadow_fade", 1.f-mSpotLightFade[s_idx]);
- }
- else
- {
- shader.uniform1f("shadow_fade", 1.f);
- }
-
- {
- LLDrawable* potential = drawablep;
- //determine if this is a good light for casting shadows
- F32 m_pri = volume->getSpotLightPriority();
-
- for (U32 i = 0; i < 2; i++)
- {
- F32 pri = 0.f;
-
- if (mTargetShadowSpotLight[i].notNull())
- {
- pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority();
- }
-
- if (m_pri > pri)
- {
- LLDrawable* temp = mTargetShadowSpotLight[i];
- mTargetShadowSpotLight[i] = potential;
- potential = temp;
- m_pri = pri;
- }
- }
- }
-
- LLViewerTexture* img = volume->getLightTexture();
-
- S32 channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
-
- if (channel > -1 && img)
- {
- gGL.getTexUnit(channel)->bind(img);
-
- F32 lod_range = logf(img->getWidth())/logf(2.f);
-
- shader.uniform1f("proj_focus", focus);
- shader.uniform1f("proj_lod", lod_range);
- shader.uniform1f("proj_ambient_lod", llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f));
- }
-}
-
-void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
-{
- stop_glerror();
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE);
- shader.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIP);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_BLOOM);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS);
-
- for (U32 i = 0; i < 4; i++)
- {
- if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1)
- {
- glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- }
- }
-
- for (U32 i = 4; i < 6; i++)
- {
- if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i) > -1)
- {
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
- }
- }
-
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
- shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC);
-
- S32 channel = shader.disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
- if (channel > -1)
- {
- LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
- if (cube_map)
- {
- cube_map->disable();
- }
- }
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- gGL.getTexUnit(0)->activate();
- shader.unbind();
-
- LLGLState::checkTextureChannels();
-}
-
-inline float sgn(float a)
-{
- if (a > 0.0F) return (1.0F);
- if (a < 0.0F) return (-1.0F);
- return (0.0F);
-}
-
-void LLPipeline::generateWaterReflection(LLCamera& camera_in)
-{
- if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
- {
- BOOL skip_avatar_update = FALSE;
- if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
- {
- skip_avatar_update = TRUE;
- }
-
- if (!skip_avatar_update)
- {
- gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON);
- }
- LLVertexBuffer::unbind();
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- LLCamera camera = camera_in;
- camera.setFar(camera.getFar()*0.87654321f);
- LLPipeline::sReflectionRender = TRUE;
- S32 occlusion = LLPipeline::sUseOcclusion;
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
-
- LLPipeline::sUseOcclusion = llmin(occlusion, 1);
-
- gPipeline.pushRenderTypeMask();
-
- glh::matrix4f projection = glh_get_current_projection();
- glh::matrix4f mat;
-
- stop_glerror();
- LLPlane plane;
-
- F32 height = gAgent.getRegion()->getWaterHeight();
- F32 to_clip = fabsf(camera.getOrigin().mV[2]-height);
- F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by
-
- //plane params
- LLVector3 pnorm;
- F32 pd;
-
- S32 water_clip = 0;
- if (!LLViewerCamera::getInstance()->cameraUnderWater())
- { //camera is above water, clip plane points up
- pnorm.setVec(0,0,1);
- pd = -height;
- plane.setVec(pnorm, pd);
- water_clip = -1;
- }
- else
- { //camera is below water, clip plane points down
- pnorm = LLVector3(0,0,-1);
- pd = height;
- plane.setVec(pnorm, pd);
- water_clip = 1;
- }
-
- if (!LLViewerCamera::getInstance()->cameraUnderWater())
- { //generate planar reflection map
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- glClearColor(0,0,0,0);
- mWaterRef.bindTarget();
- gGL.setColorMask(true, true);
- mWaterRef.clear();
- gGL.setColorMask(true, false);
-
- mWaterRef.getViewport(gGLViewport);
-
- stop_glerror();
-
- glPushMatrix();
-
- mat.set_scale(glh::vec3f(1,1,-1));
- mat.set_translate(glh::vec3f(0,0,height*2.f));
-
- glh::matrix4f current = glh_get_current_modelview();
-
- mat = current * mat;
-
- glh_set_current_modelview(mat);
- glLoadMatrixf(mat.m);
-
- LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE);
-
- glh::matrix4f inv_mat = mat.inverse();
-
- glh::vec3f origin(0,0,0);
- inv_mat.mult_matrix_vec(origin);
-
- camera.setOrigin(origin.v);
-
- glCullFace(GL_FRONT);
-
- static LLCullResult ref_result;
-
- if (LLDrawPoolWater::sNeedsDistortionUpdate)
- {
- //initial sky pass (no user clip plane)
- { //mask out everything but the sky
- gPipeline.pushRenderTypeMask();
- gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_WL_SKY,
- LLPipeline::END_RENDER_TYPES);
- static LLCullResult result;
- updateCull(camera, result);
- stateSort(camera, result);
- andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::RENDER_TYPE_WL_SKY,
- LLPipeline::END_RENDER_TYPES);
-
- renderGeom(camera, TRUE);
- gPipeline.popRenderTypeMask();
- }
-
- gPipeline.pushRenderTypeMask();
-
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_GROUND,
- LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::END_RENDER_TYPES);
-
- S32 detail = gSavedSettings.getS32("RenderReflectionDetail");
- if (detail > 0)
- { //mask out selected geometry based on reflection detail
- if (detail < 4)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES);
- if (detail < 3)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
- if (detail < 2)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES);
- }
- }
- }
-
- LLGLUserClipPlane clip_plane(plane, mat, projection);
- LLGLDisable cull(GL_CULL_FACE);
- updateCull(camera, ref_result, 1);
- stateSort(camera, ref_result);
- }
-
- if (LLDrawPoolWater::sNeedsDistortionUpdate)
- {
- if (gSavedSettings.getS32("RenderReflectionDetail") > 0)
- {
- gPipeline.grabReferences(ref_result);
- LLGLUserClipPlane clip_plane(plane, mat, projection);
- renderGeom(camera);
- }
- }
-
- gPipeline.popRenderTypeMask();
- }
- glCullFace(GL_BACK);
- glPopMatrix();
- mWaterRef.flush();
- glh_set_current_modelview(current);
- }
-
- camera.setOrigin(camera_in.getOrigin());
- //render distortion map
- static BOOL last_update = TRUE;
- if (last_update)
- {
- camera.setFar(camera_in.getFar());
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_GROUND,
- END_RENDER_TYPES);
- stop_glerror();
-
- LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE;
-
- if (LLPipeline::sUnderWaterRender)
- {
- clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND,
- LLPipeline::RENDER_TYPE_SKY,
- LLPipeline::RENDER_TYPE_CLOUDS,
- LLPipeline::RENDER_TYPE_WL_SKY,
- END_RENDER_TYPES);
- }
- LLViewerCamera::updateFrustumPlanes(camera);
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- LLColor4& col = LLDrawPoolWater::sWaterFogColor;
- glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
- mWaterDis.bindTarget();
- mWaterDis.getViewport(gGLViewport);
-
- if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate)
- {
- //clip out geometry on the same side of water as the camera
- mat = glh_get_current_modelview();
- LLGLUserClipPlane clip_plane(LLPlane(-pnorm, -(pd+pad)), mat, projection);
- static LLCullResult result;
- updateCull(camera, result, water_clip);
- stateSort(camera, result);
-
- gGL.setColorMask(true, true);
- mWaterDis.clear();
- gGL.setColorMask(true, false);
-
- renderGeom(camera);
- }
-
- LLPipeline::sUnderWaterRender = FALSE;
- mWaterDis.flush();
- }
- last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate;
-
- LLRenderTarget::unbindTarget();
-
- LLPipeline::sReflectionRender = FALSE;
-
- if (!LLRenderTarget::sUseFBO)
- {
- glClear(GL_DEPTH_BUFFER_BIT);
- }
- glClearColor(0.f, 0.f, 0.f, 0.f);
- gViewerWindow->setup3DViewport();
- gPipeline.popRenderTypeMask();
- LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
- LLDrawPoolWater::sNeedsDistortionUpdate = FALSE;
- LLViewerCamera::getInstance()->setUserClipPlane(LLPlane(-pnorm, -pd));
- LLPipeline::sUseOcclusion = occlusion;
-
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- if (!skip_avatar_update)
- {
- gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
- }
- }
-}
-
-glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
-{
- glh::matrix4f ret;
-
- LLVector3 dirN;
- LLVector3 upN;
- LLVector3 lftN;
-
- lftN = dir % up;
- lftN.normVec();
-
- upN = lftN % dir;
- upN.normVec();
-
- dirN = dir;
- dirN.normVec();
-
- ret.m[ 0] = lftN[0];
- ret.m[ 1] = upN[0];
- ret.m[ 2] = -dirN[0];
- ret.m[ 3] = 0.f;
-
- ret.m[ 4] = lftN[1];
- ret.m[ 5] = upN[1];
- ret.m[ 6] = -dirN[1];
- ret.m[ 7] = 0.f;
-
- ret.m[ 8] = lftN[2];
- ret.m[ 9] = upN[2];
- ret.m[10] = -dirN[2];
- ret.m[11] = 0.f;
-
- ret.m[12] = -(lftN*pos);
- ret.m[13] = -(upN*pos);
- ret.m[14] = dirN*pos;
- ret.m[15] = 1.f;
-
- return ret;
-}
-
-glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max)
-{
- glh::matrix4f ret;
- ret.m[ 0] = 2/(max[0]-min[0]);
- ret.m[ 4] = 0;
- ret.m[ 8] = 0;
- ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]);
-
- ret.m[ 1] = 0;
- ret.m[ 5] = 2/(max[1]-min[1]);
- ret.m[ 9] = 0;
- ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]);
-
- ret.m[ 2] = 0;
- ret.m[ 6] = 0;
- ret.m[10] = 2/(max[2]-min[2]);
- ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]);
-
- ret.m[ 3] = 0;
- ret.m[ 7] = 0;
- ret.m[11] = 0;
- ret.m[15] = 1;
-
- return ret;
-}
-
-static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows");
-static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow");
-static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow");
-
-void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion)
-{
- LLFastTimer t(FTM_SHADOW_RENDER);
-
- //clip out geometry on the same side of water as the camera
- S32 occlude = LLPipeline::sUseOcclusion;
- if (!use_occlusion)
- {
- LLPipeline::sUseOcclusion = 0;
- }
- LLPipeline::sShadowRender = TRUE;
-
- U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP, LLRenderPass::PASS_FULLBRIGHT_SHINY };
- LLGLEnable cull(GL_CULL_FACE);
-
- if (use_shader)
- {
- gDeferredShadowProgram.bind();
- }
-
- updateCull(shadow_cam, result);
- stateSort(shadow_cam, result);
-
- //generate shadow map
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixf(proj.m);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadMatrixf(view.m);
-
- stop_glerror();
- gGLLastMatrix = NULL;
-
- {
- LLGLDepthTest depth(GL_TRUE);
- glClear(GL_DEPTH_BUFFER_BIT);
- }
-
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- glColor4f(1,1,1,1);
-
- stop_glerror();
-
- gGL.setColorMask(false, false);
-
- //glCullFace(GL_FRONT);
-
- {
- LLFastTimer ftm(FTM_SHADOW_SIMPLE);
- LLGLDisable test(GL_ALPHA_TEST);
- gGL.getTexUnit(0)->disable();
- for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
- {
- renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
- }
- gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
- }
-
- if (use_shader)
- {
- gDeferredShadowProgram.unbind();
- renderGeomShadow(shadow_cam);
- gDeferredShadowProgram.bind();
- }
- else
- {
- renderGeomShadow(shadow_cam);
- }
-
- {
- LLFastTimer ftm(FTM_SHADOW_ALPHA);
- LLGLEnable test(GL_ALPHA_TEST);
- gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f);
- renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE);
- glColor4f(1,1,1,1);
- renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
- gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
- }
-
- //glCullFace(GL_BACK);
-
- gGLLastMatrix = NULL;
- glLoadMatrixd(gGLModelView);
- doOcclusion(shadow_cam);
-
- if (use_shader)
- {
- gDeferredShadowProgram.unbind();
- }
-
- gGL.setColorMask(true, true);
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- gGLLastMatrix = NULL;
-
- LLPipeline::sUseOcclusion = occlude;
- LLPipeline::sShadowRender = FALSE;
-}
-
-static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud");
-BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
-{
- LLFastTimer t(FTM_VISIBLE_CLOUD);
- //get point cloud of intersection of frust and min, max
-
- if (getVisibleExtents(camera, min, max))
- {
- return FALSE;
- }
-
- //get set of planes on bounding box
- std::vector<LLPlane> bp;
-
- bp.push_back(LLPlane(min, LLVector3(-1,0,0)));
- bp.push_back(LLPlane(min, LLVector3(0,-1,0)));
- bp.push_back(LLPlane(min, LLVector3(0,0,-1)));
- bp.push_back(LLPlane(max, LLVector3(1,0,0)));
- bp.push_back(LLPlane(max, LLVector3(0,1,0)));
- bp.push_back(LLPlane(max, LLVector3(0,0,1)));
-
- //potential points
- std::vector<LLVector3> pp;
-
- //add corners of AABB
- pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2]));
- pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2]));
- pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2]));
- pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2]));
- pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2]));
- pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2]));
- pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2]));
- pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2]));
-
- //add corners of camera frustum
- for (U32 i = 0; i < 8; i++)
- {
- pp.push_back(camera.mAgentFrustum[i]);
- }
-
-
- //bounding box line segments
- U32 bs[] =
- {
- 0,1,
- 1,3,
- 3,2,
- 2,0,
-
- 4,5,
- 5,7,
- 7,6,
- 6,4,
-
- 0,4,
- 1,5,
- 3,7,
- 2,6
- };
-
- for (U32 i = 0; i < 12; i++)
- { //for each line segment in bounding box
- for (U32 j = 0; j < 6; j++)
- { //for each plane in camera frustum
- const LLPlane& cp = camera.getAgentPlane(j);
- const LLVector3& v1 = pp[bs[i*2+0]];
- const LLVector3& v2 = pp[bs[i*2+1]];
- const LLVector3 n(cp.mV);
-
- LLVector3 line = v1-v2;
-
- F32 d1 = line*n;
- F32 d2 = -cp.dist(v2);
-
- F32 t = d2/d1;
-
- if (t > 0.f && t < 1.f)
- {
- LLVector3 intersect = v2+line*t;
- pp.push_back(intersect);
- }
- }
- }
-
- //camera frustum line segments
- const U32 fs[] =
- {
- 0,1,
- 1,2,
- 2,3,
- 3,1,
-
- 4,5,
- 5,6,
- 6,7,
- 7,4,
-
- 0,4,
- 1,5,
- 2,6,
- 3,7
- };
-
- LLVector3 center = (max+min)*0.5f;
- LLVector3 size = (max-min)*0.5f;
-
- for (U32 i = 0; i < 12; i++)
- {
- for (U32 j = 0; j < 6; ++j)
- {
- const LLVector3& v1 = pp[fs[i*2+0]+8];
- const LLVector3& v2 = pp[fs[i*2+1]+8];
- const LLPlane& cp = bp[j];
- const LLVector3 n(cp.mV);
-
- LLVector3 line = v1-v2;
-
- F32 d1 = line*n;
- F32 d2 = -cp.dist(v2);
-
- F32 t = d2/d1;
-
- if (t > 0.f && t < 1.f)
- {
- LLVector3 intersect = v2+line*t;
- pp.push_back(intersect);
- }
- }
- }
-
- LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f),
- max+LLVector3(0.05f,0.05f,0.05f) };
-
- for (U32 i = 0; i < pp.size(); ++i)
- {
- bool found = true;
-
- const F32* p = pp[i].mV;
-
- for (U32 j = 0; j < 3; ++j)
- {
- if (p[j] < ext[0].mV[j] ||
- p[j] > ext[1].mV[j])
- {
- found = false;
- break;
- }
- }
-
- for (U32 j = 0; j < 6; ++j)
- {
- const LLPlane& cp = camera.getAgentPlane(j);
- F32 dist = cp.dist(pp[i]);
- if (dist > 0.05f) //point is above some plane, not contained
- {
- found = false;
- break;
- }
- }
-
- if (found)
- {
- fp.push_back(pp[i]);
- }
- }
-
- if (fp.empty())
- {
- return FALSE;
- }
-
- return TRUE;
-}
-
-void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<LLVector3>& vpc)
-{
- if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) < 3)
- {
- return;
- }
-
- LLVector3 up;
-
- //LLGLEnable depth_clamp(GL_DEPTH_CLAMP_NV);
-
- if (lightDir.mV[2] > 0.5f)
- {
- up = LLVector3(1,0,0);
- }
- else
- {
- up = LLVector3(0, 0, 1);
- }
-
-
- F32 gi_range = gSavedSettings.getF32("RenderGIRange");
-
- U32 res = mGIMap.getWidth();
-
- F32 atten = llmax(gSavedSettings.getF32("RenderGIAttenuation"), 0.001f);
-
- //set radius to range at which distance attenuation of incoming photons is near 0
-
- F32 lrad = sqrtf(1.f/(atten*0.01f));
-
- F32 lrange = lrad+gi_range*0.5f;
-
- LLVector3 pad(lrange,lrange,lrange);
-
- glh::matrix4f view = look(LLVector3(128.f,128.f,128.f), lightDir, up);
-
- LLVector3 cp = camera.getOrigin()+camera.getAtAxis()*(gi_range*0.5f);
-
- glh::vec3f scp(cp.mV);
- view.mult_matrix_vec(scp);
- cp.setVec(scp.v);
-
- F32 pix_width = lrange/(res*0.5f);
-
- //move cp to the nearest pix_width
- for (U32 i = 0; i < 3; i++)
- {
- cp.mV[i] = llround(cp.mV[i], pix_width);
- }
-
- LLVector3 min = cp-pad;
- LLVector3 max = cp+pad;
-
- //set mGIRange to range in tc space[0,1] that covers texture block of intersecting lights around a point
- mGIRange.mV[0] = (max.mV[0]-min.mV[0])/res;
- mGIRange.mV[1] = (max.mV[1]-min.mV[1])/res;
- mGILightRadius = lrad/lrange*0.5f;
-
- glh::matrix4f proj = gl_ortho(min.mV[0], max.mV[0],
- min.mV[1], max.mV[1],
- -max.mV[2], -min.mV[2]);
-
- LLCamera sun_cam = camera;
-
- glh::matrix4f eye_view = glh_get_current_modelview();
-
- //get eye space to camera space matrix
- mGIMatrix = view*eye_view.inverse();
- mGINormalMatrix = mGIMatrix.inverse().transpose();
- mGIInvProj = proj.inverse();
- mGIMatrixProj = proj*mGIMatrix;
-
- //translate and scale to [0,1]
- glh::matrix4f trans(.5f, 0.f, 0.f, .5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- mGIMatrixProj = trans*mGIMatrixProj;
-
- glh_set_current_modelview(view);
- glh_set_current_projection(proj);
-
- LLViewerCamera::updateFrustumPlanes(sun_cam, TRUE, FALSE, TRUE);
-
- sun_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
- static LLCullResult result;
-
- pushRenderTypeMask();
-
- andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_TREE,
- LLPipeline::RENDER_TYPE_TERRAIN,
- LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
- LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_BUMP,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- END_RENDER_TYPES);
-
-
-
- S32 occlude = LLPipeline::sUseOcclusion;
- //LLPipeline::sUseOcclusion = 0;
- LLPipeline::sShadowRender = TRUE;
-
- //only render large objects into GI map
- sMinRenderSize = gSavedSettings.getF32("RenderGIMinRenderSize");
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_GI_SOURCE;
- mGIMap.bindTarget();
-
- F64 last_modelview[16];
- F64 last_projection[16];
- for (U32 i = 0; i < 16; i++)
- {
- last_modelview[i] = gGLLastModelView[i];
- last_projection[i] = gGLLastProjection[i];
- gGLLastModelView[i] = mGIModelview.m[i];
- gGLLastProjection[i] = mGIProjection.m[i];
- }
-
- sun_cam.setOrigin(0.f, 0.f, 0.f);
- updateCull(sun_cam, result);
- stateSort(sun_cam, result);
-
- for (U32 i = 0; i < 16; i++)
- {
- gGLLastModelView[i] = last_modelview[i];
- gGLLastProjection[i] = last_projection[i];
- }
-
- mGIProjection = proj;
- mGIModelview = view;
-
- LLGLEnable cull(GL_CULL_FACE);
-
- //generate GI map
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- glLoadMatrixf(proj.m);
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadMatrixf(view.m);
-
- stop_glerror();
- gGLLastMatrix = NULL;
-
- mGIMap.clear();
-
- {
- //LLGLEnable enable(GL_DEPTH_CLAMP_NV);
- renderGeomDeferred(camera);
- }
-
- mGIMap.flush();
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
- gGLLastMatrix = NULL;
-
- LLPipeline::sUseOcclusion = occlude;
- LLPipeline::sShadowRender = FALSE;
- sMinRenderSize = 0.f;
-
- popRenderTypeMask();
-
-}
-
-void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade)
-{
- if (obj && obj->getVolume())
- {
- for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter)
- {
- renderHighlight(*iter, fade);
- }
-
- LLDrawable* drawable = obj->mDrawable;
- if (drawable)
- {
- for (S32 i = 0; i < drawable->getNumFaces(); ++i)
- {
- LLFace* face = drawable->getFace(i);
- if (face)
- {
- face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade));
- }
- }
- }
- }
-}
-
-void LLPipeline::generateHighlight(LLCamera& camera)
-{
- //render highlighted object as white into offscreen render target
- if (mHighlightObject.notNull())
- {
- mHighlightSet.insert(HighlightItem(mHighlightObject));
- }
-
- if (!mHighlightSet.empty())
- {
- F32 transition = gFrameIntervalSeconds/gSavedSettings.getF32("RenderHighlightFadeTime");
-
- LLGLDisable test(GL_ALPHA_TEST);
- LLGLDepthTest depth(GL_FALSE);
- mHighlight.bindTarget();
- disableLights();
- gGL.setColorMask(true, true);
- mHighlight.clear();
-
- gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
- for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); )
- {
- std::set<HighlightItem>::iterator cur_iter = iter++;
-
- if (cur_iter->mItem.isNull())
- {
- mHighlightSet.erase(cur_iter);
- continue;
- }
-
- if (cur_iter->mItem == mHighlightObject)
- {
- cur_iter->incrFade(transition);
- }
- else
- {
- cur_iter->incrFade(-transition);
- if (cur_iter->mFade <= 0.f)
- {
- mHighlightSet.erase(cur_iter);
- continue;
- }
- }
-
- renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade);
- }
-
- mHighlight.flush();
- gGL.setColorMask(true, false);
- gViewerWindow->setup3DViewport();
- }
-}
-
-
-void LLPipeline::generateSunShadow(LLCamera& camera)
-{
- if (!sRenderDeferred || gSavedSettings.getS32("RenderShadowDetail") <= 0)
- {
- return;
- }
-
- F64 last_modelview[16];
- F64 last_projection[16];
- for (U32 i = 0; i < 16; i++)
- { //store last_modelview of world camera
- last_modelview[i] = gGLLastModelView[i];
- last_projection[i] = gGLLastProjection[i];
- }
-
- pushRenderTypeMask();
- andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
- LLPipeline::RENDER_TYPE_ALPHA,
- LLPipeline::RENDER_TYPE_GRASS,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_TREE,
- LLPipeline::RENDER_TYPE_TERRAIN,
- LLPipeline::RENDER_TYPE_WATER,
- LLPipeline::RENDER_TYPE_VOIDWATER,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_BUMP,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
- END_RENDER_TYPES);
-
- gGL.setColorMask(false, false);
-
- //get sun view matrix
-
- //store current projection/modelview matrix
- glh::matrix4f saved_proj = glh_get_current_projection();
- glh::matrix4f saved_view = glh_get_current_modelview();
- glh::matrix4f inv_view = saved_view.inverse();
-
- glh::matrix4f view[6];
- glh::matrix4f proj[6];
-
- //clip contains parallel split distances for 3 splits
- LLVector3 clip = gSavedSettings.getVector3("RenderShadowClipPlanes");
-
- //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold");
-
- //far clip on last split is minimum of camera view distance and 128
- mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]);
-
- clip = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes");
- mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]);
-
- //currently used for amount to extrude frusta corners for constructing shadow frusta
- LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist");
- //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
-
- LLVector3 lightDir = -mSunDir;
- lightDir.normVec();
-
- glh::vec3f light_dir(lightDir.mV);
-
- //create light space camera matrix
-
- LLVector3 at = lightDir;
-
- LLVector3 up = camera.getAtAxis();
-
- if (fabsf(up*lightDir) > 0.75f)
- {
- up = camera.getUpAxis();
- }
-
- /*LLVector3 left = up%at;
- up = at%left;*/
-
- up.normVec();
- at.normVec();
-
-
- LLCamera main_camera = camera;
-
- F32 near_clip = 0.f;
- {
- //get visible point cloud
- std::vector<LLVector3> fp;
-
- main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum);
-
- LLVector3 min,max;
- getVisiblePointCloud(main_camera,min,max,fp);
-
- if (fp.empty())
- {
- if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowCamera[0] = main_camera;
- mShadowExtents[0][0] = min;
- mShadowExtents[0][1] = max;
-
- mShadowFrustPoints[0].clear();
- mShadowFrustPoints[1].clear();
- mShadowFrustPoints[2].clear();
- mShadowFrustPoints[3].clear();
- }
- popRenderTypeMask();
- return;
- }
-
- generateGI(camera, lightDir, fp);
-
- //get good split distances for frustum
- for (U32 i = 0; i < fp.size(); ++i)
- {
- glh::vec3f v(fp[i].mV);
- saved_view.mult_matrix_vec(v);
- fp[i].setVec(v.v);
- }
-
- min = fp[0];
- max = fp[0];
-
- //get camera space bounding box
- for (U32 i = 1; i < fp.size(); ++i)
- {
- update_min_max(min, max, fp[i]);
- }
-
- near_clip = -max.mV[2];
- F32 far_clip = -min.mV[2]*2.f;
-
- far_clip = llmin(far_clip, 128.f);
- far_clip = llmin(far_clip, camera.getFar());
-
- F32 range = far_clip-near_clip;
-
- LLVector3 split_exp = gSavedSettings.getVector3("RenderShadowSplitExponent");
-
- F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) );
-
- da = powf(da, split_exp.mV[2]);
-
-
- F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da;
-
-
- for (U32 i = 0; i < 4; ++i)
- {
- F32 x = (F32)(i+1)/4.f;
- x = powf(x, sxp);
- mSunClipPlanes.mV[i] = near_clip+range*x;
- }
- }
-
- // convenience array of 4 near clip plane distances
- F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
-
- for (S32 j = 0; j < 4; j++)
- {
- if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowFrustPoints[j].clear();
- }
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j;
-
- //restore render matrices
- glh_set_current_modelview(saved_view);
- glh_set_current_projection(saved_proj);
-
- LLVector3 eye = camera.getOrigin();
-
- //camera used for shadow cull/render
- LLCamera shadow_cam;
-
- //create world space camera frustum for this split
- shadow_cam = camera;
- shadow_cam.setFar(16.f);
-
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
-
- LLVector3* frust = shadow_cam.mAgentFrustum;
-
- LLVector3 pn = shadow_cam.getAtAxis();
-
- LLVector3 min, max;
-
- //construct 8 corners of split frustum section
- for (U32 i = 0; i < 4; i++)
- {
- LLVector3 delta = frust[i+4]-eye;
- delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f;
- delta.normVec();
- F32 dp = delta*pn;
- frust[i] = eye + (delta*dist[j]*0.95f)/dp;
- frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp;
- }
-
- shadow_cam.calcAgentFrustumPlanes(frust);
- shadow_cam.mFrustumCornerDist = 0.f;
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowCamera[j] = shadow_cam;
- }
-
- std::vector<LLVector3> fp;
-
- if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir))
- {
- //no possible shadow receivers
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowExtents[j][0] = LLVector3();
- mShadowExtents[j][1] = LLVector3();
- mShadowCamera[j+4] = shadow_cam;
- }
-
- mShadow[j].bindTarget();
- {
- LLGLDepthTest depth(GL_TRUE);
- mShadow[j].clear();
- }
- mShadow[j].flush();
-
- mShadowError.mV[j] = 0.f;
- mShadowFOV.mV[j] = 0.f;
-
- continue;
- }
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowExtents[j][0] = min;
- mShadowExtents[j][1] = max;
- mShadowFrustPoints[j] = fp;
- }
-
-
- //find a good origin for shadow projection
- LLVector3 origin;
-
- //get a temporary view projection
- view[j] = look(camera.getOrigin(), lightDir, -up);
-
- std::vector<LLVector3> wpf;
-
- for (U32 i = 0; i < fp.size(); i++)
- {
- glh::vec3f p = glh::vec3f(fp[i].mV);
- view[j].mult_matrix_vec(p);
- wpf.push_back(LLVector3(p.v));
- }
-
- min = wpf[0];
- max = wpf[0];
-
- for (U32 i = 0; i < fp.size(); ++i)
- { //get AABB in camera space
- update_min_max(min, max, wpf[i]);
- }
-
- // Construct a perspective transform with perspective along y-axis that contains
- // points in wpf
- //Known:
- // - far clip plane
- // - near clip plane
- // - points in frustum
- //Find:
- // - origin
-
- //get some "interesting" points of reference
- LLVector3 center = (min+max)*0.5f;
- LLVector3 size = (max-min)*0.5f;
- LLVector3 near_center = center;
- near_center.mV[1] += size.mV[1]*2.f;
-
-
- //put all points in wpf in quadrant 0, reletive to center of min/max
- //get the best fit line using least squares
- F32 bfm = 0.f;
- F32 bfb = 0.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- wpf[i] -= center;
- wpf[i].mV[0] = fabsf(wpf[i].mV[0]);
- wpf[i].mV[2] = fabsf(wpf[i].mV[2]);
- }
-
- if (!wpf.empty())
- {
- F32 sx = 0.f;
- F32 sx2 = 0.f;
- F32 sy = 0.f;
- F32 sxy = 0.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- sx += wpf[i].mV[0];
- sx2 += wpf[i].mV[0]*wpf[i].mV[0];
- sy += wpf[i].mV[1];
- sxy += wpf[i].mV[0]*wpf[i].mV[1];
- }
-
- bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2);
- bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2);
- }
-
- {
- // best fit line is y=bfm*x+bfb
-
- //find point that is furthest to the right of line
- F32 off_x = -1.f;
- LLVector3 lp;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- //y = bfm*x+bfb
- //x = (y-bfb)/bfm
- F32 lx = (wpf[i].mV[1]-bfb)/bfm;
-
- lx = wpf[i].mV[0]-lx;
-
- if (off_x < lx)
- {
- off_x = lx;
- lp = wpf[i];
- }
- }
-
- //get line with slope bfm through lp
- // bfb = y-bfm*x
- bfb = lp.mV[1]-bfm*lp.mV[0];
-
- //calculate error
- mShadowError.mV[j] = 0.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- F32 lx = (wpf[i].mV[1]-bfb)/bfm;
- mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx);
- }
-
- mShadowError.mV[j] /= wpf.size();
- mShadowError.mV[j] /= size.mV[0];
-
- if (mShadowError.mV[j] > gSavedSettings.getF32("RenderShadowErrorCutoff"))
- { //just use ortho projection
- mShadowFOV.mV[j] = -1.f;
- origin.clearVec();
- proj[j] = gl_ortho(min.mV[0], max.mV[0],
- min.mV[1], max.mV[1],
- -max.mV[2], -min.mV[2]);
- }
- else
- {
- //origin is where line x = 0;
- origin.setVec(0,bfb,0);
-
- F32 fovz = 1.f;
- F32 fovx = 1.f;
-
- LLVector3 zp;
- LLVector3 xp;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- LLVector3 atz = wpf[i]-origin;
- atz.mV[0] = 0.f;
- atz.normVec();
- if (fovz > -atz.mV[1])
- {
- zp = wpf[i];
- fovz = -atz.mV[1];
- }
-
- LLVector3 atx = wpf[i]-origin;
- atx.mV[2] = 0.f;
- atx.normVec();
- if (fovx > -atx.mV[1])
- {
- fovx = -atx.mV[1];
- xp = wpf[i];
- }
- }
-
- fovx = acos(fovx);
- fovz = acos(fovz);
-
- F32 cutoff = llmin(gSavedSettings.getF32("RenderShadowFOVCutoff"), 1.4f);
-
- mShadowFOV.mV[j] = fovx;
-
- if (fovx < cutoff && fovz > cutoff)
- {
- //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff
- F32 d = zp.mV[2]/tan(cutoff);
- F32 ny = zp.mV[1] + fabsf(d);
-
- origin.mV[1] = ny;
-
- fovz = 1.f;
- fovx = 1.f;
-
- for (U32 i = 0; i < wpf.size(); ++i)
- {
- LLVector3 atz = wpf[i]-origin;
- atz.mV[0] = 0.f;
- atz.normVec();
- fovz = llmin(fovz, -atz.mV[1]);
-
- LLVector3 atx = wpf[i]-origin;
- atx.mV[2] = 0.f;
- atx.normVec();
- fovx = llmin(fovx, -atx.mV[1]);
- }
-
- fovx = acos(fovx);
- fovz = acos(fovz);
-
- if (fovx > cutoff || llround(fovz, 0.01f) > cutoff)
- {
- // llerrs << "WTF?" << llendl;
- }
-
- mShadowFOV.mV[j] = cutoff;
- }
-
-
- origin += center;
-
- F32 ynear = -(max.mV[1]-origin.mV[1]);
- F32 yfar = -(min.mV[1]-origin.mV[1]);
-
- if (ynear < 0.1f) //keep a sensible near clip plane
- {
- F32 diff = 0.1f-ynear;
- origin.mV[1] += diff;
- ynear += diff;
- yfar += diff;
- }
-
- if (fovx > cutoff)
- { //just use ortho projection
- origin.clearVec();
- mShadowError.mV[j] = -1.f;
- proj[j] = gl_ortho(min.mV[0], max.mV[0],
- min.mV[1], max.mV[1],
- -max.mV[2], -min.mV[2]);
- }
- else
- {
- //get perspective projection
- view[j] = view[j].inverse();
-
- glh::vec3f origin_agent(origin.mV);
-
- //translate view to origin
- view[j].mult_matrix_vec(origin_agent);
-
- eye = LLVector3(origin_agent.v);
-
- if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- mShadowFrustOrigin[j] = eye;
- }
-
- view[j] = look(LLVector3(origin_agent.v), lightDir, -up);
-
- F32 fx = 1.f/tanf(fovx);
- F32 fz = 1.f/tanf(fovz);
-
- proj[j] = glh::matrix4f(-fx, 0, 0, 0,
- 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar),
- 0, 0, -fz, 0,
- 0, -1.f, 0, 0);
- }
- }
- }
-
- shadow_cam.setFar(128.f);
- shadow_cam.setOriginAndLookAt(eye, up, center);
-
- shadow_cam.setOrigin(0,0,0);
-
- glh_set_current_modelview(view[j]);
- glh_set_current_projection(proj[j]);
-
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
-
- shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
-
- //translate and scale to from [-1, 1] to [0, 1]
- glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- glh_set_current_modelview(view[j]);
- glh_set_current_projection(proj[j]);
-
- for (U32 i = 0; i < 16; i++)
- {
- gGLLastModelView[i] = mShadowModelview[j].m[i];
- gGLLastProjection[i] = mShadowProjection[j].m[i];
- }
-
- mShadowModelview[j] = view[j];
- mShadowProjection[j] = proj[j];
-
-
- mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view;
-
- stop_glerror();
-
- mShadow[j].bindTarget();
- mShadow[j].getViewport(gGLViewport);
-
- {
- static LLCullResult result[4];
-
- //LLGLEnable enable(GL_DEPTH_CLAMP_NV);
- renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE);
- }
-
- mShadow[j].flush();
-
- if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
- {
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
- mShadowCamera[j+4] = shadow_cam;
- }
- }
-
-
- //hack to disable projector shadows
- static bool clear = true;
- bool gen_shadow = gSavedSettings.getS32("RenderShadowDetail") > 1;
-
- if (gen_shadow)
- {
- clear = true;
- F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f);
-
- //update shadow targets
- for (U32 i = 0; i < 2; i++)
- { //for each current shadow
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i;
-
- if (mShadowSpotLight[i].notNull() &&
- (mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
- mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
- { //keep this spotlight
- mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
- }
- else
- { //fade out this light
- mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
-
- if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
- { //faded out, grab one of the pending spots (whichever one isn't already taken)
- if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
- {
- mShadowSpotLight[i] = mTargetShadowSpotLight[0];
- }
- else
- {
- mShadowSpotLight[i] = mTargetShadowSpotLight[1];
- }
- }
- }
- }
-
- for (S32 i = 0; i < 2; i++)
- {
- glh_set_current_modelview(saved_view);
- glh_set_current_projection(saved_proj);
-
- if (mShadowSpotLight[i].isNull())
- {
- continue;
- }
-
- LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
-
- if (!volume)
- {
- mShadowSpotLight[i] = NULL;
- continue;
- }
-
- LLDrawable* drawable = mShadowSpotLight[i];
-
- LLVector3 params = volume->getSpotLightParams();
- F32 fov = params.mV[0];
-
- //get agent->light space matrix (modelview)
- LLVector3 center = drawable->getPositionAgent();
- LLQuaternion quat = volume->getRenderRotation();
-
- //get near clip plane
- LLVector3 scale = volume->getScale();
- LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
- at_axis *= quat;
-
- LLVector3 np = center+at_axis;
- at_axis.normVec();
-
- //get origin that has given fov for plane np, at_axis, and given scale
- F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
-
- LLVector3 origin = np - at_axis*dist;
-
- LLMatrix4 mat(quat, LLVector4(origin, 1.f));
-
- view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
-
- view[i+4] = view[i+4].inverse();
-
- //get perspective matrix
- F32 near_clip = dist+0.01f;
- F32 width = scale.mV[VX];
- F32 height = scale.mV[VY];
- F32 far_clip = dist+volume->getLightRadius()*1.5f;
-
- F32 fovy = fov * RAD_TO_DEG;
- F32 aspect = width/height;
-
- proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
-
- //translate and scale to from [-1, 1] to [0, 1]
- glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
- 0.f, 0.5f, 0.f, 0.5f,
- 0.f, 0.f, 0.5f, 0.5f,
- 0.f, 0.f, 0.f, 1.f);
-
- glh_set_current_modelview(view[i+4]);
- glh_set_current_projection(proj[i+4]);
-
- mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view;
-
- for (U32 j = 0; j < 16; j++)
- {
- gGLLastModelView[j] = mShadowModelview[i+4].m[j];
- gGLLastProjection[j] = mShadowProjection[i+4].m[j];
- }
-
- mShadowModelview[i+4] = view[i+4];
- mShadowProjection[i+4] = proj[i+4];
-
- LLCamera shadow_cam = camera;
- shadow_cam.setFar(far_clip);
- shadow_cam.setOrigin(origin);
-
- LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
-
- stop_glerror();
-
- mShadow[i+4].bindTarget();
- mShadow[i+4].getViewport(gGLViewport);
-
- static LLCullResult result[2];
-
- LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
-
- renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
-
- mShadow[i+4].flush();
- }
- }
- else
- {
- if (clear)
- {
- clear = false;
- for (U32 i = 4; i < 6; i++)
- {
- mShadow[i].bindTarget();
- mShadow[i].clear();
- mShadow[i].flush();
- }
- }
- }
-
- if (!gSavedSettings.getBOOL("CameraOffset"))
- {
- glh_set_current_modelview(saved_view);
- glh_set_current_projection(saved_proj);
- }
- else
- {
- glh_set_current_modelview(view[1]);
- glh_set_current_projection(proj[1]);
- glLoadMatrixf(view[1].m);
- glMatrixMode(GL_PROJECTION);
- glLoadMatrixf(proj[1].m);
- glMatrixMode(GL_MODELVIEW);
- }
- gGL.setColorMask(true, false);
-
- for (U32 i = 0; i < 16; i++)
- {
- gGLLastModelView[i] = last_modelview[i];
- gGLLastProjection[i] = last_projection[i];
- }
-
- popRenderTypeMask();
-}
-
-void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
-{
- for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
- {
- LLSpatialGroup* group = *i;
- if (!group->isDead() &&
- (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) &&
- gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
- group->mDrawMap.find(type) != group->mDrawMap.end())
- {
- pass->renderGroup(group,type,mask,texture);
- }
- }
-}
-
-void LLPipeline::generateImpostor(LLVOAvatar* avatar)
-{
- LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR);
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-
- static LLCullResult result;
- result.clear();
- grabReferences(result);
-
- if (!avatar || !avatar->mDrawable)
- {
- return;
- }
-
- assertInitialized();
-
- BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID());
-
- pushRenderTypeMask();
-
- if (muted)
- {
- andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
- }
- else
- {
- andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME,
- LLPipeline::RENDER_TYPE_AVATAR,
- LLPipeline::RENDER_TYPE_BUMP,
- LLPipeline::RENDER_TYPE_GRASS,
- LLPipeline::RENDER_TYPE_SIMPLE,
- LLPipeline::RENDER_TYPE_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_ALPHA,
- LLPipeline::RENDER_TYPE_INVISIBLE,
- LLPipeline::RENDER_TYPE_PASS_SIMPLE,
- LLPipeline::RENDER_TYPE_PASS_ALPHA,
- LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
- LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
- LLPipeline::RENDER_TYPE_PASS_SHINY,
- LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
- LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
- END_RENDER_TYPES);
- }
-
- S32 occlusion = sUseOcclusion;
- sUseOcclusion = 0;
- sReflectionRender = sRenderDeferred ? FALSE : TRUE;
- sShadowRender = TRUE;
- sImpostorRender = TRUE;
-
- LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
- markVisible(avatar->mDrawable, *viewer_camera);
- LLVOAvatar::sUseImpostors = FALSE;
-
- LLVOAvatar::attachment_map_t::iterator iter;
- for (iter = avatar->mAttachmentPoints.begin();
- iter != avatar->mAttachmentPoints.end();
- ++iter)
- {
- LLViewerJointAttachment *attachment = iter->second;
- for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
- attachment_iter != attachment->mAttachedObjects.end();
- ++attachment_iter)
- {
- if (LLViewerObject* attached_object = (*attachment_iter))
- {
- markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
- }
- }
- }
-
- stateSort(*LLViewerCamera::getInstance(), result);
-
- const LLVector3* ext = avatar->mDrawable->getSpatialExtents();
- LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
-
- LLCamera camera = *viewer_camera;
-
- camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis());
-
- LLVector2 tdim;
-
- LLVector3 half_height = (ext[1]-ext[0])*0.5f;
-
- LLVector3 left = camera.getLeftAxis();
- left *= left;
- left.normalize();
-
- LLVector3 up = camera.getUpAxis();
- up *= up;
- up.normalize();
-
- tdim.mV[0] = fabsf(half_height * left);
- tdim.mV[1] = fabsf(half_height * up);
-
- glMatrixMode(GL_PROJECTION);
- glPushMatrix();
- //glh::matrix4f ortho = gl_ortho(-tdim.mV[0], tdim.mV[0], -tdim.mV[1], tdim.mV[1], 1.0, 256.0);
- F32 distance = (pos-camera.getOrigin()).length();
- F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG;
- F32 aspect = tdim.mV[0]/tdim.mV[1]; //128.f/256.f;
- glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f);
- glh_set_current_projection(persp);
- glLoadMatrixf(persp.m);
-
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glh::matrix4f mat;
- camera.getOpenGLTransform(mat.m);
-
- mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat;
-
- glLoadMatrixf(mat.m);
- glh_set_current_modelview(mat);
-
- glClearColor(0.0f,0.0f,0.0f,0.0f);
- gGL.setColorMask(true, true);
- glStencilMask(0xFFFFFFFF);
- glClearStencil(0);
-
- // get the number of pixels per angle
- F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView());
-
- //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing)
- U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512);
- U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512);
-
- if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() ||
- resY != avatar->mImpostor.getHeight())
- {
- avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,TRUE);
-
- if (LLPipeline::sRenderDeferred)
- {
- addDeferredAttachments(avatar->mImpostor);
- }
-
- gGL.getTexUnit(0)->bind(&avatar->mImpostor);
- gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
- }
-
- LLGLEnable stencil(GL_STENCIL_TEST);
- glStencilMask(0xFFFFFFFF);
- glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
- glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
-
- {
- LLGLEnable scissor(GL_SCISSOR_TEST);
- glScissor(0, 0, resX, resY);
- avatar->mImpostor.bindTarget();
- avatar->mImpostor.clear();
- }
-
- if (LLPipeline::sRenderDeferred)
- {
- stop_glerror();
- renderGeomDeferred(camera);
- renderGeomPostDeferred(camera);
- }
- else
- {
- renderGeom(camera);
- }
-
- glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
- glStencilFunc(GL_EQUAL, 1, 0xFFFFFF);
-
- { //create alpha mask based on stencil buffer (grey out if muted)
- LLVector3 left = camera.getLeftAxis()*tdim.mV[0]*2.f;
- LLVector3 up = camera.getUpAxis()*tdim.mV[1]*2.f;
-
- if (LLPipeline::sRenderDeferred)
- {
- GLuint buff = GL_COLOR_ATTACHMENT0_EXT;
- glDrawBuffersARB(1, &buff);
- }
-
- LLGLEnable blend(muted ? 0 : GL_BLEND);
-
- if (muted)
- {
- gGL.setColorMask(true, true);
- }
- else
- {
- gGL.setColorMask(false, true);
- }
-
- gGL.setSceneBlendType(LLRender::BT_ADD);
- gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
-
- LLGLDepthTest depth(GL_FALSE, GL_FALSE);
-
- gGL.color4f(1,1,1,1);
- gGL.color4ub(64,64,64,255);
- gGL.begin(LLRender::QUADS);
- gGL.vertex3fv((pos+left-up).mV);
- gGL.vertex3fv((pos-left-up).mV);
- gGL.vertex3fv((pos-left+up).mV);
- gGL.vertex3fv((pos+left+up).mV);
- gGL.end();
- gGL.flush();
-
- gGL.setSceneBlendType(LLRender::BT_ALPHA);
- }
-
-
- avatar->mImpostor.flush();
-
- avatar->setImpostorDim(tdim);
-
- LLVOAvatar::sUseImpostors = TRUE;
- sUseOcclusion = occlusion;
- sReflectionRender = FALSE;
- sImpostorRender = FALSE;
- sShadowRender = FALSE;
- popRenderTypeMask();
-
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(GL_MODELVIEW);
- glPopMatrix();
-
- avatar->mNeedsImpostorUpdate = FALSE;
- avatar->cacheImpostorValues();
-
- LLVertexBuffer::unbind();
- LLGLState::checkStates();
- LLGLState::checkTextureChannels();
- LLGLState::checkClientArrays();
-}
-
-BOOL LLPipeline::hasRenderBatches(const U32 type) const
-{
- return sCull->getRenderMapSize(type) > 0;
-}
-
-LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type)
-{
- return sCull->beginRenderMap(type);
-}
-
-LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type)
-{
- return sCull->endRenderMap(type);
-}
-
-LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups()
-{
- return sCull->beginAlphaGroups();
-}
-
-LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
-{
- return sCull->endAlphaGroups();
-}
-
-BOOL LLPipeline::hasRenderType(const U32 type) const
-{
- // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render"
- // We then need to test that value here and return FALSE to prevent attachment to render (in mouselook for instance)
- // TODO: reintroduce RENDER_TYPE_NONE in LLRenderTypeMask and initialize its mRenderTypeEnabled[RENDER_TYPE_NONE] to FALSE explicitely
- return (type == 0 ? FALSE : mRenderTypeEnabled[type]);
-}
-
-void LLPipeline::setRenderTypeMask(U32 type, ...)
-{
- va_list args;
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- mRenderTypeEnabled[type] = TRUE;
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-}
-
-BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const
-{
- va_list args;
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- if (mRenderTypeEnabled[type])
- {
- return TRUE;
- }
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-
- return FALSE;
-}
-
-void LLPipeline::pushRenderTypeMask()
-{
- std::string cur_mask;
- cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled));
- mRenderTypeEnableStack.push(cur_mask);
-}
-
-void LLPipeline::popRenderTypeMask()
-{
- if (mRenderTypeEnableStack.empty())
- {
- llerrs << "Depleted render type stack." << llendl;
- }
-
- memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled));
- mRenderTypeEnableStack.pop();
-}
-
-void LLPipeline::andRenderTypeMask(U32 type, ...)
-{
- va_list args;
-
- BOOL tmp[NUM_RENDER_TYPES];
- for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
- {
- tmp[i] = FALSE;
- }
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- if (mRenderTypeEnabled[type])
- {
- tmp[type] = TRUE;
- }
-
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-
- for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i)
- {
- mRenderTypeEnabled[i] = tmp[i];
- }
-
-}
-
-void LLPipeline::clearRenderTypeMask(U32 type, ...)
-{
- va_list args;
-
- va_start(args, type);
- while (type < END_RENDER_TYPES)
- {
- mRenderTypeEnabled[type] = FALSE;
-
- type = va_arg(args, U32);
- }
- va_end(args);
-
- if (type > END_RENDER_TYPES)
- {
- llerrs << "Invalid render type." << llendl;
- }
-}
-
-
+/**
+ * @file pipeline.cpp
+ * @brief Rendering pipeline.
+ *
+ * $LicenseInfo:firstyear=2005&license=viewerlgpl$
+ * Second Life Viewer Source Code
+ * Copyright (C) 2010, Linden Research, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation;
+ * version 2.1 of the License only.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+ * $/LicenseInfo$
+ */
+
+#include "llviewerprecompiledheaders.h"
+
+#include "pipeline.h"
+
+// library includes
+#include "llaudioengine.h" // For debugging.
+#include "imageids.h"
+#include "llerror.h"
+#include "llviewercontrol.h"
+#include "llfasttimer.h"
+#include "llfontgl.h"
+#include "llmemtype.h"
+#include "llnamevalue.h"
+#include "llpointer.h"
+#include "llprimitive.h"
+#include "llvolume.h"
+#include "material_codes.h"
+#include "timing.h"
+#include "v3color.h"
+#include "llui.h"
+#include "llglheaders.h"
+#include "llrender.h"
+#include "llwindow.h" // swapBuffers()
+
+// newview includes
+#include "llagent.h"
+#include "llagentcamera.h"
+#include "lldrawable.h"
+#include "lldrawpoolalpha.h"
+#include "lldrawpoolavatar.h"
+#include "lldrawpoolground.h"
+#include "lldrawpoolbump.h"
+#include "lldrawpooltree.h"
+#include "lldrawpoolwater.h"
+#include "llface.h"
+#include "llfeaturemanager.h"
+#include "llfloatertelehub.h"
+#include "llfloaterreg.h"
+#include "llgldbg.h"
+#include "llhudmanager.h"
+#include "llhudnametag.h"
+#include "llhudtext.h"
+#include "lllightconstants.h"
+#include "llresmgr.h"
+#include "llselectmgr.h"
+#include "llsky.h"
+#include "lltracker.h"
+#include "lltool.h"
+#include "lltoolmgr.h"
+#include "llviewercamera.h"
+#include "llviewertexturelist.h"
+#include "llviewerobject.h"
+#include "llviewerobjectlist.h"
+#include "llviewerparcelmgr.h"
+#include "llviewerregion.h" // for audio debugging.
+#include "llviewerwindow.h" // For getSpinAxis
+#include "llvoavatarself.h"
+#include "llvoground.h"
+#include "llvosky.h"
+#include "llvotree.h"
+#include "llvovolume.h"
+#include "llvosurfacepatch.h"
+#include "llvowater.h"
+#include "llvotree.h"
+#include "llvopartgroup.h"
+#include "llworld.h"
+#include "llcubemap.h"
+#include "llviewershadermgr.h"
+#include "llviewerstats.h"
+#include "llviewerjoystick.h"
+#include "llviewerdisplay.h"
+#include "llwlparammanager.h"
+#include "llwaterparammanager.h"
+#include "llspatialpartition.h"
+#include "llmutelist.h"
+#include "lltoolpie.h"
+
+
+#ifdef _DEBUG
+// Debug indices is disabled for now for debug performance - djs 4/24/02
+//#define DEBUG_INDICES
+#else
+//#define DEBUG_INDICES
+#endif
+
+const F32 BACKLIGHT_DAY_MAGNITUDE_AVATAR = 0.2f;
+const F32 BACKLIGHT_NIGHT_MAGNITUDE_AVATAR = 0.1f;
+const F32 BACKLIGHT_DAY_MAGNITUDE_OBJECT = 0.1f;
+const F32 BACKLIGHT_NIGHT_MAGNITUDE_OBJECT = 0.08f;
+const S32 MAX_OFFSCREEN_GEOMETRY_CHANGES_PER_FRAME = 10;
+const U32 REFLECTION_MAP_RES = 128;
+
+// Max number of occluders to search for. JC
+const S32 MAX_OCCLUDER_COUNT = 2;
+
+extern S32 gBoxFrame;
+//extern BOOL gHideSelectedObjects;
+extern BOOL gDisplaySwapBuffers;
+extern BOOL gDebugGL;
+
+// hack counter for rendering a fixed number of frames after toggling
+// fullscreen to work around DEV-5361
+static S32 sDelayedVBOEnable = 0;
+
+BOOL gAvatarBacklight = FALSE;
+
+BOOL gDebugPipeline = FALSE;
+LLPipeline gPipeline;
+const LLMatrix4* gGLLastMatrix = NULL;
+
+LLFastTimer::DeclareTimer FTM_RENDER_GEOMETRY("Geometry");
+LLFastTimer::DeclareTimer FTM_RENDER_GRASS("Grass");
+LLFastTimer::DeclareTimer FTM_RENDER_INVISIBLE("Invisible");
+LLFastTimer::DeclareTimer FTM_RENDER_OCCLUSION("Occlusion");
+LLFastTimer::DeclareTimer FTM_RENDER_SHINY("Shiny");
+LLFastTimer::DeclareTimer FTM_RENDER_SIMPLE("Simple");
+LLFastTimer::DeclareTimer FTM_RENDER_TERRAIN("Terrain");
+LLFastTimer::DeclareTimer FTM_RENDER_TREES("Trees");
+LLFastTimer::DeclareTimer FTM_RENDER_UI("UI");
+LLFastTimer::DeclareTimer FTM_RENDER_WATER("Water");
+LLFastTimer::DeclareTimer FTM_RENDER_WL_SKY("Windlight Sky");
+LLFastTimer::DeclareTimer FTM_RENDER_ALPHA("Alpha Objects");
+LLFastTimer::DeclareTimer FTM_RENDER_CHARACTERS("Avatars");
+LLFastTimer::DeclareTimer FTM_RENDER_BUMP("Bump");
+LLFastTimer::DeclareTimer FTM_RENDER_FULLBRIGHT("Fullbright");
+LLFastTimer::DeclareTimer FTM_RENDER_GLOW("Glow");
+LLFastTimer::DeclareTimer FTM_GEO_UPDATE("Geo Update");
+LLFastTimer::DeclareTimer FTM_POOLRENDER("RenderPool");
+LLFastTimer::DeclareTimer FTM_POOLS("Pools");
+LLFastTimer::DeclareTimer FTM_RENDER_BLOOM_FBO("First FBO");
+LLFastTimer::DeclareTimer FTM_STATESORT("Sort Draw State");
+LLFastTimer::DeclareTimer FTM_PIPELINE("Pipeline");
+LLFastTimer::DeclareTimer FTM_CLIENT_COPY("Client Copy");
+LLFastTimer::DeclareTimer FTM_RENDER_DEFERRED("Deferred Shading");
+
+
+static LLFastTimer::DeclareTimer FTM_STATESORT_DRAWABLE("Sort Drawables");
+static LLFastTimer::DeclareTimer FTM_STATESORT_POSTSORT("Post Sort");
+
+//----------------------------------------
+std::string gPoolNames[] =
+{
+ // Correspond to LLDrawpool enum render type
+ "NONE",
+ "POOL_SIMPLE",
+ "POOL_TERRAIN",
+ "POOL_BUMP",
+ "POOL_TREE",
+ "POOL_SKY",
+ "POOL_WL_SKY",
+ "POOL_GROUND",
+ "POOL_INVISIBLE",
+ "POOL_AVATAR",
+ "POOL_WATER",
+ "POOL_GRASS",
+ "POOL_FULLBRIGHT",
+ "POOL_GLOW",
+ "POOL_ALPHA",
+};
+
+void drawBox(const LLVector3& c, const LLVector3& r);
+void drawBoxOutline(const LLVector3& pos, const LLVector3& size);
+
+U32 nhpo2(U32 v)
+{
+ U32 r = 1;
+ while (r < v) {
+ r *= 2;
+ }
+ return r;
+}
+
+glh::matrix4f glh_copy_matrix(GLdouble* src)
+{
+ glh::matrix4f ret;
+ for (U32 i = 0; i < 16; i++)
+ {
+ ret.m[i] = (F32) src[i];
+ }
+ return ret;
+}
+
+glh::matrix4f glh_get_current_modelview()
+{
+ return glh_copy_matrix(gGLModelView);
+}
+
+glh::matrix4f glh_get_current_projection()
+{
+ return glh_copy_matrix(gGLProjection);
+}
+
+void glh_copy_matrix(const glh::matrix4f& src, GLdouble* dst)
+{
+ for (U32 i = 0; i < 16; i++)
+ {
+ dst[i] = src.m[i];
+ }
+}
+
+void glh_set_current_modelview(const glh::matrix4f& mat)
+{
+ glh_copy_matrix(mat, gGLModelView);
+}
+
+void glh_set_current_projection(glh::matrix4f& mat)
+{
+ glh_copy_matrix(mat, gGLProjection);
+}
+
+glh::matrix4f gl_ortho(GLfloat left, GLfloat right, GLfloat bottom, GLfloat top, GLfloat znear, GLfloat zfar)
+{
+ glh::matrix4f ret(
+ 2.f/(right-left), 0.f, 0.f, -(right+left)/(right-left),
+ 0.f, 2.f/(top-bottom), 0.f, -(top+bottom)/(top-bottom),
+ 0.f, 0.f, -2.f/(zfar-znear), -(zfar+znear)/(zfar-znear),
+ 0.f, 0.f, 0.f, 1.f);
+
+ return ret;
+}
+
+void display_update_camera();
+//----------------------------------------
+
+S32 LLPipeline::sCompiles = 0;
+
+BOOL LLPipeline::sPickAvatar = TRUE;
+BOOL LLPipeline::sDynamicLOD = TRUE;
+BOOL LLPipeline::sShowHUDAttachments = TRUE;
+BOOL LLPipeline::sRenderPhysicalBeacons = TRUE;
+BOOL LLPipeline::sRenderScriptedBeacons = FALSE;
+BOOL LLPipeline::sRenderScriptedTouchBeacons = TRUE;
+BOOL LLPipeline::sRenderParticleBeacons = FALSE;
+BOOL LLPipeline::sRenderSoundBeacons = FALSE;
+BOOL LLPipeline::sRenderBeacons = FALSE;
+BOOL LLPipeline::sRenderHighlight = TRUE;
+BOOL LLPipeline::sForceOldBakedUpload = FALSE;
+S32 LLPipeline::sUseOcclusion = 0;
+BOOL LLPipeline::sDelayVBUpdate = TRUE;
+BOOL LLPipeline::sAutoMaskAlphaDeferred = TRUE;
+BOOL LLPipeline::sAutoMaskAlphaNonDeferred = FALSE;
+BOOL LLPipeline::sDisableShaders = FALSE;
+BOOL LLPipeline::sRenderBump = TRUE;
+BOOL LLPipeline::sUseTriStrips = TRUE;
+BOOL LLPipeline::sUseFarClip = TRUE;
+BOOL LLPipeline::sShadowRender = FALSE;
+BOOL LLPipeline::sWaterReflections = FALSE;
+BOOL LLPipeline::sRenderGlow = FALSE;
+BOOL LLPipeline::sReflectionRender = FALSE;
+BOOL LLPipeline::sImpostorRender = FALSE;
+BOOL LLPipeline::sUnderWaterRender = FALSE;
+BOOL LLPipeline::sTextureBindTest = FALSE;
+BOOL LLPipeline::sRenderFrameTest = FALSE;
+BOOL LLPipeline::sRenderAttachedLights = TRUE;
+BOOL LLPipeline::sRenderAttachedParticles = TRUE;
+BOOL LLPipeline::sRenderDeferred = FALSE;
+BOOL LLPipeline::sAllowRebuildPriorityGroup = FALSE ;
+S32 LLPipeline::sVisibleLightCount = 0;
+F32 LLPipeline::sMinRenderSize = 0.f;
+
+
+static LLCullResult* sCull = NULL;
+
+static const U32 gl_cube_face[] =
+{
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,
+};
+
+void validate_framebuffer_object();
+
+
+void addDeferredAttachments(LLRenderTarget& target)
+{
+ target.addColorAttachment(GL_RGBA); //specular
+ target.addColorAttachment(GL_RGBA); //normal+z
+}
+
+LLPipeline::LLPipeline() :
+ mBackfaceCull(FALSE),
+ mBatchCount(0),
+ mMatrixOpCount(0),
+ mTextureMatrixOps(0),
+ mMaxBatchSize(0),
+ mMinBatchSize(0),
+ mMeanBatchSize(0),
+ mTrianglesDrawn(0),
+ mNumVisibleNodes(0),
+ mVerticesRelit(0),
+ mLightingChanges(0),
+ mGeometryChanges(0),
+ mNumVisibleFaces(0),
+
+ mInitialized(FALSE),
+ mVertexShadersEnabled(FALSE),
+ mVertexShadersLoaded(0),
+ mRenderDebugFeatureMask(0),
+ mRenderDebugMask(0),
+ mOldRenderDebugMask(0),
+ mLastRebuildPool(NULL),
+ mAlphaPool(NULL),
+ mSkyPool(NULL),
+ mTerrainPool(NULL),
+ mWaterPool(NULL),
+ mGroundPool(NULL),
+ mSimplePool(NULL),
+ mFullbrightPool(NULL),
+ mInvisiblePool(NULL),
+ mGlowPool(NULL),
+ mBumpPool(NULL),
+ mWLSkyPool(NULL),
+ mLightMask(0),
+ mLightMovingMask(0),
+ mLightingDetail(0),
+ mScreenWidth(0),
+ mScreenHeight(0)
+{
+ mNoiseMap = 0;
+ mTrueNoiseMap = 0;
+ mLightFunc = 0;
+}
+
+void LLPipeline::init()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_INIT);
+
+ sDynamicLOD = gSavedSettings.getBOOL("RenderDynamicLOD");
+ sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
+ sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
+ LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+ sRenderAttachedLights = gSavedSettings.getBOOL("RenderAttachedLights");
+ sRenderAttachedParticles = gSavedSettings.getBOOL("RenderAttachedParticles");
+
+ mInitialized = TRUE;
+
+ stop_glerror();
+
+ //create render pass pools
+ getPool(LLDrawPool::POOL_ALPHA);
+ getPool(LLDrawPool::POOL_SIMPLE);
+ getPool(LLDrawPool::POOL_GRASS);
+ getPool(LLDrawPool::POOL_FULLBRIGHT);
+ getPool(LLDrawPool::POOL_INVISIBLE);
+ getPool(LLDrawPool::POOL_BUMP);
+ getPool(LLDrawPool::POOL_GLOW);
+
+ LLViewerStats::getInstance()->mTrianglesDrawnStat.reset();
+ resetFrameStats();
+
+ for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
+ {
+ mRenderTypeEnabled[i] = TRUE; //all rendering types start enabled
+ }
+
+ mRenderDebugFeatureMask = 0xffffffff; // All debugging features on
+ mRenderDebugMask = 0; // All debug starts off
+
+ // Don't turn on ground when this is set
+ // Mac Books with intel 950s need this
+ if(!gSavedSettings.getBOOL("RenderGround"))
+ {
+ toggleRenderType(RENDER_TYPE_GROUND);
+ }
+
+ mOldRenderDebugMask = mRenderDebugMask;
+
+ mBackfaceCull = TRUE;
+
+ stop_glerror();
+
+ // Enable features
+
+ LLViewerShaderMgr::instance()->setShaders();
+
+ stop_glerror();
+
+ for (U32 i = 0; i < 2; ++i)
+ {
+ mSpotLightFade[i] = 1.f;
+ }
+
+ setLightingDetail(-1);
+}
+
+LLPipeline::~LLPipeline()
+{
+
+}
+
+void LLPipeline::cleanup()
+{
+ assertInitialized();
+
+ mGroupQ1.clear() ;
+ mGroupQ2.clear() ;
+
+ for(pool_set_t::iterator iter = mPools.begin();
+ iter != mPools.end(); )
+ {
+ pool_set_t::iterator curiter = iter++;
+ LLDrawPool* poolp = *curiter;
+ if (poolp->isFacePool())
+ {
+ LLFacePool* face_pool = (LLFacePool*) poolp;
+ if (face_pool->mReferences.empty())
+ {
+ mPools.erase(curiter);
+ removeFromQuickLookup( poolp );
+ delete poolp;
+ }
+ }
+ else
+ {
+ mPools.erase(curiter);
+ removeFromQuickLookup( poolp );
+ delete poolp;
+ }
+ }
+
+ if (!mTerrainPools.empty())
+ {
+ llwarns << "Terrain Pools not cleaned up" << llendl;
+ }
+ if (!mTreePools.empty())
+ {
+ llwarns << "Tree Pools not cleaned up" << llendl;
+ }
+
+ delete mAlphaPool;
+ mAlphaPool = NULL;
+ delete mSkyPool;
+ mSkyPool = NULL;
+ delete mTerrainPool;
+ mTerrainPool = NULL;
+ delete mWaterPool;
+ mWaterPool = NULL;
+ delete mGroundPool;
+ mGroundPool = NULL;
+ delete mSimplePool;
+ mSimplePool = NULL;
+ delete mFullbrightPool;
+ mFullbrightPool = NULL;
+ delete mInvisiblePool;
+ mInvisiblePool = NULL;
+ delete mGlowPool;
+ mGlowPool = NULL;
+ delete mBumpPool;
+ mBumpPool = NULL;
+ // don't delete wl sky pool it was handled above in the for loop
+ //delete mWLSkyPool;
+ mWLSkyPool = NULL;
+
+ releaseGLBuffers();
+
+ mFaceSelectImagep = NULL;
+
+ mMovedBridge.clear();
+
+ mInitialized = FALSE;
+}
+
+//============================================================================
+
+void LLPipeline::destroyGL()
+{
+ stop_glerror();
+ unloadShaders();
+ mHighlightFaces.clear();
+
+ resetDrawOrders();
+
+ resetVertexBuffers();
+
+ releaseGLBuffers();
+
+ if (LLVertexBuffer::sEnableVBOs)
+ {
+ // render 30 frames after switching to work around DEV-5361
+ sDelayedVBOEnable = 30;
+ LLVertexBuffer::sEnableVBOs = FALSE;
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_RESIZE_SCREEN_TEXTURE("Resize Screen Texture");
+
+void LLPipeline::resizeScreenTexture()
+{
+ LLFastTimer ft(FTM_RESIZE_SCREEN_TEXTURE);
+ if (gPipeline.canUseVertexShaders() && assertInitialized())
+ {
+ GLuint resX = gViewerWindow->getWorldViewWidthRaw();
+ GLuint resY = gViewerWindow->getWorldViewHeightRaw();
+
+ allocateScreenBuffer(resX,resY);
+ }
+}
+
+void LLPipeline::allocateScreenBuffer(U32 resX, U32 resY)
+{
+ // remember these dimensions
+ mScreenWidth = resX;
+ mScreenHeight = resY;
+
+ //never use more than 4 samples for render targets
+ U32 samples = llmin(gSavedSettings.getU32("RenderFSAASamples"), (U32) 4);
+ U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
+
+ if (res_mod > 1 && res_mod < resX && res_mod < resY)
+ {
+ resX /= res_mod;
+ resY /= res_mod;
+ }
+
+ if (gSavedSettings.getBOOL("RenderUIBuffer"))
+ {
+ mUIScreen.allocate(resX,resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ //allocate deferred rendering color buffers
+ mDeferredScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ mDeferredDepth.allocate(resX, resY, 0, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ addDeferredAttachments(mDeferredScreen);
+
+ mScreen.allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ mEdgeMap.allocate(resX, resY, GL_ALPHA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ mDeferredLight[i].allocate(resX, resY, GL_RGBA, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ }
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ mGIMapPost[i].allocate(resX,resY, GL_RGB, FALSE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ }
+
+ F32 scale = gSavedSettings.getF32("RenderShadowResolutionScale");
+
+ //HACK: make alpha masking work on ATI depth shadows (work around for ATI driver bug)
+ U32 shadow_fmt = gGLManager.mIsATI ? GL_ALPHA : 0;
+
+ for (U32 i = 0; i < 4; i++)
+ {
+ mShadow[i].allocate(U32(resX*scale),U32(resY*scale), shadow_fmt, TRUE, FALSE, LLTexUnit::TT_RECT_TEXTURE);
+ }
+
+
+ U32 width = nhpo2(U32(resX*scale))/2;
+ U32 height = width;
+
+ for (U32 i = 4; i < 6; i++)
+ {
+ mShadow[i].allocate(width, height, shadow_fmt, TRUE, FALSE);
+ }
+
+ width = nhpo2(resX)/2;
+ height = nhpo2(resY)/2;
+ mLuminanceMap.allocate(width,height, GL_RGBA, FALSE, FALSE);
+ }
+ else
+ {
+ mScreen.allocate(resX, resY, GL_RGBA, TRUE, TRUE, LLTexUnit::TT_RECT_TEXTURE, FALSE);
+ }
+
+
+ if (LLRenderTarget::sUseFBO && gGLManager.mHasFramebufferMultisample && samples > 1)
+ {
+ mSampleBuffer.allocate(resX,resY,GL_RGBA,TRUE,TRUE,LLTexUnit::TT_RECT_TEXTURE,FALSE,samples);
+ if (LLPipeline::sRenderDeferred)
+ {
+ addDeferredAttachments(mSampleBuffer);
+ mDeferredScreen.setSampleBuffer(&mSampleBuffer);
+ }
+
+ mScreen.setSampleBuffer(&mSampleBuffer);
+
+ stop_glerror();
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ { //share depth buffer between deferred targets
+ mDeferredScreen.shareDepthBuffer(mScreen);
+ for (U32 i = 0; i < 3; i++)
+ { //share stencil buffer with screen space lightmap to stencil out sky
+ mDeferredScreen.shareDepthBuffer(mDeferredLight[i]);
+ }
+ }
+
+ gGL.getTexUnit(0)->disable();
+
+ stop_glerror();
+
+}
+
+//static
+void LLPipeline::updateRenderDeferred()
+{
+ BOOL deferred = ((gSavedSettings.getBOOL("RenderDeferred") &&
+ LLRenderTarget::sUseFBO &&
+ LLFeatureManager::getInstance()->isFeatureAvailable("RenderDeferred") &&
+ gSavedSettings.getBOOL("VertexShaderEnable") &&
+ gSavedSettings.getBOOL("RenderAvatarVP") &&
+ gSavedSettings.getBOOL("WindLightUseAtmosShaders")) ? TRUE : FALSE) &&
+ !gUseWireframe;
+
+ sRenderDeferred = deferred;
+}
+
+void LLPipeline::releaseGLBuffers()
+{
+ assertInitialized();
+
+ if (mNoiseMap)
+ {
+ LLImageGL::deleteTextures(1, &mNoiseMap);
+ mNoiseMap = 0;
+ }
+
+ if (mTrueNoiseMap)
+ {
+ LLImageGL::deleteTextures(1, &mTrueNoiseMap);
+ mTrueNoiseMap = 0;
+ }
+
+ if (mLightFunc)
+ {
+ LLImageGL::deleteTextures(1, &mLightFunc);
+ mLightFunc = 0;
+ }
+
+ mWaterRef.release();
+ mWaterDis.release();
+ mScreen.release();
+ mUIScreen.release();
+ mSampleBuffer.releaseSampleBuffer();
+ mDeferredScreen.release();
+ mDeferredDepth.release();
+ for (U32 i = 0; i < 3; i++)
+ {
+ mDeferredLight[i].release();
+ }
+
+ mEdgeMap.release();
+ mGIMap.release();
+ mGIMapPost[0].release();
+ mGIMapPost[1].release();
+ mHighlight.release();
+ mLuminanceMap.release();
+
+ for (U32 i = 0; i < 6; i++)
+ {
+ mShadow[i].release();
+ }
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ mGlow[i].release();
+ }
+
+ LLVOAvatar::resetImpostors();
+}
+
+void LLPipeline::createGLBuffers()
+{
+ LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_CREATE_BUFFERS);
+ assertInitialized();
+
+ updateRenderDeferred();
+
+ if (LLPipeline::sWaterReflections)
+ { //water reflection texture
+ U32 res = (U32) gSavedSettings.getS32("RenderWaterRefResolution");
+
+ mWaterRef.allocate(res,res,GL_RGBA,TRUE,FALSE);
+ mWaterDis.allocate(res,res,GL_RGBA,TRUE,FALSE);
+ }
+
+ mHighlight.allocate(256,256,GL_RGBA, FALSE, FALSE);
+
+ stop_glerror();
+
+ GLuint resX = gViewerWindow->getWorldViewWidthRaw();
+ GLuint resY = gViewerWindow->getWorldViewHeightRaw();
+
+ if (LLPipeline::sRenderGlow)
+ { //screen space glow buffers
+ const U32 glow_res = llmax(1,
+ llmin(512, 1 << gSavedSettings.getS32("RenderGlowResolutionPow")));
+
+ for (U32 i = 0; i < 3; i++)
+ {
+ mGlow[i].allocate(512,glow_res,GL_RGBA,FALSE,FALSE);
+ }
+
+ allocateScreenBuffer(resX,resY);
+ mScreenWidth = 0;
+ mScreenHeight = 0;
+
+ }
+
+ if (sRenderDeferred)
+ {
+ if (!mNoiseMap)
+ {
+ const U32 noiseRes = 128;
+ LLVector3 noise[noiseRes*noiseRes];
+
+ F32 scaler = gSavedSettings.getF32("RenderDeferredNoise")/100.f;
+ for (U32 i = 0; i < noiseRes*noiseRes; ++i)
+ {
+ noise[i] = LLVector3(ll_frand()-0.5f, ll_frand()-0.5f, 0.f);
+ noise[i].normVec();
+ noise[i].mV[2] = ll_frand()*scaler+1.f-scaler/2.f;
+ }
+
+ LLImageGL::generateTextures(1, &mNoiseMap);
+
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mNoiseMap);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB, GL_FLOAT, noise);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ if (!mTrueNoiseMap)
+ {
+ const U32 noiseRes = 128;
+ F32 noise[noiseRes*noiseRes*3];
+ for (U32 i = 0; i < noiseRes*noiseRes*3; i++)
+ {
+ noise[i] = ll_frand()*2.0-1.0;
+ }
+
+ LLImageGL::generateTextures(1, &mTrueNoiseMap);
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mTrueNoiseMap);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_RGB16F_ARB, noiseRes, noiseRes, GL_RGB,GL_FLOAT, noise);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ if (!mLightFunc)
+ {
+ U32 lightResX = gSavedSettings.getU32("RenderSpecularResX");
+ U32 lightResY = gSavedSettings.getU32("RenderSpecularResY");
+ U8* lg = new U8[lightResX*lightResY];
+
+ for (U32 y = 0; y < lightResY; ++y)
+ {
+ for (U32 x = 0; x < lightResX; ++x)
+ {
+ //spec func
+ F32 sa = (F32) x/(lightResX-1);
+ F32 spec = (F32) y/(lightResY-1);
+ //lg[y*lightResX+x] = (U8) (powf(sa, 128.f*spec*spec)*255);
+
+ //F32 sp = acosf(sa)/(1.f-spec);
+
+ sa = powf(sa, gSavedSettings.getF32("RenderSpecularExponent"));
+ F32 a = acosf(sa*0.25f+0.75f);
+ F32 m = llmax(0.5f-spec*0.5f, 0.001f);
+ F32 t2 = tanf(a)/m;
+ t2 *= t2;
+
+ F32 c4a = (3.f+4.f*cosf(2.f*a)+cosf(4.f*a))/8.f;
+ F32 bd = 1.f/(4.f*m*m*c4a)*powf(F_E, -t2);
+
+ lg[y*lightResX+x] = (U8) (llclamp(bd, 0.f, 1.f)*255);
+ }
+ }
+
+ LLImageGL::generateTextures(1, &mLightFunc);
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
+ LLImageGL::setManualImage(LLTexUnit::getInternalType(LLTexUnit::TT_TEXTURE), 0, GL_ALPHA, lightResX, lightResY, GL_ALPHA, GL_UNSIGNED_BYTE, lg);
+ gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
+
+ delete [] lg;
+ }
+
+ if (gSavedSettings.getBOOL("RenderDeferredGI"))
+ {
+ mGIMap.allocate(512,512,GL_RGBA, TRUE, FALSE);
+ addDeferredAttachments(mGIMap);
+ }
+ }
+}
+
+void LLPipeline::restoreGL()
+{
+ LLMemType mt_cb(LLMemType::MTYPE_PIPELINE_RESTORE_GL);
+ assertInitialized();
+
+ if (mVertexShadersEnabled)
+ {
+ LLViewerShaderMgr::instance()->setShaders();
+ }
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->restoreGL();
+ }
+ }
+ }
+}
+
+
+BOOL LLPipeline::canUseVertexShaders()
+{
+ if (sDisableShaders ||
+ !gGLManager.mHasVertexShader ||
+ !gGLManager.mHasFragmentShader ||
+ !LLFeatureManager::getInstance()->isFeatureAvailable("VertexShaderEnable") ||
+ (assertInitialized() && mVertexShadersLoaded != 1) )
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+BOOL LLPipeline::canUseWindLightShaders() const
+{
+ return (!LLPipeline::sDisableShaders &&
+ gWLSkyProgram.mProgramObject != 0 &&
+ LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_WINDLIGHT) > 1);
+}
+
+BOOL LLPipeline::canUseWindLightShadersOnObjects() const
+{
+ return (canUseWindLightShaders()
+ && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_OBJECT) > 0);
+}
+
+BOOL LLPipeline::canUseAntiAliasing() const
+{
+ return TRUE; //(gSavedSettings.getBOOL("RenderUseFBO"));
+}
+
+void LLPipeline::unloadShaders()
+{
+ LLMemType mt_us(LLMemType::MTYPE_PIPELINE_UNLOAD_SHADERS);
+ LLViewerShaderMgr::instance()->unloadShaders();
+
+ mVertexShadersLoaded = 0;
+}
+
+void LLPipeline::assertInitializedDoError()
+{
+ llerrs << "LLPipeline used when uninitialized." << llendl;
+}
+
+//============================================================================
+
+void LLPipeline::enableShadows(const BOOL enable_shadows)
+{
+ //should probably do something here to wrangle shadows....
+}
+
+S32 LLPipeline::getMaxLightingDetail() const
+{
+ /*if (mVertexShaderLevel[SHADER_OBJECT] >= LLDrawPoolSimple::SHADER_LEVEL_LOCAL_LIGHTS)
+ {
+ return 3;
+ }
+ else*/
+ {
+ return 1;
+ }
+}
+
+S32 LLPipeline::setLightingDetail(S32 level)
+{
+ LLMemType mt_ld(LLMemType::MTYPE_PIPELINE_LIGHTING_DETAIL);
+ assertInitialized();
+
+ if (level < 0)
+ {
+ if (gSavedSettings.getBOOL("VertexShaderEnable"))
+ {
+ level = 1;
+ }
+ else
+ {
+ level = 0;
+ }
+ }
+ level = llclamp(level, 0, getMaxLightingDetail());
+ if (level != mLightingDetail)
+ {
+ mLightingDetail = level;
+
+ if (mVertexShadersLoaded == 1)
+ {
+ LLViewerShaderMgr::instance()->setShaders();
+ }
+ }
+ return mLightingDetail;
+}
+
+class LLOctreeDirtyTexture : public LLOctreeTraveler<LLDrawable>
+{
+public:
+ const std::set<LLViewerFetchedTexture*>& mTextures;
+
+ LLOctreeDirtyTexture(const std::set<LLViewerFetchedTexture*>& textures) : mTextures(textures) { }
+
+ virtual void visit(const LLOctreeNode<LLDrawable>* node)
+ {
+ LLSpatialGroup* group = (LLSpatialGroup*) node->getListener(0);
+
+ if (!group->isState(LLSpatialGroup::GEOM_DIRTY) && !group->getData().empty())
+ {
+ for (LLSpatialGroup::draw_map_t::iterator i = group->mDrawMap.begin(); i != group->mDrawMap.end(); ++i)
+ {
+ for (LLSpatialGroup::drawmap_elem_t::iterator j = i->second.begin(); j != i->second.end(); ++j)
+ {
+ LLDrawInfo* params = *j;
+ LLViewerFetchedTexture* tex = LLViewerTextureManager::staticCastToFetchedTexture(params->mTexture);
+ if (tex && mTextures.find(tex) != mTextures.end())
+ {
+ group->setState(LLSpatialGroup::GEOM_DIRTY);
+ }
+ }
+ }
+ }
+
+ for (LLSpatialGroup::bridge_list_t::iterator i = group->mBridgeList.begin(); i != group->mBridgeList.end(); ++i)
+ {
+ LLSpatialBridge* bridge = *i;
+ traverse(bridge->mOctree);
+ }
+ }
+};
+
+// Called when a texture changes # of channels (causes faces to move to alpha pool)
+void LLPipeline::dirtyPoolObjectTextures(const std::set<LLViewerFetchedTexture*>& textures)
+{
+ assertInitialized();
+
+ // *TODO: This is inefficient and causes frame spikes; need a better way to do this
+ // Most of the time is spent in dirty.traverse.
+
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (poolp->isFacePool())
+ {
+ ((LLFacePool*) poolp)->dirtyTextures(textures);
+ }
+ }
+
+ LLOctreeDirtyTexture dirty(textures);
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ dirty.traverse(part->mOctree);
+ }
+ }
+ }
+}
+
+LLDrawPool *LLPipeline::findPool(const U32 type, LLViewerTexture *tex0)
+{
+ assertInitialized();
+
+ LLDrawPool *poolp = NULL;
+ switch( type )
+ {
+ case LLDrawPool::POOL_SIMPLE:
+ poolp = mSimplePool;
+ break;
+
+ case LLDrawPool::POOL_GRASS:
+ poolp = mGrassPool;
+ break;
+
+ case LLDrawPool::POOL_FULLBRIGHT:
+ poolp = mFullbrightPool;
+ break;
+
+ case LLDrawPool::POOL_INVISIBLE:
+ poolp = mInvisiblePool;
+ break;
+
+ case LLDrawPool::POOL_GLOW:
+ poolp = mGlowPool;
+ break;
+
+ case LLDrawPool::POOL_TREE:
+ poolp = get_if_there(mTreePools, (uintptr_t)tex0, (LLDrawPool*)0 );
+ break;
+
+ case LLDrawPool::POOL_TERRAIN:
+ poolp = get_if_there(mTerrainPools, (uintptr_t)tex0, (LLDrawPool*)0 );
+ break;
+
+ case LLDrawPool::POOL_BUMP:
+ poolp = mBumpPool;
+ break;
+
+ case LLDrawPool::POOL_ALPHA:
+ poolp = mAlphaPool;
+ break;
+
+ case LLDrawPool::POOL_AVATAR:
+ break; // Do nothing
+
+ case LLDrawPool::POOL_SKY:
+ poolp = mSkyPool;
+ break;
+
+ case LLDrawPool::POOL_WATER:
+ poolp = mWaterPool;
+ break;
+
+ case LLDrawPool::POOL_GROUND:
+ poolp = mGroundPool;
+ break;
+
+ case LLDrawPool::POOL_WL_SKY:
+ poolp = mWLSkyPool;
+ break;
+
+ default:
+ llassert(0);
+ llerrs << "Invalid Pool Type in LLPipeline::findPool() type=" << type << llendl;
+ break;
+ }
+
+ return poolp;
+}
+
+
+LLDrawPool *LLPipeline::getPool(const U32 type, LLViewerTexture *tex0)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+ LLDrawPool *poolp = findPool(type, tex0);
+ if (poolp)
+ {
+ return poolp;
+ }
+
+ LLDrawPool *new_poolp = LLDrawPool::createPool(type, tex0);
+ addPool( new_poolp );
+
+ return new_poolp;
+}
+
+
+// static
+LLDrawPool* LLPipeline::getPoolFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+ U32 type = getPoolTypeFromTE(te, imagep);
+ return gPipeline.getPool(type, imagep);
+}
+
+//static
+U32 LLPipeline::getPoolTypeFromTE(const LLTextureEntry* te, LLViewerTexture* imagep)
+{
+ LLMemType mt_gpt(LLMemType::MTYPE_PIPELINE_GET_POOL_TYPE);
+
+ if (!te || !imagep)
+ {
+ return 0;
+ }
+
+ bool alpha = te->getColor().mV[3] < 0.999f;
+ if (imagep)
+ {
+ alpha = alpha || (imagep->getComponents() == 4 && imagep->getType() != LLViewerTexture::MEDIA_TEXTURE) || (imagep->getComponents() == 2);
+ }
+
+ if (alpha)
+ {
+ return LLDrawPool::POOL_ALPHA;
+ }
+ else if ((te->getBumpmap() || te->getShiny()))
+ {
+ return LLDrawPool::POOL_BUMP;
+ }
+ else
+ {
+ return LLDrawPool::POOL_SIMPLE;
+ }
+}
+
+
+void LLPipeline::addPool(LLDrawPool *new_poolp)
+{
+ LLMemType mt_a(LLMemType::MTYPE_PIPELINE_ADD_POOL);
+ assertInitialized();
+ mPools.insert(new_poolp);
+ addToQuickLookup( new_poolp );
+}
+
+void LLPipeline::allocDrawable(LLViewerObject *vobj)
+{
+ LLMemType mt_ad(LLMemType::MTYPE_PIPELINE_ALLOCATE_DRAWABLE);
+ LLDrawable *drawable = new LLDrawable();
+ vobj->mDrawable = drawable;
+
+ drawable->mVObjp = vobj;
+
+ //encompass completely sheared objects by taking
+ //the most extreme point possible (<1,1,0.5>)
+ drawable->setRadius(LLVector3(1,1,0.5f).scaleVec(vobj->getScale()).length());
+ if (vobj->isOrphaned())
+ {
+ drawable->setState(LLDrawable::FORCE_INVISIBLE);
+ }
+ drawable->updateXform(TRUE);
+}
+
+
+void LLPipeline::unlinkDrawable(LLDrawable *drawable)
+{
+ LLFastTimer t(FTM_PIPELINE);
+
+ assertInitialized();
+
+ LLPointer<LLDrawable> drawablep = drawable; // make sure this doesn't get deleted before we are done
+
+ // Based on flags, remove the drawable from the queues that it's on.
+ if (drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ LLDrawable::drawable_vector_t::iterator iter = std::find(mMovedList.begin(), mMovedList.end(), drawablep);
+ if (iter != mMovedList.end())
+ {
+ mMovedList.erase(iter);
+ }
+ }
+
+ if (drawablep->getSpatialGroup())
+ {
+ if (!drawablep->getSpatialGroup()->mSpatialPartition->remove(drawablep, drawablep->getSpatialGroup()))
+ {
+#ifdef LL_RELEASE_FOR_DOWNLOAD
+ llwarns << "Couldn't remove object from spatial group!" << llendl;
+#else
+ llerrs << "Couldn't remove object from spatial group!" << llendl;
+#endif
+ }
+ }
+
+ mLights.erase(drawablep);
+ for (light_set_t::iterator iter = mNearbyLights.begin();
+ iter != mNearbyLights.end(); iter++)
+ {
+ if (iter->drawable == drawablep)
+ {
+ mNearbyLights.erase(iter);
+ break;
+ }
+ }
+
+ {
+ HighlightItem item(drawablep);
+ mHighlightSet.erase(item);
+
+ if (mHighlightObject == drawablep)
+ {
+ mHighlightObject = NULL;
+ }
+ }
+
+ for (U32 i = 0; i < 2; ++i)
+ {
+ if (mShadowSpotLight[i] == drawablep)
+ {
+ mShadowSpotLight[i] = NULL;
+ }
+
+ if (mTargetShadowSpotLight[i] == drawablep)
+ {
+ mTargetShadowSpotLight[i] = NULL;
+ }
+ }
+
+
+}
+
+U32 LLPipeline::addObject(LLViewerObject *vobj)
+{
+ LLMemType mt_ao(LLMemType::MTYPE_PIPELINE_ADD_OBJECT);
+ if (gNoRender)
+ {
+ return 0;
+ }
+
+ if (gSavedSettings.getBOOL("RenderDelayCreation"))
+ {
+ mCreateQ.push_back(vobj);
+ }
+ else
+ {
+ createObject(vobj);
+ }
+
+ return 1;
+}
+
+void LLPipeline::createObjects(F32 max_dtime)
+{
+ LLFastTimer ftm(FTM_GEO_UPDATE);
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_CREATE_OBJECTS);
+
+ LLTimer update_timer;
+
+ while (!mCreateQ.empty() && update_timer.getElapsedTimeF32() < max_dtime)
+ {
+ LLViewerObject* vobj = mCreateQ.front();
+ if (!vobj->isDead())
+ {
+ createObject(vobj);
+ }
+ mCreateQ.pop_front();
+ }
+
+ //for (LLViewerObject::vobj_list_t::iterator iter = mCreateQ.begin(); iter != mCreateQ.end(); ++iter)
+ //{
+ // createObject(*iter);
+ //}
+
+ //mCreateQ.clear();
+}
+
+void LLPipeline::createObject(LLViewerObject* vobj)
+{
+ LLDrawable* drawablep = vobj->mDrawable;
+
+ if (!drawablep)
+ {
+ drawablep = vobj->createDrawable(this);
+ }
+ else
+ {
+ llerrs << "Redundant drawable creation!" << llendl;
+ }
+
+ llassert(drawablep);
+
+ if (vobj->getParent())
+ {
+ vobj->setDrawableParent(((LLViewerObject*)vobj->getParent())->mDrawable); // LLPipeline::addObject 1
+ }
+ else
+ {
+ vobj->setDrawableParent(NULL); // LLPipeline::addObject 2
+ }
+
+ markRebuild(drawablep, LLDrawable::REBUILD_ALL, TRUE);
+
+ if (drawablep->getVOVolume() && gSavedSettings.getBOOL("RenderAnimateRes"))
+ {
+ // fun animated res
+ drawablep->updateXform(TRUE);
+ drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
+ drawablep->setScale(LLVector3(0,0,0));
+ drawablep->makeActive();
+ }
+}
+
+
+void LLPipeline::resetFrameStats()
+{
+ assertInitialized();
+
+ LLViewerStats::getInstance()->mTrianglesDrawnStat.addValue(mTrianglesDrawn/1000.f);
+
+ if (mBatchCount > 0)
+ {
+ mMeanBatchSize = gPipeline.mTrianglesDrawn/gPipeline.mBatchCount;
+ }
+ mTrianglesDrawn = 0;
+ sCompiles = 0;
+ mVerticesRelit = 0;
+ mLightingChanges = 0;
+ mGeometryChanges = 0;
+ mNumVisibleFaces = 0;
+
+ if (mOldRenderDebugMask != mRenderDebugMask)
+ {
+ gObjectList.clearDebugText();
+ mOldRenderDebugMask = mRenderDebugMask;
+ }
+
+}
+
+//external functions for asynchronous updating
+void LLPipeline::updateMoveDampedAsync(LLDrawable* drawablep)
+{
+ if (gSavedSettings.getBOOL("FreezeTime"))
+ {
+ return;
+ }
+ if (!drawablep)
+ {
+ llerrs << "updateMove called with NULL drawablep" << llendl;
+ return;
+ }
+ if (drawablep->isState(LLDrawable::EARLY_MOVE))
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ // update drawable now
+ drawablep->clearState(LLDrawable::MOVE_UNDAMPED); // force to DAMPED
+ drawablep->updateMove(); // returns done
+ drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
+ // Put on move list so that EARLY_MOVE gets cleared
+ if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ mMovedList.push_back(drawablep);
+ drawablep->setState(LLDrawable::ON_MOVE_LIST);
+ }
+}
+
+void LLPipeline::updateMoveNormalAsync(LLDrawable* drawablep)
+{
+ if (gSavedSettings.getBOOL("FreezeTime"))
+ {
+ return;
+ }
+ if (!drawablep)
+ {
+ llerrs << "updateMove called with NULL drawablep" << llendl;
+ return;
+ }
+ if (drawablep->isState(LLDrawable::EARLY_MOVE))
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ // update drawable now
+ drawablep->setState(LLDrawable::MOVE_UNDAMPED); // force to UNDAMPED
+ drawablep->updateMove();
+ drawablep->setState(LLDrawable::EARLY_MOVE); // flag says we already did an undamped move this frame
+ // Put on move list so that EARLY_MOVE gets cleared
+ if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ mMovedList.push_back(drawablep);
+ drawablep->setState(LLDrawable::ON_MOVE_LIST);
+ }
+}
+
+void LLPipeline::updateMovedList(LLDrawable::drawable_vector_t& moved_list)
+{
+ for (LLDrawable::drawable_vector_t::iterator iter = moved_list.begin();
+ iter != moved_list.end(); )
+ {
+ LLDrawable::drawable_vector_t::iterator curiter = iter++;
+ LLDrawable *drawablep = *curiter;
+ BOOL done = TRUE;
+ if (!drawablep->isDead() && (!drawablep->isState(LLDrawable::EARLY_MOVE)))
+ {
+ done = drawablep->updateMove();
+ }
+ drawablep->clearState(LLDrawable::EARLY_MOVE | LLDrawable::MOVE_UNDAMPED);
+ if (done)
+ {
+ drawablep->clearState(LLDrawable::ON_MOVE_LIST);
+ iter = moved_list.erase(curiter);
+ }
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_OCTREE_BALANCE("Balance Octree");
+static LLFastTimer::DeclareTimer FTM_UPDATE_MOVE("Update Move");
+
+void LLPipeline::updateMove()
+{
+ LLFastTimer t(FTM_UPDATE_MOVE);
+ LLMemType mt_um(LLMemType::MTYPE_PIPELINE_UPDATE_MOVE);
+
+ if (gSavedSettings.getBOOL("FreezeTime"))
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ {
+ static LLFastTimer::DeclareTimer ftm("Retexture");
+ LLFastTimer t(ftm);
+
+ for (LLDrawable::drawable_set_t::iterator iter = mRetexturedList.begin();
+ iter != mRetexturedList.end(); ++iter)
+ {
+ LLDrawable* drawablep = *iter;
+ if (drawablep && !drawablep->isDead())
+ {
+ drawablep->updateTexture();
+ }
+ }
+ mRetexturedList.clear();
+ }
+
+ {
+ static LLFastTimer::DeclareTimer ftm("Moved List");
+ LLFastTimer t(ftm);
+ updateMovedList(mMovedList);
+ }
+
+ //balance octrees
+ {
+ LLFastTimer ot(FTM_OCTREE_BALANCE);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->mOctree->balance();
+ }
+ }
+ }
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////
+// Culling and occlusion testing
+/////////////////////////////////////////////////////////////////////////////
+
+//static
+F32 LLPipeline::calcPixelArea(LLVector3 center, LLVector3 size, LLCamera &camera)
+{
+ LLVector3 lookAt = center - camera.getOrigin();
+ F32 dist = lookAt.length();
+
+ //ramp down distance for nearby objects
+ //shrink dist by dist/16.
+ if (dist < 16.f)
+ {
+ dist /= 16.f;
+ dist *= dist;
+ dist *= 16.f;
+ }
+
+ //get area of circle around node
+ F32 app_angle = atanf(size.length()/dist);
+ F32 radius = app_angle*LLDrawable::sCurPixelAngle;
+ return radius*radius * F_PI;
+}
+
+void LLPipeline::grabReferences(LLCullResult& result)
+{
+ sCull = &result;
+}
+
+BOOL LLPipeline::visibleObjectsInFrustum(LLCamera& camera)
+{
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ if (part->visibleObjectsInFrustum(camera))
+ {
+ return TRUE;
+ }
+ }
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+BOOL LLPipeline::getVisibleExtents(LLCamera& camera, LLVector3& min, LLVector3& max)
+{
+ const F32 X = 65536.f;
+
+ min = LLVector3(X,X,X);
+ max = LLVector3(-X,-X,-X);
+
+ U32 saved_camera_id = LLViewerCamera::sCurCameraID;
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+
+ BOOL res = TRUE;
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ if (!part->getVisibleExtents(camera, min, max))
+ {
+ res = FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ LLViewerCamera::sCurCameraID = saved_camera_id;
+
+ return res;
+}
+
+static LLFastTimer::DeclareTimer FTM_CULL("Object Culling");
+
+void LLPipeline::updateCull(LLCamera& camera, LLCullResult& result, S32 water_clip)
+{
+ LLFastTimer t(FTM_CULL);
+ LLMemType mt_uc(LLMemType::MTYPE_PIPELINE_UPDATE_CULL);
+
+ grabReferences(result);
+
+ sCull->clear();
+
+ BOOL to_texture = LLPipeline::sUseOcclusion > 1 &&
+ !hasRenderType(LLPipeline::RENDER_TYPE_HUD) &&
+ LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD &&
+ gPipeline.canUseVertexShaders() &&
+ sRenderGlow;
+
+ if (to_texture)
+ {
+ mScreen.bindTarget();
+ }
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixd(gGLLastProjection);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLLastModelView);
+
+
+ LLVertexBuffer::unbind();
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ if (sUseOcclusion > 1)
+ {
+ gGL.setColorMask(false, false);
+ }
+
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ if (water_clip != 0)
+ {
+ LLPlane plane(LLVector3(0,0, (F32) -water_clip), (F32) water_clip*region->getWaterHeight());
+ camera.setUserClipPlane(plane);
+ }
+ else
+ {
+ camera.disableUserClipPlane();
+ }
+
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ part->cull(camera);
+ }
+ }
+ }
+ }
+
+ camera.disableUserClipPlane();
+
+ if (hasRenderType(LLPipeline::RENDER_TYPE_SKY) &&
+ gSky.mVOSkyp.notNull() &&
+ gSky.mVOSkyp->mDrawable.notNull())
+ {
+ gSky.mVOSkyp->mDrawable->setVisible(camera);
+ sCull->pushDrawable(gSky.mVOSkyp->mDrawable);
+ gSky.updateCull();
+ stop_glerror();
+ }
+
+ if (hasRenderType(LLPipeline::RENDER_TYPE_GROUND) &&
+ !gPipeline.canUseWindLightShaders() &&
+ gSky.mVOGroundp.notNull() &&
+ gSky.mVOGroundp->mDrawable.notNull() &&
+ !LLPipeline::sWaterReflections)
+ {
+ gSky.mVOGroundp->mDrawable->setVisible(camera);
+ sCull->pushDrawable(gSky.mVOGroundp->mDrawable);
+ }
+
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ if (sUseOcclusion > 1)
+ {
+ gGL.setColorMask(true, false);
+ }
+
+ if (to_texture)
+ {
+ mScreen.flush();
+ }
+}
+
+void LLPipeline::markNotCulled(LLSpatialGroup* group, LLCamera& camera)
+{
+ if (group->getData().empty())
+ {
+ return;
+ }
+
+ group->setVisible();
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ group->updateDistance(camera);
+ }
+
+ const F32 MINIMUM_PIXEL_AREA = 16.f;
+
+ if (group->mPixelArea < MINIMUM_PIXEL_AREA)
+ {
+ return;
+ }
+
+ if (sMinRenderSize > 0.f &&
+ llmax(llmax(group->mBounds[1].mV[0], group->mBounds[1].mV[1]), group->mBounds[1].mV[2]) < sMinRenderSize)
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ if (!group->mSpatialPartition->mRenderByGroup)
+ { //render by drawable
+ sCull->pushDrawableGroup(group);
+ }
+ else
+ { //render by group
+ sCull->pushVisibleGroup(group);
+ }
+
+ mNumVisibleNodes++;
+}
+
+void LLPipeline::markOccluder(LLSpatialGroup* group)
+{
+ if (sUseOcclusion > 1 && group && !group->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION))
+ {
+ LLSpatialGroup* parent = group->getParent();
+
+ if (!parent || !parent->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ { //only mark top most occluders as active occlusion
+ sCull->pushOcclusionGroup(group);
+ group->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
+
+ if (parent &&
+ !parent->isOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION) &&
+ parent->getElementCount() == 0 &&
+ parent->needsUpdate())
+ {
+ sCull->pushOcclusionGroup(group);
+ parent->setOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
+ }
+ }
+ }
+}
+
+void LLPipeline::doOcclusion(LLCamera& camera)
+{
+ LLVertexBuffer::unbind();
+
+ if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_OCCLUSION))
+ {
+ gGL.setColorMask(true, false, false, false);
+ }
+ else
+ {
+ gGL.setColorMask(false, false);
+ }
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+
+ LLGLDisable cull(GL_CULL_FACE);
+ if (LLPipeline::sUseOcclusion > 1)
+ {
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginOcclusionGroups(); iter != sCull->endOcclusionGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->doOcclusion(&camera);
+ group->clearOcclusionState(LLSpatialGroup::ACTIVE_OCCLUSION);
+ }
+ }
+
+ gGL.setColorMask(true, false);
+}
+
+BOOL LLPipeline::updateDrawableGeom(LLDrawable* drawablep, BOOL priority)
+{
+ BOOL update_complete = drawablep->updateGeometry(priority);
+ if (update_complete && assertInitialized())
+ {
+ drawablep->setState(LLDrawable::BUILT);
+ mGeometryChanges++;
+ }
+ return update_complete;
+}
+
+void LLPipeline::updateGL()
+{
+ while (!LLGLUpdate::sGLQ.empty())
+ {
+ LLGLUpdate* glu = LLGLUpdate::sGLQ.front();
+ glu->updateGL();
+ glu->mInQ = FALSE;
+ LLGLUpdate::sGLQ.pop_front();
+ }
+}
+
+void LLPipeline::rebuildPriorityGroups()
+{
+ if(!sAllowRebuildPriorityGroup)
+ {
+ return ;
+ }
+ sAllowRebuildPriorityGroup = FALSE ;
+
+ LLTimer update_timer;
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+ assertInitialized();
+
+ // Iterate through all drawables on the priority build queue,
+ for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ1.begin();
+ iter != mGroupQ1.end(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->rebuildGeom();
+ group->clearState(LLSpatialGroup::IN_BUILD_Q1);
+ }
+
+ mGroupQ1.clear();
+}
+
+void LLPipeline::rebuildGroups()
+{
+ // Iterate through some drawables on the non-priority build queue
+ S32 size = (S32) mGroupQ2.size();
+ S32 min_count = llclamp((S32) ((F32) (size * size)/4096*0.25f), 1, size);
+
+ S32 count = 0;
+
+ std::sort(mGroupQ2.begin(), mGroupQ2.end(), LLSpatialGroup::CompareUpdateUrgency());
+
+ LLSpatialGroup::sg_vector_t::iterator iter;
+ for (iter = mGroupQ2.begin();
+ iter != mGroupQ2.end(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+
+ if (group->isDead())
+ {
+ continue;
+ }
+
+ group->rebuildGeom();
+
+ if (group->mSpatialPartition->mRenderByGroup)
+ {
+ count++;
+ }
+
+ group->clearState(LLSpatialGroup::IN_BUILD_Q2);
+
+ if (count > min_count)
+ {
+ ++iter;
+ break;
+ }
+ }
+
+ mGroupQ2.erase(mGroupQ2.begin(), iter);
+
+ updateMovedList(mMovedBridge);
+}
+
+void LLPipeline::updateGeom(F32 max_dtime)
+{
+ LLTimer update_timer;
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_UPDATE_GEOM);
+ LLPointer<LLDrawable> drawablep;
+
+ LLFastTimer t(FTM_GEO_UPDATE);
+
+ assertInitialized();
+
+ if (sDelayedVBOEnable > 0)
+ {
+ if (--sDelayedVBOEnable <= 0)
+ {
+ resetVertexBuffers();
+ LLVertexBuffer::sEnableVBOs = TRUE;
+ }
+ }
+
+ // notify various object types to reset internal cost metrics, etc.
+ // for now, only LLVOVolume does this to throttle LOD changes
+ LLVOVolume::preUpdateGeom();
+
+ // Iterate through all drawables on the priority build queue,
+ for (LLDrawable::drawable_list_t::iterator iter = mBuildQ1.begin();
+ iter != mBuildQ1.end();)
+ {
+ LLDrawable::drawable_list_t::iterator curiter = iter++;
+ LLDrawable* drawablep = *curiter;
+ if (drawablep && !drawablep->isDead())
+ {
+ if (drawablep->isState(LLDrawable::IN_REBUILD_Q2))
+ {
+ drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
+ LLDrawable::drawable_list_t::iterator find = std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep);
+ if (find != mBuildQ2.end())
+ {
+ mBuildQ2.erase(find);
+ }
+ }
+
+ if (updateDrawableGeom(drawablep, TRUE))
+ {
+ drawablep->clearState(LLDrawable::IN_REBUILD_Q1);
+ mBuildQ1.erase(curiter);
+ }
+ }
+ else
+ {
+ mBuildQ1.erase(curiter);
+ }
+ }
+
+ // Iterate through some drawables on the non-priority build queue
+ S32 min_count = 16;
+ S32 size = (S32) mBuildQ2.size();
+ if (size > 1024)
+ {
+ min_count = llclamp((S32) (size * (F32) size/4096), 16, size);
+ }
+
+ S32 count = 0;
+
+ max_dtime = llmax(update_timer.getElapsedTimeF32()+0.001f, max_dtime);
+ LLSpatialGroup* last_group = NULL;
+ LLSpatialBridge* last_bridge = NULL;
+
+ for (LLDrawable::drawable_list_t::iterator iter = mBuildQ2.begin();
+ iter != mBuildQ2.end(); )
+ {
+ LLDrawable::drawable_list_t::iterator curiter = iter++;
+ LLDrawable* drawablep = *curiter;
+
+ LLSpatialBridge* bridge = drawablep->isRoot() ? drawablep->getSpatialBridge() :
+ drawablep->getParent()->getSpatialBridge();
+
+ if (drawablep->getSpatialGroup() != last_group &&
+ (!last_bridge || bridge != last_bridge) &&
+ (update_timer.getElapsedTimeF32() >= max_dtime) && count > min_count)
+ {
+ break;
+ }
+
+ //make sure updates don't stop in the middle of a spatial group
+ //to avoid thrashing (objects are enqueued by group)
+ last_group = drawablep->getSpatialGroup();
+ last_bridge = bridge;
+
+ BOOL update_complete = TRUE;
+ if (!drawablep->isDead())
+ {
+ update_complete = updateDrawableGeom(drawablep, FALSE);
+ count++;
+ }
+ if (update_complete)
+ {
+ drawablep->clearState(LLDrawable::IN_REBUILD_Q2);
+ mBuildQ2.erase(curiter);
+ }
+ }
+
+ updateMovedList(mMovedBridge);
+}
+
+void LLPipeline::markVisible(LLDrawable *drawablep, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_VISIBLE);
+
+ if(drawablep && !drawablep->isDead())
+ {
+ if (drawablep->isSpatialBridge())
+ {
+ const LLDrawable* root = ((LLSpatialBridge*) drawablep)->mDrawable;
+ llassert(root); // trying to catch a bad assumption
+ if (root && // // this test may not be needed, see above
+ root->getVObj()->isAttachment())
+ {
+ LLDrawable* rootparent = root->getParent();
+ if (rootparent) // this IS sometimes NULL
+ {
+ LLViewerObject *vobj = rootparent->getVObj();
+ llassert(vobj); // trying to catch a bad assumption
+ if (vobj) // this test may not be needed, see above
+ {
+ const LLVOAvatar* av = vobj->asAvatar();
+ if (av && av->isImpostor())
+ {
+ return;
+ }
+ }
+ }
+ }
+ sCull->pushBridge((LLSpatialBridge*) drawablep);
+ }
+ else
+ {
+ sCull->pushDrawable(drawablep);
+ }
+
+ drawablep->setVisible(camera);
+ }
+}
+
+void LLPipeline::markMoved(LLDrawable *drawablep, BOOL damped_motion)
+{
+ LLMemType mt_mm(LLMemType::MTYPE_PIPELINE_MARK_MOVED);
+
+ if (!drawablep)
+ {
+ //llerrs << "Sending null drawable to moved list!" << llendl;
+ return;
+ }
+
+ if (drawablep->isDead())
+ {
+ llwarns << "Marking NULL or dead drawable moved!" << llendl;
+ return;
+ }
+
+ if (drawablep->getParent())
+ {
+ //ensure that parent drawables are moved first
+ markMoved(drawablep->getParent(), damped_motion);
+ }
+
+ assertInitialized();
+
+ if (!drawablep->isState(LLDrawable::ON_MOVE_LIST))
+ {
+ if (drawablep->isSpatialBridge())
+ {
+ mMovedBridge.push_back(drawablep);
+ }
+ else
+ {
+ mMovedList.push_back(drawablep);
+ }
+ drawablep->setState(LLDrawable::ON_MOVE_LIST);
+ }
+ if (damped_motion == FALSE)
+ {
+ drawablep->setState(LLDrawable::MOVE_UNDAMPED); // UNDAMPED trumps DAMPED
+ }
+ else if (drawablep->isState(LLDrawable::MOVE_UNDAMPED))
+ {
+ drawablep->clearState(LLDrawable::MOVE_UNDAMPED);
+ }
+}
+
+void LLPipeline::markShift(LLDrawable *drawablep)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_SHIFT);
+
+ if (!drawablep || drawablep->isDead())
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ if (!drawablep->isState(LLDrawable::ON_SHIFT_LIST))
+ {
+ drawablep->getVObj()->setChanged(LLXform::SHIFTED | LLXform::SILHOUETTE);
+ if (drawablep->getParent())
+ {
+ markShift(drawablep->getParent());
+ }
+ mShiftList.push_back(drawablep);
+ drawablep->setState(LLDrawable::ON_SHIFT_LIST);
+ }
+}
+
+void LLPipeline::shiftObjects(const LLVector3 &offset)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_SHIFT_OBJECTS);
+
+ assertInitialized();
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+ gDepthDirty = TRUE;
+
+ for (LLDrawable::drawable_vector_t::iterator iter = mShiftList.begin();
+ iter != mShiftList.end(); iter++)
+ {
+ LLDrawable *drawablep = *iter;
+ if (drawablep->isDead())
+ {
+ continue;
+ }
+ drawablep->shiftPos(offset);
+ drawablep->clearState(LLDrawable::ON_SHIFT_LIST);
+ }
+ mShiftList.resize(0);
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->shift(offset);
+ }
+ }
+ }
+
+ LLHUDText::shiftAll(offset);
+ LLHUDNameTag::shiftAll(offset);
+ display_update_camera();
+}
+
+void LLPipeline::markTextured(LLDrawable *drawablep)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_TEXTURED);
+
+ if (drawablep && !drawablep->isDead() && assertInitialized())
+ {
+ mRetexturedList.insert(drawablep);
+ }
+}
+
+void LLPipeline::markGLRebuild(LLGLUpdate* glu)
+{
+ if (glu && !glu->mInQ)
+ {
+ LLGLUpdate::sGLQ.push_back(glu);
+ glu->mInQ = TRUE;
+ }
+}
+
+void LLPipeline::markRebuild(LLSpatialGroup* group, BOOL priority)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+ //assert_main_thread();
+
+ if (group && !group->isDead() && group->mSpatialPartition)
+ {
+ if (group->mSpatialPartition->mPartitionType == LLViewerRegion::PARTITION_HUD)
+ {
+ priority = TRUE;
+ }
+
+ if (priority)
+ {
+ if (!group->isState(LLSpatialGroup::IN_BUILD_Q1))
+ {
+ mGroupQ1.push_back(group);
+ group->setState(LLSpatialGroup::IN_BUILD_Q1);
+
+ if (group->isState(LLSpatialGroup::IN_BUILD_Q2))
+ {
+ LLSpatialGroup::sg_vector_t::iterator iter = std::find(mGroupQ2.begin(), mGroupQ2.end(), group);
+ if (iter != mGroupQ2.end())
+ {
+ mGroupQ2.erase(iter);
+ }
+ group->clearState(LLSpatialGroup::IN_BUILD_Q2);
+ }
+ }
+ }
+ else if (!group->isState(LLSpatialGroup::IN_BUILD_Q2 | LLSpatialGroup::IN_BUILD_Q1))
+ {
+ //llerrs << "Non-priority updates not yet supported!" << llendl;
+ if (std::find(mGroupQ2.begin(), mGroupQ2.end(), group) != mGroupQ2.end())
+ {
+ llerrs << "WTF?" << llendl;
+ }
+ mGroupQ2.push_back(group);
+ group->setState(LLSpatialGroup::IN_BUILD_Q2);
+
+ }
+ }
+}
+
+void LLPipeline::markRebuild(LLDrawable *drawablep, LLDrawable::EDrawableFlags flag, BOOL priority)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_MARK_REBUILD);
+
+ if (drawablep && !drawablep->isDead() && assertInitialized())
+ {
+ if (!drawablep->isState(LLDrawable::BUILT))
+ {
+ priority = TRUE;
+ }
+ if (priority)
+ {
+ if (!drawablep->isState(LLDrawable::IN_REBUILD_Q1))
+ {
+ mBuildQ1.push_back(drawablep);
+ drawablep->setState(LLDrawable::IN_REBUILD_Q1); // mark drawable as being in priority queue
+ }
+ }
+ else if (!drawablep->isState(LLDrawable::IN_REBUILD_Q2))
+ {
+ mBuildQ2.push_back(drawablep);
+ drawablep->setState(LLDrawable::IN_REBUILD_Q2); // need flag here because it is just a list
+ }
+ if (flag & (LLDrawable::REBUILD_VOLUME | LLDrawable::REBUILD_POSITION))
+ {
+ drawablep->getVObj()->setChanged(LLXform::SILHOUETTE);
+ }
+ drawablep->setState(flag);
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_RESET_DRAWORDER("Reset Draw Order");
+
+void LLPipeline::stateSort(LLCamera& camera, LLCullResult &result)
+{
+ if (hasAnyRenderType(LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_TERRAIN,
+ LLPipeline::RENDER_TYPE_TREE,
+ LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::END_RENDER_TYPES))
+ {
+ //clear faces from face pools
+ LLFastTimer t(FTM_RESET_DRAWORDER);
+ gPipeline.resetDrawOrders();
+ }
+
+ LLFastTimer ftm(FTM_STATESORT);
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+
+ //LLVertexBuffer::unbind();
+
+ grabReferences(result);
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginDrawableGroups(); iter != sCull->endDrawableGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->checkOcclusion();
+ if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ markOccluder(group);
+ }
+ else
+ {
+ group->setVisible();
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ markVisible(*i, camera);
+ }
+ }
+ }
+ for (LLCullResult::sg_list_t::iterator iter = sCull->beginVisibleGroups(); iter != sCull->endVisibleGroups(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ group->checkOcclusion();
+ if (sUseOcclusion > 1 && group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ markOccluder(group);
+ }
+ else
+ {
+ group->setVisible();
+ stateSort(group, camera);
+ }
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ for (LLCullResult::bridge_list_t::iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+ {
+ LLCullResult::bridge_list_t::iterator cur_iter = i;
+ LLSpatialBridge* bridge = *cur_iter;
+ LLSpatialGroup* group = bridge->getSpatialGroup();
+ if (!bridge->isDead() && group && !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ stateSort(bridge, camera);
+ }
+ }
+ }
+ {
+ LLFastTimer ftm(FTM_STATESORT_DRAWABLE);
+ for (LLCullResult::drawable_list_t::iterator iter = sCull->beginVisibleList();
+ iter != sCull->endVisibleList(); ++iter)
+ {
+ LLDrawable *drawablep = *iter;
+ if (!drawablep->isDead())
+ {
+ stateSort(drawablep, camera);
+ }
+ }
+ }
+ {
+ LLFastTimer ftm(FTM_CLIENT_COPY);
+ LLVertexBuffer::clientCopy();
+ }
+
+ postSort(camera);
+}
+
+void LLPipeline::stateSort(LLSpatialGroup* group, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+ if (group->changeLOD())
+ {
+ for (LLSpatialGroup::element_iter i = group->getData().begin(); i != group->getData().end(); ++i)
+ {
+ LLDrawable* drawablep = *i;
+ stateSort(drawablep, camera);
+ }
+ }
+
+}
+
+void LLPipeline::stateSort(LLSpatialBridge* bridge, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+ if (!sShadowRender && bridge->getSpatialGroup()->changeLOD())
+ {
+ bool force_update = false;
+ bridge->updateDistance(camera, force_update);
+ }
+}
+
+void LLPipeline::stateSort(LLDrawable* drawablep, LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_STATE_SORT);
+
+ if (!drawablep
+ || drawablep->isDead()
+ || !hasRenderType(drawablep->getRenderType()))
+ {
+ return;
+ }
+
+ if (LLSelectMgr::getInstance()->mHideSelectedObjects)
+ {
+ if (drawablep->getVObj().notNull() &&
+ drawablep->getVObj()->isSelected())
+ {
+ return;
+ }
+ }
+
+ if (drawablep->isAvatar())
+ { //don't draw avatars beyond render distance or if we don't have a spatial group.
+ if ((drawablep->getSpatialGroup() == NULL) ||
+ (drawablep->getSpatialGroup()->mDistance > LLVOAvatar::sRenderDistance))
+ {
+ return;
+ }
+
+ LLVOAvatar* avatarp = (LLVOAvatar*) drawablep->getVObj().get();
+ if (!avatarp->isVisible())
+ {
+ return;
+ }
+ }
+
+ assertInitialized();
+
+ if (hasRenderType(drawablep->mRenderType))
+ {
+ if (!drawablep->isState(LLDrawable::INVISIBLE|LLDrawable::FORCE_INVISIBLE))
+ {
+ drawablep->setVisible(camera, NULL, FALSE);
+ }
+ else if (drawablep->isState(LLDrawable::CLEAR_INVISIBLE))
+ {
+ // clear invisible flag here to avoid single frame glitch
+ drawablep->clearState(LLDrawable::FORCE_INVISIBLE|LLDrawable::CLEAR_INVISIBLE);
+ }
+ }
+
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ LLSpatialGroup* group = drawablep->getSpatialGroup();
+ if (!group || group->changeLOD())
+ {
+ if (drawablep->isVisible())
+ {
+ if (!drawablep->isActive())
+ {
+ bool force_update = false;
+ drawablep->updateDistance(camera, force_update);
+ }
+ else if (drawablep->isAvatar())
+ {
+ bool force_update = false;
+ drawablep->updateDistance(camera, force_update); // calls vobj->updateLOD() which calls LLVOAvatar::updateVisibility()
+ }
+ }
+ }
+ }
+
+ if (!drawablep->getVOVolume())
+ {
+ for (LLDrawable::face_list_t::iterator iter = drawablep->mFaces.begin();
+ iter != drawablep->mFaces.end(); iter++)
+ {
+ LLFace* facep = *iter;
+
+ if (facep->hasGeometry())
+ {
+ if (facep->getPool())
+ {
+ facep->getPool()->enqueue(facep);
+ }
+ else
+ {
+ break;
+ }
+ }
+ }
+ }
+
+
+ mNumVisibleFaces += drawablep->getNumFaces();
+}
+
+
+void forAllDrawables(LLCullResult::sg_list_t::iterator begin,
+ LLCullResult::sg_list_t::iterator end,
+ void (*func)(LLDrawable*))
+{
+ for (LLCullResult::sg_list_t::iterator i = begin; i != end; ++i)
+ {
+ for (LLSpatialGroup::element_iter j = (*i)->getData().begin(); j != (*i)->getData().end(); ++j)
+ {
+ func(*j);
+ }
+ }
+}
+
+void LLPipeline::forAllVisibleDrawables(void (*func)(LLDrawable*))
+{
+ forAllDrawables(sCull->beginDrawableGroups(), sCull->endDrawableGroups(), func);
+ forAllDrawables(sCull->beginVisibleGroups(), sCull->endVisibleGroups(), func);
+}
+
+//function for creating scripted beacons
+void renderScriptedBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && !vobj->isAvatar()
+ && !vobj->getParent()
+ && vobj->flagScripted())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderScriptedTouchBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && !vobj->isAvatar()
+ && !vobj->getParent()
+ && vobj->flagScripted()
+ && vobj->flagHandleTouch())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(1.f, 0.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderPhysicalBeacons(LLDrawable* drawablep)
+{
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && !vobj->isAvatar()
+ //&& !vobj->getParent()
+ && vobj->usePhysics())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", LLColor4(0.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderParticleBeacons(LLDrawable* drawablep)
+{
+ // Look for attachments, objects, etc.
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj
+ && vobj->isParticleSource())
+ {
+ if (gPipeline.sRenderBeacons)
+ {
+ LLColor4 light_blue(0.5f, 0.5f, 1.f, 0.5f);
+ gObjectList.addDebugBeacon(vobj->getPositionAgent(), "", light_blue, LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void renderSoundHighlights(LLDrawable* drawablep)
+{
+ // Look for attachments, objects, etc.
+ LLViewerObject *vobj = drawablep->getVObj();
+ if (vobj && vobj->isAudioSource())
+ {
+ if (gPipeline.sRenderHighlight)
+ {
+ S32 face_id;
+ S32 count = drawablep->getNumFaces();
+ for (face_id = 0; face_id < count; face_id++)
+ {
+ gPipeline.mHighlightFaces.push_back(drawablep->getFace(face_id) );
+ }
+ }
+ }
+}
+
+void LLPipeline::postSort(LLCamera& camera)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_POST_SORT);
+ LLFastTimer ftm(FTM_STATESORT_POSTSORT);
+
+ assertInitialized();
+
+ llpushcallstacks ;
+ //rebuild drawable geometry
+ for (LLCullResult::sg_list_t::iterator i = sCull->beginDrawableGroups(); i != sCull->endDrawableGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (!sUseOcclusion ||
+ !group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ group->rebuildGeom();
+ }
+ }
+ llpushcallstacks ;
+ //rebuild groups
+ sCull->assertDrawMapsEmpty();
+
+ /*LLSpatialGroup::sNoDelete = FALSE;
+ for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (sUseOcclusion &&
+ group->isState(LLSpatialGroup::OCCLUDED))
+ {
+ continue;
+ }
+
+ group->rebuildGeom();
+ }
+ LLSpatialGroup::sNoDelete = TRUE;*/
+
+
+ rebuildPriorityGroups();
+ llpushcallstacks ;
+
+ const S32 bin_count = 1024*8;
+
+ static LLCullResult::drawinfo_list_t alpha_bins[bin_count];
+ static U32 bin_size[bin_count];
+
+ //clear one bin per frame to avoid memory bloat
+ static S32 clear_idx = 0;
+ clear_idx = (1+clear_idx)%bin_count;
+ alpha_bins[clear_idx].clear();
+
+ for (U32 j = 0; j < bin_count; j++)
+ {
+ bin_size[j] = 0;
+ }
+
+ //build render map
+ for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (sUseOcclusion &&
+ group->isOcclusionState(LLSpatialGroup::OCCLUDED))
+ {
+ continue;
+ }
+
+ if (group->isState(LLSpatialGroup::NEW_DRAWINFO) && group->isState(LLSpatialGroup::GEOM_DIRTY))
+ { //no way this group is going to be drawable without a rebuild
+ group->rebuildGeom();
+ }
+
+ for (LLSpatialGroup::draw_map_t::iterator j = group->mDrawMap.begin(); j != group->mDrawMap.end(); ++j)
+ {
+ LLSpatialGroup::drawmap_elem_t& src_vec = j->second;
+ if (!hasRenderType(j->first))
+ {
+ continue;
+ }
+
+ for (LLSpatialGroup::drawmap_elem_t::iterator k = src_vec.begin(); k != src_vec.end(); ++k)
+ {
+ if (sMinRenderSize > 0.f)
+ {
+ LLVector3 bounds = (*k)->mExtents[1]-(*k)->mExtents[0];
+ if (llmax(llmax(bounds.mV[0], bounds.mV[1]), bounds.mV[2]) > sMinRenderSize)
+ {
+ sCull->pushDrawInfo(j->first, *k);
+ }
+ }
+ else
+ {
+ sCull->pushDrawInfo(j->first, *k);
+ }
+ }
+ }
+
+ if (hasRenderType(LLPipeline::RENDER_TYPE_PASS_ALPHA))
+ {
+ LLSpatialGroup::draw_map_t::iterator alpha = group->mDrawMap.find(LLRenderPass::PASS_ALPHA);
+
+ if (alpha != group->mDrawMap.end())
+ { //store alpha groups for sorting
+ LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+ if (LLViewerCamera::sCurCameraID == LLViewerCamera::CAMERA_WORLD)
+ {
+ if (bridge)
+ {
+ LLCamera trans_camera = bridge->transformCamera(camera);
+ group->updateDistance(trans_camera);
+ }
+ else
+ {
+ group->updateDistance(camera);
+ }
+ }
+
+ if (hasRenderType(LLDrawPool::POOL_ALPHA))
+ {
+ sCull->pushAlphaGroup(group);
+ }
+ }
+ }
+ }
+
+ if (!sShadowRender)
+ {
+ //sort by texture or bump map
+ for (U32 i = 0; i < LLRenderPass::NUM_RENDER_TYPES; ++i)
+ {
+ if (i == LLRenderPass::PASS_BUMP)
+ {
+ std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareBump());
+ }
+ else
+ {
+ std::sort(sCull->beginRenderMap(i), sCull->endRenderMap(i), LLDrawInfo::CompareTexturePtrMatrix());
+ }
+ }
+
+ std::sort(sCull->beginAlphaGroups(), sCull->endAlphaGroups(), LLSpatialGroup::CompareDepthGreater());
+ }
+ llpushcallstacks ;
+ // only render if the flag is set. The flag is only set if we are in edit mode or the toggle is set in the menus
+ if (LLFloaterReg::instanceVisible("beacons") && !sShadowRender)
+ {
+ if (sRenderScriptedTouchBeacons)
+ {
+ // Only show the beacon on the root object.
+ forAllVisibleDrawables(renderScriptedTouchBeacons);
+ }
+ else
+ if (sRenderScriptedBeacons)
+ {
+ // Only show the beacon on the root object.
+ forAllVisibleDrawables(renderScriptedBeacons);
+ }
+
+ if (sRenderPhysicalBeacons)
+ {
+ // Only show the beacon on the root object.
+ forAllVisibleDrawables(renderPhysicalBeacons);
+ }
+
+ if (sRenderParticleBeacons)
+ {
+ forAllVisibleDrawables(renderParticleBeacons);
+ }
+
+ // If god mode, also show audio cues
+ if (sRenderSoundBeacons && gAudiop)
+ {
+ // Walk all sound sources and render out beacons for them. Note, this isn't done in the ForAllVisibleDrawables function, because some are not visible.
+ LLAudioEngine::source_map::iterator iter;
+ for (iter = gAudiop->mAllSources.begin(); iter != gAudiop->mAllSources.end(); ++iter)
+ {
+ LLAudioSource *sourcep = iter->second;
+
+ LLVector3d pos_global = sourcep->getPositionGlobal();
+ LLVector3 pos = gAgent.getPosAgentFromGlobal(pos_global);
+ if (gPipeline.sRenderBeacons)
+ {
+ //pos += LLVector3(0.f, 0.f, 0.2f);
+ gObjectList.addDebugBeacon(pos, "", LLColor4(1.f, 1.f, 0.f, 0.5f), LLColor4(1.f, 1.f, 1.f, 0.5f), gSavedSettings.getS32("DebugBeaconLineWidth"));
+ }
+ }
+ // now deal with highlights for all those seeable sound sources
+ forAllVisibleDrawables(renderSoundHighlights);
+ }
+ }
+ llpushcallstacks ;
+ // If managing your telehub, draw beacons at telehub and currently selected spawnpoint.
+ if (LLFloaterTelehub::renderBeacons())
+ {
+ LLFloaterTelehub::addBeacons();
+ }
+
+ if (!sShadowRender)
+ {
+ mSelectedFaces.clear();
+
+ // Draw face highlights for selected faces.
+ if (LLSelectMgr::getInstance()->getTEMode())
+ {
+ struct f : public LLSelectedTEFunctor
+ {
+ virtual bool apply(LLViewerObject* object, S32 te)
+ {
+ if (object->mDrawable)
+ {
+ gPipeline.mSelectedFaces.push_back(object->mDrawable->getFace(te));
+ }
+ return true;
+ }
+ } func;
+ LLSelectMgr::getInstance()->getSelection()->applyToTEs(&func);
+ }
+ }
+
+ //LLSpatialGroup::sNoDelete = FALSE;
+ llpushcallstacks ;
+}
+
+
+void render_hud_elements()
+{
+ LLMemType mt_rhe(LLMemType::MTYPE_PIPELINE_RENDER_HUD_ELS);
+ LLFastTimer t(FTM_RENDER_UI);
+ gPipeline.disableLights();
+
+ LLGLDisable fog(GL_FOG);
+ LLGLSUIDefault gls_ui;
+
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ glStencilFunc(GL_ALWAYS, 255, 0xFFFFFFFF);
+ glStencilMask(0xFFFFFFFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
+ gGL.color4f(1,1,1,1);
+ if (!LLPipeline::sReflectionRender && gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+ gViewerWindow->renderSelections(FALSE, FALSE, FALSE); // For HUD version in render_ui_3d()
+
+ // Draw the tracking overlays
+ LLTracker::render3D();
+
+ // Show the property lines
+ LLWorld::getInstance()->renderPropertyLines();
+ LLViewerParcelMgr::getInstance()->render();
+ LLViewerParcelMgr::getInstance()->renderParcelCollision();
+
+ // Render name tags.
+ LLHUDObject::renderAll();
+ }
+ else if (gForceRenderLandFence)
+ {
+ // This is only set when not rendering the UI, for parcel snapshots
+ LLViewerParcelMgr::getInstance()->render();
+ }
+ else if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ LLHUDText::renderAllHUD();
+ }
+ gGL.flush();
+}
+
+void LLPipeline::renderHighlights()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_HL);
+
+ assertInitialized();
+
+ // Draw 3D UI elements here (before we clear the Z buffer in POOL_HUD)
+ // Render highlighted faces.
+ LLGLSPipelineAlpha gls_pipeline_alpha;
+ LLColor4 color(1.f, 1.f, 1.f, 0.5f);
+ LLGLEnable color_mat(GL_COLOR_MATERIAL);
+ disableLights();
+
+ if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD) && !mHighlightSet.empty())
+ { //draw blurry highlight image over screen
+ LLGLEnable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ gGL.flush();
+ glStencilMask(0xFFFFFFFF);
+ glClearStencil(1);
+ glClear(GL_STENCIL_BUFFER_BIT);
+
+ glStencilFunc(GL_ALWAYS, 0, 0xFFFFFFFF);
+ glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE);
+
+ gGL.setColorMask(false, false);
+ for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); ++iter)
+ {
+ renderHighlight(iter->mItem->getVObj(), 1.f);
+ }
+ gGL.setColorMask(true, false);
+
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glStencilFunc(GL_NOTEQUAL, 0, 0xFFFFFFFF);
+
+ //gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+
+ gGL.pushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ gGL.pushMatrix();
+ glLoadIdentity();
+
+ gGL.getTexUnit(0)->bind(&mHighlight);
+
+ LLVector2 tc1;
+ LLVector2 tc2;
+
+ tc1.setVec(0,0);
+ tc2.setVec(2,2);
+
+ gGL.begin(LLRender::TRIANGLES);
+
+ F32 scale = gSavedSettings.getF32("RenderHighlightBrightness");
+ LLColor4 color = gSavedSettings.getColor4("RenderHighlightColor");
+ F32 thickness = gSavedSettings.getF32("RenderHighlightThickness");
+
+ for (S32 pass = 0; pass < 2; ++pass)
+ {
+ if (pass == 0)
+ {
+ gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+ }
+ else
+ {
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+
+ for (S32 i = 0; i < 8; ++i)
+ {
+ for (S32 j = 0; j < 8; ++j)
+ {
+ LLVector2 tc(i-4+0.5f, j-4+0.5f);
+
+ F32 dist = 1.f-(tc.length()/sqrtf(32.f));
+ dist *= scale/64.f;
+
+ tc *= thickness;
+ tc.mV[0] = (tc.mV[0])/mHighlight.getWidth();
+ tc.mV[1] = (tc.mV[1])/mHighlight.getHeight();
+
+ gGL.color4f(color.mV[0],
+ color.mV[1],
+ color.mV[2],
+ color.mV[3]*dist);
+
+ gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc.mV[0]+tc1.mV[0], tc.mV[1]+tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc.mV[0]+tc2.mV[0], tc.mV[1]+tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+ }
+ }
+ }
+
+ gGL.end();
+
+ gGL.popMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ gGL.popMatrix();
+
+ //gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+
+ if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
+ {
+ gHighlightProgram.bind();
+ gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,1,1,0.5f);
+ }
+
+ if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
+ {
+ // Make sure the selection image gets downloaded and decoded
+ if (!mFaceSelectImagep)
+ {
+ mFaceSelectImagep = LLViewerTextureManager::getFetchedTexture(IMG_FACE_SELECT);
+ }
+ mFaceSelectImagep->addTextureStats((F32)MAX_IMAGE_AREA);
+
+ U32 count = mSelectedFaces.size();
+ for (U32 i = 0; i < count; i++)
+ {
+ LLFace *facep = mSelectedFaces[i];
+ if (!facep || facep->getDrawable()->isDead())
+ {
+ llerrs << "Bad face on selection" << llendl;
+ return;
+ }
+
+ facep->renderSelected(mFaceSelectImagep, color);
+ }
+ }
+
+ if (hasRenderDebugFeatureMask(RENDER_DEBUG_FEATURE_SELECTED))
+ {
+ // Paint 'em red!
+ color.setVec(1.f, 0.f, 0.f, 0.5f);
+ if ((LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0))
+ {
+ gHighlightProgram.vertexAttrib4f(LLViewerShaderMgr::MATERIAL_COLOR,1,0,0,0.5f);
+ }
+ int count = mHighlightFaces.size();
+ for (S32 i = 0; i < count; i++)
+ {
+ LLFace* facep = mHighlightFaces[i];
+ facep->renderSelected(LLViewerTexture::sNullImagep, color);
+ }
+ }
+
+ // Contains a list of the faces of objects that are physical or
+ // have touch-handlers.
+ mHighlightFaces.clear();
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_INTERFACE) > 0)
+ {
+ gHighlightProgram.unbind();
+ }
+}
+
+//debug use
+U32 LLPipeline::sCurRenderPoolType = 0 ;
+
+void LLPipeline::renderGeom(LLCamera& camera, BOOL forceVBOUpdate)
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_RENDER_GEOM);
+ LLFastTimer t(FTM_RENDER_GEOMETRY);
+
+ assertInitialized();
+
+ F64 saved_modelview[16];
+ F64 saved_projection[16];
+
+ //HACK: preserve/restore matrices around HUD render
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ for (U32 i = 0; i < 16; i++)
+ {
+ saved_modelview[i] = gGLModelView[i];
+ saved_projection[i] = gGLProjection[i];
+ }
+ }
+
+ ///////////////////////////////////////////
+ //
+ // Sync and verify GL state
+ //
+ //
+
+ stop_glerror();
+
+ LLVertexBuffer::unbind();
+
+ // Do verification of GL state
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+ if (mRenderDebugMask & RENDER_DEBUG_VERIFY)
+ {
+ if (!verify())
+ {
+ llerrs << "Pipeline verification failed!" << llendl;
+ }
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:ForceVBO");
+
+ // Initialize lots of GL state to "safe" values
+ glMatrixMode(GL_TEXTURE);
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+
+ LLGLSPipeline gls_pipeline;
+ LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+
+ LLGLState gls_color_material(GL_COLOR_MATERIAL, mLightingDetail < 2);
+
+ // Toggle backface culling for debugging
+ LLGLEnable cull_face(mBackfaceCull ? GL_CULL_FACE : 0);
+ // Set fog
+ BOOL use_fog = hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_FOG);
+ LLGLEnable fog_enable(use_fog &&
+ !gPipeline.canUseWindLightShadersOnObjects() ? GL_FOG : 0);
+ gSky.updateFog(camera.getFar());
+ if (!use_fog)
+ {
+ sUnderWaterRender = FALSE;
+ }
+
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sDefaultImagep);
+ LLViewerFetchedTexture::sDefaultImagep->setAddressMode(LLTexUnit::TAM_WRAP);
+
+ //////////////////////////////////////////////
+ //
+ // Actually render all of the geometry
+ //
+ //
+ stop_glerror();
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPools");
+
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (hasRenderType(poolp->getType()))
+ {
+ poolp->prerender();
+ }
+ }
+
+ {
+ LLFastTimer t(FTM_POOLS);
+
+ // HACK: don't calculate local lights if we're rendering the HUD!
+ // Removing this check will cause bad flickering when there are
+ // HUD elements being rendered AND the user is in flycam mode -nyx
+ if (!gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ calcNearbyLights(camera);
+ setupHWLights(NULL);
+ }
+
+ BOOL occlude = sUseOcclusion > 1;
+ U32 cur_type = 0;
+
+ pool_set_t::iterator iter1 = mPools.begin();
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ //debug use
+ sCurRenderPoolType = cur_type ;
+
+ if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ doOcclusion(camera);
+ }
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumPasses() > 0)
+ {
+ LLFastTimer t(FTM_POOLRENDER);
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginRenderPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->render(i);
+ }
+ poolp->endRenderPass(i);
+ LLVertexBuffer::unbind();
+ if (gDebugGL || gDebugPipeline)
+ {
+ GLint depth;
+ glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+ if (depth > 3)
+ {
+ if (gDebugSession)
+ {
+ ll_fail("GL matrix stack corrupted.");
+ }
+ llerrs << "GL matrix stack corrupted!" << llendl;
+ }
+ std::string msg = llformat("%s pass %d", gPoolNames[cur_type].c_str(), i);
+ LLGLState::checkStates(msg);
+ LLGLState::checkTextureChannels(msg);
+ LLGLState::checkClientArrays(msg);
+ }
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDrawPoolsEnd");
+
+ LLVertexBuffer::unbind();
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ if (occlude)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ doOcclusion(camera);
+ }
+ }
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+
+
+ stop_glerror();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderHighlights");
+
+ if (!sReflectionRender)
+ {
+ renderHighlights();
+ }
+
+ // Contains a list of the faces of objects that are physical or
+ // have touch-handlers.
+ mHighlightFaces.clear();
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderDebug");
+
+ renderDebug();
+
+ LLVertexBuffer::unbind();
+
+ if (!LLPipeline::sReflectionRender && !LLPipeline::sRenderDeferred)
+ {
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ // Render debugging beacons.
+ gObjectList.renderObjectBeacons();
+ gObjectList.resetObjectBeacons();
+ }
+ else
+ {
+ // Make sure particle effects disappear
+ LLHUDObject::renderAllForTimer();
+ }
+ }
+ else
+ {
+ // Make sure particle effects disappear
+ LLHUDObject::renderAllForTimer();
+ }
+
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomEnd");
+
+ //HACK: preserve/restore matrices around HUD render
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLModelView[i] = saved_modelview[i];
+ gGLProjection[i] = saved_projection[i];
+ }
+ }
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+}
+
+void LLPipeline::renderGeomDeferred(LLCamera& camera)
+{
+ LLAppViewer::instance()->pingMainloopTimeout("Pipeline:RenderGeomDeferred");
+
+ LLMemType mt_rgd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_DEFFERRED);
+ LLFastTimer t(FTM_RENDER_GEOMETRY);
+
+ LLFastTimer t2(FTM_POOLS);
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
+ stop_glerror();
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+ stop_glerror();
+
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (hasRenderType(poolp->getType()))
+ {
+ poolp->prerender();
+ }
+ }
+
+ LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ U32 cur_type = 0;
+
+ gGL.setColorMask(true, true);
+
+ pool_set_t::iterator iter1 = mPools.begin();
+
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumDeferredPasses() > 0)
+ {
+ LLFastTimer t(FTM_POOLRENDER);
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumDeferredPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginDeferredPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->renderDeferred(i);
+ }
+ poolp->endDeferredPass(i);
+ LLVertexBuffer::unbind();
+
+ if (gDebugGL || gDebugPipeline)
+ {
+ GLint depth;
+ glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+ if (depth > 3)
+ {
+ llerrs << "GL matrix stack corrupted!" << llendl;
+ }
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+ }
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ gGL.setColorMask(true, false);
+}
+
+void LLPipeline::renderGeomPostDeferred(LLCamera& camera)
+{
+ LLMemType mt_rgpd(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_POST_DEF);
+ LLFastTimer t(FTM_POOLS);
+ U32 cur_type = 0;
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+
+ calcNearbyLights(camera);
+ setupHWLights(NULL);
+
+ gGL.setColorMask(true, false);
+
+ pool_set_t::iterator iter1 = mPools.begin();
+ BOOL occlude = LLPipeline::sUseOcclusion > 1;
+
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ if (occlude && cur_type >= LLDrawPool::POOL_GRASS)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ doOcclusion(camera);
+ gGL.setColorMask(true, false);
+ }
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumPostDeferredPasses() > 0)
+ {
+ LLFastTimer t(FTM_POOLRENDER);
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumPostDeferredPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginPostDeferredPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->renderPostDeferred(i);
+ }
+ poolp->endPostDeferredPass(i);
+ LLVertexBuffer::unbind();
+
+ if (gDebugGL || gDebugPipeline)
+ {
+ GLint depth;
+ glGetIntegerv(GL_MODELVIEW_STACK_DEPTH, &depth);
+ if (depth > 3)
+ {
+ llerrs << "GL matrix stack corrupted!" << llendl;
+ }
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+ }
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ if (occlude)
+ {
+ occlude = FALSE;
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ doOcclusion(camera);
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ }
+}
+
+void LLPipeline::renderGeomShadow(LLCamera& camera)
+{
+ LLMemType mt_rgs(LLMemType::MTYPE_PIPELINE_RENDER_GEOM_SHADOW);
+ U32 cur_type = 0;
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ LLVertexBuffer::unbind();
+
+ pool_set_t::iterator iter1 = mPools.begin();
+
+ while ( iter1 != mPools.end() )
+ {
+ LLDrawPool *poolp = *iter1;
+
+ cur_type = poolp->getType();
+
+ pool_set_t::iterator iter2 = iter1;
+ if (hasRenderType(poolp->getType()) && poolp->getNumShadowPasses() > 0)
+ {
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+
+ for( S32 i = 0; i < poolp->getNumShadowPasses(); i++ )
+ {
+ LLVertexBuffer::unbind();
+ poolp->beginShadowPass(i);
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+
+ p->renderShadow(i);
+ }
+ poolp->endShadowPass(i);
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+ }
+ }
+ else
+ {
+ // Skip all pools of this type
+ for (iter2 = iter1; iter2 != mPools.end(); iter2++)
+ {
+ LLDrawPool *p = *iter2;
+ if (p->getType() != cur_type)
+ {
+ break;
+ }
+ }
+ }
+ iter1 = iter2;
+ stop_glerror();
+ }
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+}
+
+
+void LLPipeline::addTrianglesDrawn(S32 index_count, U32 render_type)
+{
+ assertInitialized();
+ S32 count = 0;
+ if (render_type == LLRender::TRIANGLE_STRIP)
+ {
+ count = index_count-2;
+ }
+ else
+ {
+ count = index_count/3;
+ }
+
+ mTrianglesDrawn += count;
+ mBatchCount++;
+ mMaxBatchSize = llmax(mMaxBatchSize, count);
+ mMinBatchSize = llmin(mMinBatchSize, count);
+
+ if (LLPipeline::sRenderFrameTest)
+ {
+ gViewerWindow->getWindow()->swapBuffers();
+ ms_sleep(16);
+ }
+}
+
+void LLPipeline::renderDebug()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+
+ assertInitialized();
+
+ gGL.color4f(1,1,1,1);
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ gGL.setColorMask(true, false);
+
+ // Debug stuff.
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ part->renderDebug();
+ }
+ }
+ }
+ }
+
+ for (LLCullResult::bridge_list_t::const_iterator i = sCull->beginVisibleBridge(); i != sCull->endVisibleBridge(); ++i)
+ {
+ LLSpatialBridge* bridge = *i;
+ if (!bridge->isDead() && hasRenderType(bridge->mDrawableType))
+ {
+ glPushMatrix();
+ glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
+ bridge->renderDebug();
+ glPopMatrix();
+ }
+ }
+
+ if (hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ LLGLEnable blend(GL_BLEND);
+ LLGLDepthTest depth(TRUE, FALSE);
+ LLGLDisable cull(GL_CULL_FACE);
+
+ gGL.color4f(1,1,1,1);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ F32 a = 0.1f;
+
+ F32 col[] =
+ {
+ 1,0,0,a,
+ 0,1,0,a,
+ 0,0,1,a,
+ 1,0,1,a,
+
+ 1,1,0,a,
+ 0,1,1,a,
+ 1,1,1,a,
+ 1,0,1,a,
+ };
+
+ for (U32 i = 0; i < 8; i++)
+ {
+ LLVector3* frust = mShadowCamera[i].mAgentFrustum;
+
+ if (i > 3)
+ { //render shadow frusta as volumes
+ if (mShadowFrustPoints[i-4].empty())
+ {
+ continue;
+ }
+
+ gGL.color4fv(col+(i-4)*4);
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
+ gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.end();
+
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(frust[0].mV);
+ gGL.vertex3fv(frust[1].mV);
+ gGL.vertex3fv(frust[3].mV);
+ gGL.vertex3fv(frust[2].mV);
+ gGL.end();
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[7].mV);
+ gGL.vertex3fv(frust[6].mV);
+ gGL.end();
+ }
+
+
+ if (i < 4)
+ {
+
+ if (i == 0 || !mShadowFrustPoints[i].empty())
+ {
+ //render visible point cloud
+ gGL.flush();
+ glPointSize(8.f);
+ gGL.begin(LLRender::POINTS);
+
+ F32* c = col+i*4;
+ gGL.color3fv(c);
+
+ for (U32 j = 0; j < mShadowFrustPoints[i].size(); ++j)
+ {
+ gGL.vertex3fv(mShadowFrustPoints[i][j].mV);
+
+ }
+ gGL.end();
+
+ gGL.flush();
+ glPointSize(1.f);
+
+ LLVector3* ext = mShadowExtents[i];
+ LLVector3 pos = (ext[0]+ext[1])*0.5f;
+ LLVector3 size = (ext[1]-ext[0])*0.5f;
+ drawBoxOutline(pos, size);
+
+ //render camera frustum splits as outlines
+ gGL.begin(LLRender::LINES);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[1].mV);
+ gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[2].mV);
+ gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[3].mV);
+ gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[0].mV);
+ gGL.vertex3fv(frust[4].mV); gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[5].mV); gGL.vertex3fv(frust[6].mV);
+ gGL.vertex3fv(frust[6].mV); gGL.vertex3fv(frust[7].mV);
+ gGL.vertex3fv(frust[7].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[0].mV); gGL.vertex3fv(frust[4].mV);
+ gGL.vertex3fv(frust[1].mV); gGL.vertex3fv(frust[5].mV);
+ gGL.vertex3fv(frust[2].mV); gGL.vertex3fv(frust[6].mV);
+ gGL.vertex3fv(frust[3].mV); gGL.vertex3fv(frust[7].mV);
+ gGL.end();
+ }
+
+ }
+
+ /*for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(j);
+ if (part)
+ {
+ if (hasRenderType(part->mDrawableType))
+ {
+ part->renderIntersectingBBoxes(&mShadowCamera[i]);
+ }
+ }
+ }
+ }*/
+ }
+ }
+
+ if (mRenderDebugMask & RENDER_DEBUG_COMPOSITION)
+ {
+ // Debug composition layers
+ F32 x, y;
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ if (gAgent.getRegion())
+ {
+ gGL.begin(LLRender::POINTS);
+ // Draw the composition layer for the region that I'm in.
+ for (x = 0; x <= 260; x++)
+ {
+ for (y = 0; y <= 260; y++)
+ {
+ if ((x > 255) || (y > 255))
+ {
+ gGL.color4f(1.f, 0.f, 0.f, 1.f);
+ }
+ else
+ {
+ gGL.color4f(0.f, 0.f, 1.f, 1.f);
+ }
+ F32 z = gAgent.getRegion()->getCompositionXY((S32)x, (S32)y);
+ z *= 5.f;
+ z += 50.f;
+ gGL.vertex3f(x, y, z);
+ }
+ }
+ gGL.end();
+ }
+ }
+
+ if (mRenderDebugMask & LLPipeline::RENDER_DEBUG_BUILD_QUEUE)
+ {
+ U32 count = 0;
+ U32 size = mBuildQ2.size();
+ LLColor4 col;
+
+ LLGLEnable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+
+ for (LLSpatialGroup::sg_vector_t::iterator iter = mGroupQ2.begin(); iter != mGroupQ2.end(); ++iter)
+ {
+ LLSpatialGroup* group = *iter;
+ if (group->isDead())
+ {
+ continue;
+ }
+
+ LLSpatialBridge* bridge = group->mSpatialPartition->asBridge();
+
+ if (bridge && (!bridge->mDrawable || bridge->mDrawable->isDead()))
+ {
+ continue;
+ }
+
+ if (bridge)
+ {
+ gGL.pushMatrix();
+ glMultMatrixf((F32*)bridge->mDrawable->getRenderMatrix().mMatrix);
+ }
+
+ F32 alpha = (F32) (size-count)/size;
+
+
+ LLVector2 c(1.f-alpha, alpha);
+ c.normVec();
+
+
+ ++count;
+ col.set(c.mV[0], c.mV[1], 0, alpha*0.5f+0.1f);
+ group->drawObjectBox(col);
+
+ if (bridge)
+ {
+ gGL.popMatrix();
+ }
+ }
+ }
+
+ gGL.flush();
+}
+
+void LLPipeline::rebuildPools()
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_REBUILD_POOLS);
+
+ assertInitialized();
+
+ S32 max_count = mPools.size();
+ pool_set_t::iterator iter1 = mPools.upper_bound(mLastRebuildPool);
+ while(max_count > 0 && mPools.size() > 0) // && num_rebuilds < MAX_REBUILDS)
+ {
+ if (iter1 == mPools.end())
+ {
+ iter1 = mPools.begin();
+ }
+ LLDrawPool* poolp = *iter1;
+
+ if (poolp->isDead())
+ {
+ mPools.erase(iter1++);
+ removeFromQuickLookup( poolp );
+ if (poolp == mLastRebuildPool)
+ {
+ mLastRebuildPool = NULL;
+ }
+ delete poolp;
+ }
+ else
+ {
+ mLastRebuildPool = poolp;
+ iter1++;
+ }
+ max_count--;
+ }
+
+ if (isAgentAvatarValid())
+ {
+ gAgentAvatarp->rebuildHUD();
+ }
+}
+
+void LLPipeline::addToQuickLookup( LLDrawPool* new_poolp )
+{
+ LLMemType mt(LLMemType::MTYPE_PIPELINE_QUICK_LOOKUP);
+
+ assertInitialized();
+
+ switch( new_poolp->getType() )
+ {
+ case LLDrawPool::POOL_SIMPLE:
+ if (mSimplePool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate simple pool." << llendl;
+ }
+ else
+ {
+ mSimplePool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_GRASS:
+ if (mGrassPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate grass pool." << llendl;
+ }
+ else
+ {
+ mGrassPool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_FULLBRIGHT:
+ if (mFullbrightPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate simple pool." << llendl;
+ }
+ else
+ {
+ mFullbrightPool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_INVISIBLE:
+ if (mInvisiblePool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate simple pool." << llendl;
+ }
+ else
+ {
+ mInvisiblePool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_GLOW:
+ if (mGlowPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate glow pool." << llendl;
+ }
+ else
+ {
+ mGlowPool = (LLRenderPass*) new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_TREE:
+ mTreePools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
+ break;
+
+ case LLDrawPool::POOL_TERRAIN:
+ mTerrainPools[ uintptr_t(new_poolp->getTexture()) ] = new_poolp ;
+ break;
+
+ case LLDrawPool::POOL_BUMP:
+ if (mBumpPool)
+ {
+ llassert(0);
+ llwarns << "Ignoring duplicate bump pool." << llendl;
+ }
+ else
+ {
+ mBumpPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_ALPHA:
+ if( mAlphaPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Alpha pool" << llendl;
+ }
+ else
+ {
+ mAlphaPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_AVATAR:
+ break; // Do nothing
+
+ case LLDrawPool::POOL_SKY:
+ if( mSkyPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Sky pool" << llendl;
+ }
+ else
+ {
+ mSkyPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_WATER:
+ if( mWaterPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Water pool" << llendl;
+ }
+ else
+ {
+ mWaterPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_GROUND:
+ if( mGroundPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate Ground Pool" << llendl;
+ }
+ else
+ {
+ mGroundPool = new_poolp;
+ }
+ break;
+
+ case LLDrawPool::POOL_WL_SKY:
+ if( mWLSkyPool )
+ {
+ llassert(0);
+ llwarns << "LLPipeline::addPool(): Ignoring duplicate WLSky Pool" << llendl;
+ }
+ else
+ {
+ mWLSkyPool = new_poolp;
+ }
+ break;
+
+ default:
+ llassert(0);
+ llwarns << "Invalid Pool Type in LLPipeline::addPool()" << llendl;
+ break;
+ }
+}
+
+void LLPipeline::removePool( LLDrawPool* poolp )
+{
+ assertInitialized();
+ removeFromQuickLookup(poolp);
+ mPools.erase(poolp);
+ delete poolp;
+}
+
+void LLPipeline::removeFromQuickLookup( LLDrawPool* poolp )
+{
+ assertInitialized();
+ LLMemType mt(LLMemType::MTYPE_PIPELINE);
+ switch( poolp->getType() )
+ {
+ case LLDrawPool::POOL_SIMPLE:
+ llassert(mSimplePool == poolp);
+ mSimplePool = NULL;
+ break;
+
+ case LLDrawPool::POOL_GRASS:
+ llassert(mGrassPool == poolp);
+ mGrassPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_FULLBRIGHT:
+ llassert(mFullbrightPool == poolp);
+ mFullbrightPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_INVISIBLE:
+ llassert(mInvisiblePool == poolp);
+ mInvisiblePool = NULL;
+ break;
+
+ case LLDrawPool::POOL_WL_SKY:
+ llassert(mWLSkyPool == poolp);
+ mWLSkyPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_GLOW:
+ llassert(mGlowPool == poolp);
+ mGlowPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_TREE:
+ #ifdef _DEBUG
+ {
+ BOOL found = mTreePools.erase( (uintptr_t)poolp->getTexture() );
+ llassert( found );
+ }
+ #else
+ mTreePools.erase( (uintptr_t)poolp->getTexture() );
+ #endif
+ break;
+
+ case LLDrawPool::POOL_TERRAIN:
+ #ifdef _DEBUG
+ {
+ BOOL found = mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
+ llassert( found );
+ }
+ #else
+ mTerrainPools.erase( (uintptr_t)poolp->getTexture() );
+ #endif
+ break;
+
+ case LLDrawPool::POOL_BUMP:
+ llassert( poolp == mBumpPool );
+ mBumpPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_ALPHA:
+ llassert( poolp == mAlphaPool );
+ mAlphaPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_AVATAR:
+ break; // Do nothing
+
+ case LLDrawPool::POOL_SKY:
+ llassert( poolp == mSkyPool );
+ mSkyPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_WATER:
+ llassert( poolp == mWaterPool );
+ mWaterPool = NULL;
+ break;
+
+ case LLDrawPool::POOL_GROUND:
+ llassert( poolp == mGroundPool );
+ mGroundPool = NULL;
+ break;
+
+ default:
+ llassert(0);
+ llwarns << "Invalid Pool Type in LLPipeline::removeFromQuickLookup() type=" << poolp->getType() << llendl;
+ break;
+ }
+}
+
+void LLPipeline::resetDrawOrders()
+{
+ assertInitialized();
+ // Iterate through all of the draw pools and rebuild them.
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ poolp->resetDrawOrders();
+ }
+}
+
+//============================================================================
+// Once-per-frame setup of hardware lights,
+// including sun/moon, avatar backlight, and up to 6 local lights
+
+void LLPipeline::setupAvatarLights(BOOL for_edit)
+{
+ assertInitialized();
+
+ if (for_edit)
+ {
+ LLColor4 diffuse(1.f, 1.f, 1.f, 0.f);
+ LLVector4 light_pos_cam(-8.f, 0.25f, 10.f, 0.f); // w==0 => directional light
+ LLMatrix4 camera_mat = LLViewerCamera::getInstance()->getModelview();
+ LLMatrix4 camera_rot(camera_mat.getMat3());
+ camera_rot.invert();
+ LLVector4 light_pos = light_pos_cam * camera_rot;
+
+ light_pos.normalize();
+
+ mHWLightColors[1] = diffuse;
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse.mV);
+ glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
+ glLightfv(GL_LIGHT1, GL_POSITION, light_pos.mV);
+ glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0f);
+ glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.0f);
+ glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0f);
+ glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.0f);
+ glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 180.0f);
+ }
+ else if (gAvatarBacklight) // Always true (unless overridden in a devs .ini)
+ {
+ LLVector3 opposite_pos = -1.f * mSunDir;
+ LLVector3 orthog_light_pos = mSunDir % LLVector3::z_axis;
+ LLVector4 backlight_pos = LLVector4(lerp(opposite_pos, orthog_light_pos, 0.3f), 0.0f);
+ backlight_pos.normalize();
+
+ LLColor4 light_diffuse = mSunDiffuse;
+ LLColor4 backlight_diffuse(1.f - light_diffuse.mV[VRED], 1.f - light_diffuse.mV[VGREEN], 1.f - light_diffuse.mV[VBLUE], 1.f);
+ F32 max_component = 0.001f;
+ for (S32 i = 0; i < 3; i++)
+ {
+ if (backlight_diffuse.mV[i] > max_component)
+ {
+ max_component = backlight_diffuse.mV[i];
+ }
+ }
+ F32 backlight_mag;
+ if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
+ {
+ backlight_mag = BACKLIGHT_DAY_MAGNITUDE_OBJECT;
+ }
+ else
+ {
+ backlight_mag = BACKLIGHT_NIGHT_MAGNITUDE_OBJECT;
+ }
+ backlight_diffuse *= backlight_mag / max_component;
+
+ mHWLightColors[1] = backlight_diffuse;
+ glLightfv(GL_LIGHT1, GL_POSITION, backlight_pos.mV); // this is just sun/moon direction
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, backlight_diffuse.mV);
+ glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
+ glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1.0f);
+ glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0.0f);
+ glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0.0f);
+ glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 0.0f);
+ glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 180.0f);
+ }
+ else
+ {
+ mHWLightColors[1] = LLColor4::black;
+ glLightfv(GL_LIGHT1, GL_DIFFUSE, LLColor4::black.mV);
+ glLightfv(GL_LIGHT1, GL_AMBIENT, LLColor4::black.mV);
+ glLightfv(GL_LIGHT1, GL_SPECULAR, LLColor4::black.mV);
+ }
+}
+
+static F32 calc_light_dist(LLVOVolume* light, const LLVector3& cam_pos, F32 max_dist)
+{
+ F32 inten = light->getLightIntensity();
+ if (inten < .001f)
+ {
+ return max_dist;
+ }
+ F32 radius = light->getLightRadius();
+ BOOL selected = light->isSelected();
+ LLVector3 dpos = light->getRenderPosition() - cam_pos;
+ F32 dist2 = dpos.lengthSquared();
+ if (!selected && dist2 > (max_dist + radius)*(max_dist + radius))
+ {
+ return max_dist;
+ }
+ F32 dist = fsqrtf(dist2);
+ dist *= 1.f / inten;
+ dist -= radius;
+ if (selected)
+ {
+ dist -= 10000.f; // selected lights get highest priority
+ }
+ if (light->mDrawable.notNull() && light->mDrawable->isState(LLDrawable::ACTIVE))
+ {
+ // moving lights get a little higher priority (too much causes artifacts)
+ dist -= light->getLightRadius()*0.25f;
+ }
+ return dist;
+}
+
+void LLPipeline::calcNearbyLights(LLCamera& camera)
+{
+ assertInitialized();
+
+ if (LLPipeline::sReflectionRender)
+ {
+ return;
+ }
+
+ if (mLightingDetail >= 1)
+ {
+ // mNearbyLight (and all light_set_t's) are sorted such that
+ // begin() == the closest light and rbegin() == the farthest light
+ const S32 MAX_LOCAL_LIGHTS = 6;
+// LLVector3 cam_pos = gAgentCamera.getCameraPositionAgent();
+ LLVector3 cam_pos = LLViewerJoystick::getInstance()->getOverrideCamera() ?
+ camera.getOrigin() :
+ gAgent.getPositionAgent();
+
+ F32 max_dist = LIGHT_MAX_RADIUS * 4.f; // ignore enitrely lights > 4 * max light rad
+
+ // UPDATE THE EXISTING NEARBY LIGHTS
+ light_set_t cur_nearby_lights;
+ for (light_set_t::iterator iter = mNearbyLights.begin();
+ iter != mNearbyLights.end(); iter++)
+ {
+ const Light* light = &(*iter);
+ LLDrawable* drawable = light->drawable;
+ LLVOVolume* volight = drawable->getVOVolume();
+ if (!volight || !drawable->isState(LLDrawable::LIGHT))
+ {
+ drawable->clearState(LLDrawable::NEARBY_LIGHT);
+ continue;
+ }
+ if (light->fade <= -LIGHT_FADE_TIME)
+ {
+ drawable->clearState(LLDrawable::NEARBY_LIGHT);
+ continue;
+ }
+ if (!sRenderAttachedLights && volight && volight->isAttachment())
+ {
+ drawable->clearState(LLDrawable::NEARBY_LIGHT);
+ continue;
+ }
+
+ F32 dist = calc_light_dist(volight, cam_pos, max_dist);
+ cur_nearby_lights.insert(Light(drawable, dist, light->fade));
+ }
+ mNearbyLights = cur_nearby_lights;
+
+ // FIND NEW LIGHTS THAT ARE IN RANGE
+ light_set_t new_nearby_lights;
+ for (LLDrawable::drawable_set_t::iterator iter = mLights.begin();
+ iter != mLights.end(); ++iter)
+ {
+ LLDrawable* drawable = *iter;
+ LLVOVolume* light = drawable->getVOVolume();
+ if (!light || drawable->isState(LLDrawable::NEARBY_LIGHT))
+ {
+ continue;
+ }
+ if (light->isHUDAttachment())
+ {
+ continue; // no lighting from HUD objects
+ }
+ F32 dist = calc_light_dist(light, cam_pos, max_dist);
+ if (dist >= max_dist)
+ {
+ continue;
+ }
+ if (!sRenderAttachedLights && light && light->isAttachment())
+ {
+ continue;
+ }
+ new_nearby_lights.insert(Light(drawable, dist, 0.f));
+ if (new_nearby_lights.size() > (U32)MAX_LOCAL_LIGHTS)
+ {
+ new_nearby_lights.erase(--new_nearby_lights.end());
+ const Light& last = *new_nearby_lights.rbegin();
+ max_dist = last.dist;
+ }
+ }
+
+ // INSERT ANY NEW LIGHTS
+ for (light_set_t::iterator iter = new_nearby_lights.begin();
+ iter != new_nearby_lights.end(); iter++)
+ {
+ const Light* light = &(*iter);
+ if (mNearbyLights.size() < (U32)MAX_LOCAL_LIGHTS)
+ {
+ mNearbyLights.insert(*light);
+ ((LLDrawable*) light->drawable)->setState(LLDrawable::NEARBY_LIGHT);
+ }
+ else
+ {
+ // crazy cast so that we can overwrite the fade value
+ // even though gcc enforces sets as const
+ // (fade value doesn't affect sort so this is safe)
+ Light* farthest_light = ((Light*) (&(*(mNearbyLights.rbegin()))));
+ if (light->dist < farthest_light->dist)
+ {
+ if (farthest_light->fade >= 0.f)
+ {
+ farthest_light->fade = -gFrameIntervalSeconds;
+ }
+ }
+ else
+ {
+ break; // none of the other lights are closer
+ }
+ }
+ }
+
+ }
+}
+
+void LLPipeline::setupHWLights(LLDrawPool* pool)
+{
+ assertInitialized();
+
+ // Ambient
+ LLColor4 ambient = gSky.getTotalAmbientColor();
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV);
+
+ // Light 0 = Sun or Moon (All objects)
+ {
+ if (gSky.getSunDirection().mV[2] >= LLSky::NIGHTTIME_ELEVATION_COS)
+ {
+ mSunDir.setVec(gSky.getSunDirection());
+ mSunDiffuse.setVec(gSky.getSunDiffuseColor());
+ }
+ else
+ {
+ mSunDir.setVec(gSky.getMoonDirection());
+ mSunDiffuse.setVec(gSky.getMoonDiffuseColor());
+ }
+
+ F32 max_color = llmax(mSunDiffuse.mV[0], mSunDiffuse.mV[1], mSunDiffuse.mV[2]);
+ if (max_color > 1.f)
+ {
+ mSunDiffuse *= 1.f/max_color;
+ }
+ mSunDiffuse.clamp();
+
+ LLVector4 light_pos(mSunDir, 0.0f);
+ LLColor4 light_diffuse = mSunDiffuse;
+ mHWLightColors[0] = light_diffuse;
+ glLightfv(GL_LIGHT0, GL_POSITION, light_pos.mV); // this is just sun/moon direction
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse.mV);
+ glLightfv(GL_LIGHT0, GL_AMBIENT, LLColor4::black.mV);
+ glLightfv(GL_LIGHT0, GL_SPECULAR, LLColor4::black.mV);
+ glLightf (GL_LIGHT0, GL_CONSTANT_ATTENUATION, 1.0f);
+ glLightf (GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.0f);
+ glLightf (GL_LIGHT0, GL_QUADRATIC_ATTENUATION, 0.0f);
+ glLightf (GL_LIGHT0, GL_SPOT_EXPONENT, 0.0f);
+ glLightf (GL_LIGHT0, GL_SPOT_CUTOFF, 180.0f);
+ }
+
+ // Light 1 = Backlight (for avatars)
+ // (set by enableLightsAvatar)
+
+ S32 cur_light = 2;
+
+ // Nearby lights = LIGHT 2-7
+
+ mLightMovingMask = 0;
+
+ if (mLightingDetail >= 1)
+ {
+ for (light_set_t::iterator iter = mNearbyLights.begin();
+ iter != mNearbyLights.end(); ++iter)
+ {
+ LLDrawable* drawable = iter->drawable;
+ LLVOVolume* light = drawable->getVOVolume();
+ if (!light)
+ {
+ continue;
+ }
+ if (drawable->isState(LLDrawable::ACTIVE))
+ {
+ mLightMovingMask |= (1<<cur_light);
+ }
+
+ LLColor4 light_color = light->getLightColor();
+ light_color.mV[3] = 0.0f;
+
+ F32 fade = iter->fade;
+ if (fade < LIGHT_FADE_TIME)
+ {
+ // fade in/out light
+ if (fade >= 0.f)
+ {
+ fade = fade / LIGHT_FADE_TIME;
+ ((Light*) (&(*iter)))->fade += gFrameIntervalSeconds;
+ }
+ else
+ {
+ fade = 1.f + fade / LIGHT_FADE_TIME;
+ ((Light*) (&(*iter)))->fade -= gFrameIntervalSeconds;
+ }
+ fade = llclamp(fade,0.f,1.f);
+ light_color *= fade;
+ }
+
+ LLVector3 light_pos(light->getRenderPosition());
+ LLVector4 light_pos_gl(light_pos, 1.0f);
+
+ F32 light_radius = llmax(light->getLightRadius(), 0.001f);
+
+ F32 x = (3.f * (1.f + light->getLightFalloff())); // why this magic? probably trying to match a historic behavior.
+ float linatten = x / (light_radius); // % of brightness at radius
+
+ mHWLightColors[cur_light] = light_color;
+ S32 gllight = GL_LIGHT0+cur_light;
+ glLightfv(gllight, GL_POSITION, light_pos_gl.mV);
+ glLightfv(gllight, GL_DIFFUSE, light_color.mV);
+ glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV);
+ glLightf (gllight, GL_CONSTANT_ATTENUATION, 0.0f);
+ glLightf (gllight, GL_LINEAR_ATTENUATION, linatten);
+ glLightf (gllight, GL_QUADRATIC_ATTENUATION, 0.0f);
+ if (light->isLightSpotlight() // directional (spot-)light
+ && (LLPipeline::sRenderDeferred || gSavedSettings.getBOOL("RenderSpotLightsInNondeferred"))) // these are only rendered as GL spotlights if we're in deferred rendering mode *or* the setting forces them on
+ {
+ LLVector3 spotparams = light->getSpotLightParams();
+ LLQuaternion quat = light->getRenderRotation();
+ LLVector3 at_axis(0,0,-1); // this matches deferred rendering's object light direction
+ at_axis *= quat;
+ //llinfos << "SPOT!!!!!!! fov: " << spotparams.mV[0] << " focus: " << spotparams.mV[1] << " dir: " << at_axis << llendl;
+ glLightfv(gllight, GL_SPOT_DIRECTION, at_axis.mV);
+ glLightf (gllight, GL_SPOT_EXPONENT, 2.0f); // 2.0 = good old dot product ^ 2
+ glLightf (gllight, GL_SPOT_CUTOFF, 90.0f); // hemisphere
+ const float specular[] = {0.f, 0.f, 0.f, 0.f};
+ glLightfv(gllight, GL_SPECULAR, specular);
+ }
+ else // omnidirectional (point) light
+ {
+ glLightf (gllight, GL_SPOT_EXPONENT, 0.0f);
+ glLightf (gllight, GL_SPOT_CUTOFF, 180.0f);
+
+ // we use specular.w = 1.0 as a cheap hack for the shaders to know that this is omnidirectional rather than a spotlight
+ const float specular[] = {0.f, 0.f, 0.f, 1.f};
+ glLightfv(gllight, GL_SPECULAR, specular);
+ //llinfos << "boring light" << llendl;
+ }
+ cur_light++;
+ if (cur_light >= 8)
+ {
+ break; // safety
+ }
+ }
+ }
+ for ( ; cur_light < 8 ; cur_light++)
+ {
+ mHWLightColors[cur_light] = LLColor4::black;
+ S32 gllight = GL_LIGHT0+cur_light;
+ glLightfv(gllight, GL_DIFFUSE, LLColor4::black.mV);
+ glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV);
+ glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
+ }
+
+ if (isAgentAvatarValid() &&
+ gAgentAvatarp->mSpecialRenderMode == 3)
+ {
+ LLColor4 light_color = LLColor4::white;
+ light_color.mV[3] = 0.0f;
+
+ LLVector3 light_pos(LLViewerCamera::getInstance()->getOrigin());
+ LLVector4 light_pos_gl(light_pos, 1.0f);
+
+ F32 light_radius = 16.f;
+
+ F32 x = 3.f;
+ float linatten = x / (light_radius); // % of brightness at radius
+
+ mHWLightColors[2] = light_color;
+ S32 gllight = GL_LIGHT2;
+ glLightfv(gllight, GL_POSITION, light_pos_gl.mV);
+ glLightfv(gllight, GL_DIFFUSE, light_color.mV);
+ glLightfv(gllight, GL_AMBIENT, LLColor4::black.mV);
+ glLightfv(gllight, GL_SPECULAR, LLColor4::black.mV);
+ glLightf (gllight, GL_CONSTANT_ATTENUATION, 0.0f);
+ glLightf (gllight, GL_LINEAR_ATTENUATION, linatten);
+ glLightf (gllight, GL_QUADRATIC_ATTENUATION, 0.0f);
+ glLightf (gllight, GL_SPOT_EXPONENT, 0.0f);
+ glLightf (gllight, GL_SPOT_CUTOFF, 180.0f);
+ }
+
+ // Init GL state
+ glDisable(GL_LIGHTING);
+ for (S32 gllight=GL_LIGHT0; gllight<=GL_LIGHT7; gllight++)
+ {
+ glDisable(gllight);
+ }
+ mLightMask = 0;
+}
+
+void LLPipeline::enableLights(U32 mask)
+{
+ assertInitialized();
+
+ if (mLightingDetail == 0)
+ {
+ mask &= 0xf003; // sun and backlight only (and fullbright bit)
+ }
+ if (mLightMask != mask)
+ {
+ stop_glerror();
+ if (!mLightMask)
+ {
+ glEnable(GL_LIGHTING);
+ }
+ if (mask)
+ {
+ stop_glerror();
+ for (S32 i=0; i<8; i++)
+ {
+ if (mask & (1<<i))
+ {
+ glEnable(GL_LIGHT0 + i);
+ glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, mHWLightColors[i].mV);
+ }
+ else
+ {
+ glDisable(GL_LIGHT0 + i);
+ glLightfv(GL_LIGHT0 + i, GL_DIFFUSE, LLColor4::black.mV);
+ }
+ }
+ stop_glerror();
+ }
+ else
+ {
+ glDisable(GL_LIGHTING);
+ }
+ stop_glerror();
+ mLightMask = mask;
+ LLColor4 ambient = gSky.getTotalAmbientColor();
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT,ambient.mV);
+ stop_glerror();
+ }
+}
+
+void LLPipeline::enableLightsStatic()
+{
+ assertInitialized();
+ U32 mask = 0x01; // Sun
+ if (mLightingDetail >= 2)
+ {
+ mask |= mLightMovingMask; // Hardware moving lights
+ glColor4f(0.f, 0.f, 0.f, 1.0f); // no local lighting by default
+ }
+ else
+ {
+ mask |= 0xff & (~2); // Hardware local lights
+ }
+ enableLights(mask);
+}
+
+void LLPipeline::enableLightsDynamic()
+{
+ assertInitialized();
+ U32 mask = 0xff & (~2); // Local lights
+ enableLights(mask);
+ if (mLightingDetail >= 2)
+ {
+ glColor4f(0.f, 0.f, 0.f, 1.f); // no local lighting by default
+ }
+
+ if (isAgentAvatarValid() && getLightingDetail() <= 0)
+ {
+ if (gAgentAvatarp->mSpecialRenderMode == 0) // normal
+ {
+ gPipeline.enableLightsAvatar();
+ }
+ else if (gAgentAvatarp->mSpecialRenderMode >= 1) // anim preview
+ {
+ gPipeline.enableLightsAvatarEdit(LLColor4(0.7f, 0.6f, 0.3f, 1.f));
+ }
+ }
+}
+
+void LLPipeline::enableLightsAvatar()
+{
+ U32 mask = 0xff; // All lights
+ setupAvatarLights(FALSE);
+ enableLights(mask);
+}
+
+void LLPipeline::enableLightsAvatarEdit(const LLColor4& color)
+{
+ U32 mask = 0x2002; // Avatar backlight only, set ambient
+ setupAvatarLights(TRUE);
+ enableLights(mask);
+
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
+}
+
+void LLPipeline::enableLightsFullbright(const LLColor4& color)
+{
+ assertInitialized();
+ U32 mask = 0x1000; // Non-0 mask, set ambient
+ enableLights(mask);
+
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT,color.mV);
+ /*if (mLightingDetail >= 2)
+ {
+ glColor4f(0.f, 0.f, 0.f, 1.f); // no local lighting by default
+ }*/
+}
+
+void LLPipeline::disableLights()
+{
+ enableLights(0); // no lighting (full bright)
+ glColor4f(1.f, 1.f, 1.f, 1.f); // lighting color = white by default
+}
+
+//============================================================================
+
+class LLMenuItemGL;
+class LLInvFVBridge;
+struct cat_folder_pair;
+class LLVOBranch;
+class LLVOLeaf;
+
+void LLPipeline::findReferences(LLDrawable *drawablep)
+{
+ assertInitialized();
+ if (mLights.find(drawablep) != mLights.end())
+ {
+ llinfos << "In mLights" << llendl;
+ }
+ if (std::find(mMovedList.begin(), mMovedList.end(), drawablep) != mMovedList.end())
+ {
+ llinfos << "In mMovedList" << llendl;
+ }
+ if (std::find(mShiftList.begin(), mShiftList.end(), drawablep) != mShiftList.end())
+ {
+ llinfos << "In mShiftList" << llendl;
+ }
+ if (mRetexturedList.find(drawablep) != mRetexturedList.end())
+ {
+ llinfos << "In mRetexturedList" << llendl;
+ }
+
+ if (std::find(mBuildQ1.begin(), mBuildQ1.end(), drawablep) != mBuildQ1.end())
+ {
+ llinfos << "In mBuildQ1" << llendl;
+ }
+ if (std::find(mBuildQ2.begin(), mBuildQ2.end(), drawablep) != mBuildQ2.end())
+ {
+ llinfos << "In mBuildQ2" << llendl;
+ }
+
+ S32 count;
+
+ count = gObjectList.findReferences(drawablep);
+ if (count)
+ {
+ llinfos << "In other drawables: " << count << " references" << llendl;
+ }
+}
+
+BOOL LLPipeline::verify()
+{
+ BOOL ok = assertInitialized();
+ if (ok)
+ {
+ for (pool_set_t::iterator iter = mPools.begin(); iter != mPools.end(); ++iter)
+ {
+ LLDrawPool *poolp = *iter;
+ if (!poolp->verify())
+ {
+ ok = FALSE;
+ }
+ }
+ }
+
+ if (!ok)
+ {
+ llwarns << "Pipeline verify failed!" << llendl;
+ }
+ return ok;
+}
+
+//////////////////////////////
+//
+// Collision detection
+//
+//
+
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+/**
+ * A method to compute a ray-AABB intersection.
+ * Original code by Andrew Woo, from "Graphics Gems", Academic Press, 1990
+ * Optimized code by Pierre Terdiman, 2000 (~20-30% faster on my Celeron 500)
+ * Epsilon value added by Klaus Hartmann. (discarding it saves a few cycles only)
+ *
+ * Hence this version is faster as well as more robust than the original one.
+ *
+ * Should work provided:
+ * 1) the integer representation of 0.0f is 0x00000000
+ * 2) the sign bit of the float is the most significant one
+ *
+ * Report bugs: p.terdiman@codercorner.com
+ *
+ * \param aabb [in] the axis-aligned bounding box
+ * \param origin [in] ray origin
+ * \param dir [in] ray direction
+ * \param coord [out] impact coordinates
+ * \return true if ray intersects AABB
+ */
+///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+//#define RAYAABB_EPSILON 0.00001f
+#define IR(x) ((U32&)x)
+
+bool LLRayAABB(const LLVector3 &center, const LLVector3 &size, const LLVector3& origin, const LLVector3& dir, LLVector3 &coord, F32 epsilon)
+{
+ BOOL Inside = TRUE;
+ LLVector3 MinB = center - size;
+ LLVector3 MaxB = center + size;
+ LLVector3 MaxT;
+ MaxT.mV[VX]=MaxT.mV[VY]=MaxT.mV[VZ]=-1.0f;
+
+ // Find candidate planes.
+ for(U32 i=0;i<3;i++)
+ {
+ if(origin.mV[i] < MinB.mV[i])
+ {
+ coord.mV[i] = MinB.mV[i];
+ Inside = FALSE;
+
+ // Calculate T distances to candidate planes
+ if(IR(dir.mV[i])) MaxT.mV[i] = (MinB.mV[i] - origin.mV[i]) / dir.mV[i];
+ }
+ else if(origin.mV[i] > MaxB.mV[i])
+ {
+ coord.mV[i] = MaxB.mV[i];
+ Inside = FALSE;
+
+ // Calculate T distances to candidate planes
+ if(IR(dir.mV[i])) MaxT.mV[i] = (MaxB.mV[i] - origin.mV[i]) / dir.mV[i];
+ }
+ }
+
+ // Ray origin inside bounding box
+ if(Inside)
+ {
+ coord = origin;
+ return true;
+ }
+
+ // Get largest of the maxT's for final choice of intersection
+ U32 WhichPlane = 0;
+ if(MaxT.mV[1] > MaxT.mV[WhichPlane]) WhichPlane = 1;
+ if(MaxT.mV[2] > MaxT.mV[WhichPlane]) WhichPlane = 2;
+
+ // Check final candidate actually inside box
+ if(IR(MaxT.mV[WhichPlane])&0x80000000) return false;
+
+ for(U32 i=0;i<3;i++)
+ {
+ if(i!=WhichPlane)
+ {
+ coord.mV[i] = origin.mV[i] + MaxT.mV[WhichPlane] * dir.mV[i];
+ if (epsilon > 0)
+ {
+ if(coord.mV[i] < MinB.mV[i] - epsilon || coord.mV[i] > MaxB.mV[i] + epsilon) return false;
+ }
+ else
+ {
+ if(coord.mV[i] < MinB.mV[i] || coord.mV[i] > MaxB.mV[i]) return false;
+ }
+ }
+ }
+ return true; // ray hits box
+}
+
+//////////////////////////////
+//
+// Macros, functions, and inline methods from other classes
+//
+//
+
+void LLPipeline::setLight(LLDrawable *drawablep, BOOL is_light)
+{
+ if (drawablep && assertInitialized())
+ {
+ if (is_light)
+ {
+ mLights.insert(drawablep);
+ drawablep->setState(LLDrawable::LIGHT);
+ }
+ else
+ {
+ drawablep->clearState(LLDrawable::LIGHT);
+ mLights.erase(drawablep);
+ }
+ }
+}
+
+//static
+void LLPipeline::toggleRenderType(U32 type)
+{
+ gPipeline.mRenderTypeEnabled[type] = !gPipeline.mRenderTypeEnabled[type];
+ if (type == LLPipeline::RENDER_TYPE_WATER)
+ {
+ gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER] = !gPipeline.mRenderTypeEnabled[LLPipeline::RENDER_TYPE_VOIDWATER];
+ }
+}
+
+//static
+void LLPipeline::toggleRenderTypeControl(void* data)
+{
+ U32 type = (U32)(intptr_t)data;
+ U32 bit = (1<<type);
+ if (gPipeline.hasRenderType(type))
+ {
+ llinfos << "Toggling render type mask " << std::hex << bit << " off" << std::dec << llendl;
+ }
+ else
+ {
+ llinfos << "Toggling render type mask " << std::hex << bit << " on" << std::dec << llendl;
+ }
+ gPipeline.toggleRenderType(type);
+}
+
+//static
+BOOL LLPipeline::hasRenderTypeControl(void* data)
+{
+ U32 type = (U32)(intptr_t)data;
+ return gPipeline.hasRenderType(type);
+}
+
+// Allows UI items labeled "Hide foo" instead of "Show foo"
+//static
+BOOL LLPipeline::toggleRenderTypeControlNegated(void* data)
+{
+ S32 type = (S32)(intptr_t)data;
+ return !gPipeline.hasRenderType(type);
+}
+
+//static
+void LLPipeline::toggleRenderDebug(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ if (gPipeline.hasRenderDebugMask(bit))
+ {
+ llinfos << "Toggling render debug mask " << std::hex << bit << " off" << std::dec << llendl;
+ }
+ else
+ {
+ llinfos << "Toggling render debug mask " << std::hex << bit << " on" << std::dec << llendl;
+ }
+ gPipeline.mRenderDebugMask ^= bit;
+}
+
+
+//static
+BOOL LLPipeline::toggleRenderDebugControl(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ return gPipeline.hasRenderDebugMask(bit);
+}
+
+//static
+void LLPipeline::toggleRenderDebugFeature(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ gPipeline.mRenderDebugFeatureMask ^= bit;
+}
+
+
+//static
+BOOL LLPipeline::toggleRenderDebugFeatureControl(void* data)
+{
+ U32 bit = (U32)(intptr_t)data;
+ return gPipeline.hasRenderDebugFeatureMask(bit);
+}
+
+// static
+void LLPipeline::setRenderScriptedBeacons(BOOL val)
+{
+ sRenderScriptedBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderScriptedBeacons(void*)
+{
+ sRenderScriptedBeacons = !sRenderScriptedBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderScriptedBeacons(void*)
+{
+ return sRenderScriptedBeacons;
+}
+
+// static
+void LLPipeline::setRenderScriptedTouchBeacons(BOOL val)
+{
+ sRenderScriptedTouchBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderScriptedTouchBeacons(void*)
+{
+ sRenderScriptedTouchBeacons = !sRenderScriptedTouchBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderScriptedTouchBeacons(void*)
+{
+ return sRenderScriptedTouchBeacons;
+}
+
+// static
+void LLPipeline::setRenderPhysicalBeacons(BOOL val)
+{
+ sRenderPhysicalBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderPhysicalBeacons(void*)
+{
+ sRenderPhysicalBeacons = !sRenderPhysicalBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderPhysicalBeacons(void*)
+{
+ return sRenderPhysicalBeacons;
+}
+
+// static
+void LLPipeline::setRenderParticleBeacons(BOOL val)
+{
+ sRenderParticleBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderParticleBeacons(void*)
+{
+ sRenderParticleBeacons = !sRenderParticleBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderParticleBeacons(void*)
+{
+ return sRenderParticleBeacons;
+}
+
+// static
+void LLPipeline::setRenderSoundBeacons(BOOL val)
+{
+ sRenderSoundBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderSoundBeacons(void*)
+{
+ sRenderSoundBeacons = !sRenderSoundBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderSoundBeacons(void*)
+{
+ return sRenderSoundBeacons;
+}
+
+// static
+void LLPipeline::setRenderBeacons(BOOL val)
+{
+ sRenderBeacons = val;
+}
+
+// static
+void LLPipeline::toggleRenderBeacons(void*)
+{
+ sRenderBeacons = !sRenderBeacons;
+}
+
+// static
+BOOL LLPipeline::getRenderBeacons(void*)
+{
+ return sRenderBeacons;
+}
+
+// static
+void LLPipeline::setRenderHighlights(BOOL val)
+{
+ sRenderHighlight = val;
+}
+
+// static
+void LLPipeline::toggleRenderHighlights(void*)
+{
+ sRenderHighlight = !sRenderHighlight;
+}
+
+// static
+BOOL LLPipeline::getRenderHighlights(void*)
+{
+ return sRenderHighlight;
+}
+
+LLViewerObject* LLPipeline::lineSegmentIntersectInWorld(const LLVector3& start, const LLVector3& end,
+ BOOL pick_transparent,
+ S32* face_hit,
+ LLVector3* intersection, // return the intersection point
+ LLVector2* tex_coord, // return the texture coordinates of the intersection point
+ LLVector3* normal, // return the surface normal at the intersection point
+ LLVector3* bi_normal // return the surface bi-normal at the intersection point
+ )
+{
+ LLDrawable* drawable = NULL;
+
+ LLVector3 local_end = end;
+
+ LLVector3 position;
+
+ sPickAvatar = FALSE; //LLToolMgr::getInstance()->inBuildMode() ? FALSE : TRUE;
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ for (U32 j = 0; j < LLViewerRegion::NUM_PARTITIONS; j++)
+ {
+ if ((j == LLViewerRegion::PARTITION_VOLUME) ||
+ (j == LLViewerRegion::PARTITION_BRIDGE) ||
+ (j == LLViewerRegion::PARTITION_TERRAIN) ||
+ (j == LLViewerRegion::PARTITION_TREE) ||
+ (j == LLViewerRegion::PARTITION_GRASS)) // only check these partitions for now
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(j);
+ if (part && hasRenderType(part->mDrawableType))
+ {
+ LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
+ if (hit)
+ {
+ drawable = hit;
+ local_end = position;
+ }
+ }
+ }
+ }
+ }
+
+ if (!sPickAvatar)
+ {
+ //save hit info in case we need to restore
+ //due to attachment override
+ LLVector3 local_normal;
+ LLVector3 local_binormal;
+ LLVector2 local_texcoord;
+ S32 local_face_hit = -1;
+
+ if (face_hit)
+ {
+ local_face_hit = *face_hit;
+ }
+ if (tex_coord)
+ {
+ local_texcoord = *tex_coord;
+ }
+ if (bi_normal)
+ {
+ local_binormal = *bi_normal;
+ }
+ if (normal)
+ {
+ local_normal = *normal;
+ }
+
+ const F32 ATTACHMENT_OVERRIDE_DIST = 0.1f;
+
+ //check against avatars
+ sPickAvatar = TRUE;
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_BRIDGE);
+ if (part && hasRenderType(part->mDrawableType))
+ {
+ LLDrawable* hit = part->lineSegmentIntersect(start, local_end, pick_transparent, face_hit, &position, tex_coord, normal, bi_normal);
+ if (hit)
+ {
+ if (!drawable ||
+ !drawable->getVObj()->isAttachment() ||
+ (position-local_end).magVec() > ATTACHMENT_OVERRIDE_DIST)
+ { //avatar overrides if previously hit drawable is not an attachment or
+ //attachment is far enough away from detected intersection
+ drawable = hit;
+ local_end = position;
+ }
+ else
+ { //prioritize attachments over avatars
+ position = local_end;
+
+ if (face_hit)
+ {
+ *face_hit = local_face_hit;
+ }
+ if (tex_coord)
+ {
+ *tex_coord = local_texcoord;
+ }
+ if (bi_normal)
+ {
+ *bi_normal = local_binormal;
+ }
+ if (normal)
+ {
+ *normal = local_normal;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //check all avatar nametags (silly, isn't it?)
+ for (std::vector< LLCharacter* >::iterator iter = LLCharacter::sInstances.begin();
+ iter != LLCharacter::sInstances.end();
+ ++iter)
+ {
+ LLVOAvatar* av = (LLVOAvatar*) *iter;
+ if (av->mNameText.notNull()
+ && av->mNameText->lineSegmentIntersect(start, local_end, position))
+ {
+ drawable = av->mDrawable;
+ local_end = position;
+ }
+ }
+
+ if (intersection)
+ {
+ *intersection = position;
+ }
+
+ return drawable ? drawable->getVObj().get() : NULL;
+}
+
+LLViewerObject* LLPipeline::lineSegmentIntersectInHUD(const LLVector3& start, const LLVector3& end,
+ BOOL pick_transparent,
+ S32* face_hit,
+ LLVector3* intersection, // return the intersection point
+ LLVector2* tex_coord, // return the texture coordinates of the intersection point
+ LLVector3* normal, // return the surface normal at the intersection point
+ LLVector3* bi_normal // return the surface bi-normal at the intersection point
+ )
+{
+ LLDrawable* drawable = NULL;
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+
+ BOOL toggle = FALSE;
+ if (!hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ toggle = TRUE;
+ }
+
+ LLSpatialPartition* part = region->getSpatialPartition(LLViewerRegion::PARTITION_HUD);
+ if (part)
+ {
+ LLDrawable* hit = part->lineSegmentIntersect(start, end, pick_transparent, face_hit, intersection, tex_coord, normal, bi_normal);
+ if (hit)
+ {
+ drawable = hit;
+ }
+ }
+
+ if (toggle)
+ {
+ toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ }
+ }
+ return drawable ? drawable->getVObj().get() : NULL;
+}
+
+LLSpatialPartition* LLPipeline::getSpatialPartition(LLViewerObject* vobj)
+{
+ if (vobj)
+ {
+ LLViewerRegion* region = vobj->getRegion();
+ if (region)
+ {
+ return region->getSpatialPartition(vobj->getPartitionType());
+ }
+ }
+ return NULL;
+}
+
+
+void LLPipeline::resetVertexBuffers(LLDrawable* drawable)
+{
+ if (!drawable || drawable->isDead())
+ {
+ return;
+ }
+
+ for (S32 i = 0; i < drawable->getNumFaces(); i++)
+ {
+ LLFace* facep = drawable->getFace(i);
+ facep->mVertexBuffer = NULL;
+ facep->mLastVertexBuffer = NULL;
+ }
+}
+
+void LLPipeline::resetVertexBuffers()
+{
+ sRenderBump = gSavedSettings.getBOOL("RenderObjectBump");
+ sUseTriStrips = gSavedSettings.getBOOL("RenderUseTriStrips");
+ LLVertexBuffer::sUseStreamDraw = gSavedSettings.getBOOL("RenderUseStreamVBO");
+
+ for (LLWorld::region_list_t::const_iterator iter = LLWorld::getInstance()->getRegionList().begin();
+ iter != LLWorld::getInstance()->getRegionList().end(); ++iter)
+ {
+ LLViewerRegion* region = *iter;
+ for (U32 i = 0; i < LLViewerRegion::NUM_PARTITIONS; i++)
+ {
+ LLSpatialPartition* part = region->getSpatialPartition(i);
+ if (part)
+ {
+ part->resetVertexBuffers();
+ }
+ }
+ }
+
+ resetDrawOrders();
+
+ gSky.resetVertexBuffers();
+
+ if (LLVertexBuffer::sGLCount > 0)
+ {
+ LLVertexBuffer::cleanupClass();
+ }
+
+ //delete all name pool caches
+ LLGLNamePool::cleanupPools();
+
+ if (LLVertexBuffer::sGLCount > 0)
+ {
+ llwarns << "VBO wipe failed." << llendl;
+ }
+
+ if (!LLVertexBuffer::sStreamIBOPool.mNameList.empty() ||
+ !LLVertexBuffer::sStreamVBOPool.mNameList.empty() ||
+ !LLVertexBuffer::sDynamicIBOPool.mNameList.empty() ||
+ !LLVertexBuffer::sDynamicVBOPool.mNameList.empty())
+ {
+ llwarns << "VBO name pool cleanup failed." << llendl;
+ }
+
+ LLVertexBuffer::unbind();
+
+ LLPipeline::sTextureBindTest = gSavedSettings.getBOOL("RenderDebugTextureBind");
+}
+
+void LLPipeline::renderObjects(U32 type, U32 mask, BOOL texture)
+{
+ LLMemType mt_ro(LLMemType::MTYPE_PIPELINE_RENDER_OBJECTS);
+ assertInitialized();
+ glLoadMatrixd(gGLModelView);
+ gGLLastMatrix = NULL;
+ mSimplePool->pushBatches(type, mask);
+ glLoadMatrixd(gGLModelView);
+ gGLLastMatrix = NULL;
+}
+
+void LLPipeline::setUseVBO(BOOL use_vbo)
+{
+ if (use_vbo != LLVertexBuffer::sEnableVBOs)
+ {
+ if (use_vbo)
+ {
+ llinfos << "Enabling VBO." << llendl;
+ }
+ else
+ {
+ llinfos << "Disabling VBO." << llendl;
+ }
+
+ resetVertexBuffers();
+ LLVertexBuffer::initClass(use_vbo, gSavedSettings.getBOOL("RenderVBOMappingDisable"));
+ }
+}
+
+void LLPipeline::setDisableVBOMapping(BOOL no_vbo_mapping)
+{
+ if (LLVertexBuffer::sEnableVBOs && no_vbo_mapping != LLVertexBuffer::sDisableVBOMapping)
+ {
+ if (no_vbo_mapping)
+ {
+ llinfos << "Disabling VBO glMapBufferARB." << llendl;
+ }
+ else
+ {
+ llinfos << "Enabling VBO glMapBufferARB." << llendl;
+ }
+
+ resetVertexBuffers();
+ LLVertexBuffer::initClass(true, no_vbo_mapping);
+ }
+}
+
+void apply_cube_face_rotation(U32 face)
+{
+ switch (face)
+ {
+ case 0:
+ glRotatef(90.f, 0, 1, 0);
+ glRotatef(180.f, 1, 0, 0);
+ break;
+ case 2:
+ glRotatef(-90.f, 1, 0, 0);
+ break;
+ case 4:
+ glRotatef(180.f, 0, 1, 0);
+ glRotatef(180.f, 0, 0, 1);
+ break;
+ case 1:
+ glRotatef(-90.f, 0, 1, 0);
+ glRotatef(180.f, 1, 0, 0);
+ break;
+ case 3:
+ glRotatef(90, 1, 0, 0);
+ break;
+ case 5:
+ glRotatef(180, 0, 0, 1);
+ break;
+ }
+}
+
+void validate_framebuffer_object()
+{
+ GLenum status;
+ status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
+ switch(status)
+ {
+ case GL_FRAMEBUFFER_COMPLETE_EXT:
+ //framebuffer OK, no error.
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
+ // frame buffer not OK: probably means unsupported depth buffer format
+ llerrs << "Framebuffer Incomplete Dimensions." << llendl;
+ break;
+ case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
+ // frame buffer not OK: probably means unsupported depth buffer format
+ llerrs << "Framebuffer Incomplete Attachment." << llendl;
+ break;
+ case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
+ /* choose different formats */
+ llerrs << "Framebuffer unsupported." << llendl;
+ break;
+ default:
+ llerrs << "Unknown framebuffer status." << llendl;
+ break;
+ }
+}
+
+void LLPipeline::bindScreenToTexture()
+{
+
+}
+
+static LLFastTimer::DeclareTimer FTM_RENDER_BLOOM("Bloom");
+
+void LLPipeline::renderBloom(BOOL for_snapshot, F32 zoom_factor, int subfield)
+{
+ LLMemType mt_ru(LLMemType::MTYPE_PIPELINE_RENDER_BLOOM);
+ if (!(gPipeline.canUseVertexShaders() &&
+ sRenderGlow))
+ {
+ return;
+ }
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+ assertInitialized();
+
+ if (gUseWireframe)
+ {
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ }
+
+ U32 res_mod = gSavedSettings.getU32("RenderResolutionDivisor");
+
+ LLVector2 tc1(0,0);
+ LLVector2 tc2((F32) gViewerWindow->getWorldViewWidthRaw()*2,
+ (F32) gViewerWindow->getWorldViewHeightRaw()*2);
+
+ if (res_mod > 1)
+ {
+ tc2 /= (F32) res_mod;
+ }
+
+ gGL.setColorMask(true, true);
+
+ LLFastTimer ftm(FTM_RENDER_BLOOM);
+ gGL.color4f(1,1,1,1);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable cull(GL_CULL_FACE);
+
+ enableLightsFullbright(LLColor4(1,1,1,1));
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ gGL.setColorMask(true, true);
+ glClearColor(0,0,0,0);
+
+ /*if (for_snapshot)
+ {
+ gGL.getTexUnit(0)->bind(&mGlow[1]);
+ {
+ //LLGLEnable stencil(GL_STENCIL_TEST);
+ //glStencilFunc(GL_NOTEQUAL, 255, 0xFFFFFFFF);
+ //glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ //LLGLDisable blend(GL_BLEND);
+
+ // If the snapshot is constructed from tiles, calculate which
+ // tile we're in.
+
+ //from LLViewerCamera::setPerpsective
+ if (zoom_factor > 1.f)
+ {
+ int pos_y = subfield / llceil(zoom_factor);
+ int pos_x = subfield - (pos_y*llceil(zoom_factor));
+ F32 size = 1.f/zoom_factor;
+
+ tc1.set(pos_x*size, pos_y*size);
+ tc2 = tc1 + LLVector2(size,size);
+ }
+ else
+ {
+ tc2.set(1,1);
+ }
+
+ LLGLEnable blend(GL_BLEND);
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.color4f(1,1,1,1);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,1);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(1,-1);
+
+ gGL.texCoord2f(tc2.mV[0], tc2.mV[1]);
+ gGL.vertex2f(1,1);
+
+ gGL.end();
+
+ gGL.flush();
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+
+ gGL.flush();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ return;
+ }*/
+
+ {
+ {
+ LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
+ mGlow[2].bindTarget();
+ mGlow[2].clear();
+ }
+
+ gGlowExtractProgram.bind();
+ F32 minLum = llmax(gSavedSettings.getF32("RenderGlowMinLuminance"), 0.0f);
+ F32 maxAlpha = gSavedSettings.getF32("RenderGlowMaxExtractAlpha");
+ F32 warmthAmount = gSavedSettings.getF32("RenderGlowWarmthAmount");
+ LLVector3 lumWeights = gSavedSettings.getVector3("RenderGlowLumWeights");
+ LLVector3 warmthWeights = gSavedSettings.getVector3("RenderGlowWarmthWeights");
+ gGlowExtractProgram.uniform1f("minLuminance", minLum);
+ gGlowExtractProgram.uniform1f("maxExtractAlpha", maxAlpha);
+ gGlowExtractProgram.uniform3f("lumWeights", lumWeights.mV[0], lumWeights.mV[1], lumWeights.mV[2]);
+ gGlowExtractProgram.uniform3f("warmthWeights", warmthWeights.mV[0], warmthWeights.mV[1], warmthWeights.mV[2]);
+ gGlowExtractProgram.uniform1f("warmthAmount", warmthAmount);
+ LLGLEnable blend_on(GL_BLEND);
+ LLGLEnable test(GL_ALPHA_TEST);
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+ gGL.setSceneBlendType(LLRender::BT_ADD_WITH_ALPHA);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.getTexUnit(0)->disable();
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
+ gGL.getTexUnit(0)->bind(&mScreen);
+
+ gGL.color4f(1,1,1,1);
+ gPipeline.enableLightsFullbright(LLColor4(1,1,1,1));
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+
+ mGlow[2].flush();
+ }
+
+ tc1.setVec(0,0);
+ tc2.setVec(2,2);
+
+ // power of two between 1 and 1024
+ U32 glowResPow = gSavedSettings.getS32("RenderGlowResolutionPow");
+ const U32 glow_res = llmax(1,
+ llmin(1024, 1 << glowResPow));
+
+ S32 kernel = gSavedSettings.getS32("RenderGlowIterations")*2;
+ F32 delta = gSavedSettings.getF32("RenderGlowWidth") / glow_res;
+ // Use half the glow width if we have the res set to less than 9 so that it looks
+ // almost the same in either case.
+ if (glowResPow < 9)
+ {
+ delta *= 0.5f;
+ }
+ F32 strength = gSavedSettings.getF32("RenderGlowStrength");
+
+ gGlowProgram.bind();
+ gGlowProgram.uniform1f("glowStrength", strength);
+
+ for (S32 i = 0; i < kernel; i++)
+ {
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ {
+ LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
+ mGlow[i%2].bindTarget();
+ mGlow[i%2].clear();
+ }
+
+ if (i == 0)
+ {
+ gGL.getTexUnit(0)->bind(&mGlow[2]);
+ }
+ else
+ {
+ gGL.getTexUnit(0)->bind(&mGlow[(i-1)%2]);
+ }
+
+ if (i%2 == 0)
+ {
+ gGlowProgram.uniform2f("glowDelta", delta, 0);
+ }
+ else
+ {
+ gGlowProgram.uniform2f("glowDelta", 0, delta);
+ }
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ mGlow[i%2].flush();
+ }
+
+ gGlowProgram.unbind();
+
+ if (LLRenderTarget::sUseFBO)
+ {
+ LLFastTimer ftm(FTM_RENDER_BLOOM_FBO);
+ glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+ }
+
+ gGLViewport[0] = gViewerWindow->getWorldViewRectRaw().mLeft;
+ gGLViewport[1] = gViewerWindow->getWorldViewRectRaw().mBottom;
+ gGLViewport[2] = gViewerWindow->getWorldViewRectRaw().getWidth();
+ gGLViewport[3] = gViewerWindow->getWorldViewRectRaw().getHeight();
+ glViewport(gGLViewport[0], gGLViewport[1], gGLViewport[2], gGLViewport[3]);
+
+ tc2.setVec((F32) gViewerWindow->getWorldViewWidthRaw(),
+ (F32) gViewerWindow->getWorldViewHeightRaw());
+
+ gGL.flush();
+
+ LLVertexBuffer::unbind();
+
+ if (LLPipeline::sRenderDeferred && LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ LLGLDisable blend(GL_BLEND);
+ bindDeferredShader(gDeferredGIFinalProgram);
+
+ S32 channel = gDeferredGIFinalProgram.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mScreen.bindTexture(0, channel);
+ }
+
+ gGL.begin(LLRender::TRIANGLE_STRIP);
+ gGL.texCoord2f(tc1.mV[0], tc1.mV[1]);
+ gGL.vertex2f(-1,-1);
+
+ gGL.texCoord2f(tc1.mV[0], tc2.mV[1]);
+ gGL.vertex2f(-1,3);
+
+ gGL.texCoord2f(tc2.mV[0], tc1.mV[1]);
+ gGL.vertex2f(3,-1);
+
+ gGL.end();
+
+ unbindDeferredShader(gDeferredGIFinalProgram);
+ }
+ else
+ {
+
+ if (res_mod > 1)
+ {
+ tc2 /= (F32) res_mod;
+ }
+
+ U32 mask = LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_TEXCOORD1;
+ LLPointer<LLVertexBuffer> buff = new LLVertexBuffer(mask, 0);
+ buff->allocateBuffer(3,0,TRUE);
+
+ LLStrider<LLVector3> v;
+ LLStrider<LLVector2> uv1;
+ LLStrider<LLVector2> uv2;
+
+ buff->getVertexStrider(v);
+ buff->getTexCoord0Strider(uv1);
+ buff->getTexCoord1Strider(uv2);
+
+ uv1[0] = LLVector2(0, 0);
+ uv1[1] = LLVector2(0, 2);
+ uv1[2] = LLVector2(2, 0);
+
+ uv2[0] = LLVector2(0, 0);
+ uv2[1] = LLVector2(0, tc2.mV[1]*2.f);
+ uv2[2] = LLVector2(tc2.mV[0]*2.f, 0);
+
+ v[0] = LLVector3(-1,-1,0);
+ v[1] = LLVector3(-1,3,0);
+ v[2] = LLVector3(3,-1,0);
+
+ buff->setBuffer(0);
+
+ LLGLDisable blend(GL_BLEND);
+
+ //tex unit 0
+ gGL.getTexUnit(0)->setTextureColorBlend(LLTexUnit::TBO_REPLACE, LLTexUnit::TBS_TEX_COLOR);
+
+ gGL.getTexUnit(0)->bind(&mGlow[1]);
+ gGL.getTexUnit(1)->activate();
+ gGL.getTexUnit(1)->enable(LLTexUnit::TT_RECT_TEXTURE);
+
+
+ //tex unit 1
+ gGL.getTexUnit(1)->setTextureColorBlend(LLTexUnit::TBO_ADD, LLTexUnit::TBS_TEX_COLOR, LLTexUnit::TBS_PREV_COLOR);
+
+ gGL.getTexUnit(1)->bind(&mScreen);
+ gGL.getTexUnit(1)->activate();
+
+ LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+
+ buff->setBuffer(mask);
+ buff->drawArrays(LLRender::TRIANGLE_STRIP, 0, 3);
+
+ gGL.getTexUnit(1)->disable();
+ gGL.getTexUnit(1)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ gGL.getTexUnit(0)->activate();
+ gGL.getTexUnit(0)->setTextureBlendType(LLTexUnit::TB_MULT);
+
+ if (LLRenderTarget::sUseFBO)
+ { //copy depth buffer from mScreen to framebuffer
+ LLRenderTarget::copyContentsToFramebuffer(mScreen, 0, 0, mScreen.getWidth(), mScreen.getHeight(),
+ 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+ }
+
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+
+}
+
+static LLFastTimer::DeclareTimer FTM_BIND_DEFERRED("Bind Deferred");
+
+void LLPipeline::bindDeferredShader(LLGLSLShader& shader, U32 light_index, LLRenderTarget* gi_source, LLRenderTarget* last_gi_post, U32 noise_map)
+{
+ LLFastTimer t(FTM_BIND_DEFERRED);
+
+ if (noise_map == 0xFFFFFFFF)
+ {
+ noise_map = mNoiseMap;
+ }
+
+ LLGLState::checkTextureChannels();
+
+ shader.bind();
+ S32 channel = 0;
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(0,channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(1, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(2, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ if (gi_source)
+ {
+ BOOL has_gi = FALSE;
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gi_source->bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gi_source->bindTexture(1, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gi_source->bindTexture(2, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gi_source->bindTexture(1, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gi_source->bindTexture(3, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ last_gi_post->bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ last_gi_post->bindTexture(2, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ last_gi_post->bindTexture(1, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ last_gi_post->bindTexture(3, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH);
+ if (channel > -1)
+ {
+ has_gi = TRUE;
+ gGL.getTexUnit(channel)->bind(gi_source, TRUE);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ stop_glerror();
+
+ glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ glTexParameteri(LLTexUnit::getInternalType(mGIMap.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
+
+ stop_glerror();
+ }
+
+ if (has_gi)
+ {
+ F32 range_x = llmin(mGIRange.mV[0], 1.f);
+ F32 range_y = llmin(mGIRange.mV[1], 1.f);
+
+ LLVector2 scale(range_x,range_y);
+
+ LLVector2 kern[25];
+
+ for (S32 i = 0; i < 5; ++i)
+ {
+ for (S32 j = 0; j < 5; ++j)
+ {
+ S32 idx = i*5+j;
+ kern[idx].mV[0] = (i-2)*0.5f;
+ kern[idx].mV[1] = (j-2)*0.5f;
+ kern[idx].scaleVec(scale);
+ }
+ }
+
+ shader.uniform2fv("gi_kern", 25, (F32*) kern);
+ shader.uniformMatrix4fv("gi_mat", 1, FALSE, mGIMatrix.m);
+ shader.uniformMatrix4fv("gi_mat_proj", 1, FALSE, mGIMatrixProj.m);
+ shader.uniformMatrix4fv("gi_inv_proj", 1, FALSE, mGIInvProj.m);
+ shader.uniformMatrix4fv("gi_norm_mat", 1, FALSE, mGINormalMatrix.m);
+ }
+ }
+
+ /*channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredScreen.bindTexture(3, channel);
+ }*/
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bind(&mDeferredDepth, TRUE);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ stop_glerror();
+
+ glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ glTexParameteri(LLTexUnit::getInternalType(mDeferredDepth.getUsage()), GL_DEPTH_TEXTURE_MODE_ARB, GL_ALPHA);
+
+ stop_glerror();
+
+ glh::matrix4f projection = glh_get_current_projection();
+ glh::matrix4f inv_proj = projection.inverse();
+
+ shader.uniformMatrix4fv("inv_proj", 1, FALSE, inv_proj.m);
+ shader.uniform4f("viewport", (F32) gGLViewport[0],
+ (F32) gGLViewport[1],
+ (F32) gGLViewport[2],
+ (F32) gGLViewport[3]);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, noise_map);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLightFunc);
+ }
+
+ stop_glerror();
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredLight[light_index].bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE);
+ if (channel > -1)
+ {
+ gGL.getTexUnit(channel)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_BLOOM);
+ if (channel > -1)
+ {
+ mGlow[1].bindTexture(0, channel);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ gi_source->bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mEdgeMap.bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredLight[1].bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ if (channel > -1)
+ {
+ mDeferredLight[2].bindTexture(0, channel);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ }
+
+
+ stop_glerror();
+
+ for (U32 i = 0; i < 4; i++)
+ {
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE);
+ stop_glerror();
+ if (channel > -1)
+ {
+ stop_glerror();
+ gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ stop_glerror();
+
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+ stop_glerror();
+ }
+ }
+
+ for (U32 i = 4; i < 6; i++)
+ {
+ channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i);
+ stop_glerror();
+ if (channel > -1)
+ {
+ stop_glerror();
+ gGL.getTexUnit(channel)->bind(&mShadow[i], TRUE);
+ gGL.getTexUnit(channel)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
+ gGL.getTexUnit(channel)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
+ stop_glerror();
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_COMPARE_R_TO_TEXTURE_ARB);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC_ARB, GL_LEQUAL);
+ stop_glerror();
+ }
+ }
+
+ stop_glerror();
+
+ F32 mat[16*6];
+ for (U32 i = 0; i < 16; i++)
+ {
+ mat[i] = mSunShadowMatrix[0].m[i];
+ mat[i+16] = mSunShadowMatrix[1].m[i];
+ mat[i+32] = mSunShadowMatrix[2].m[i];
+ mat[i+48] = mSunShadowMatrix[3].m[i];
+ mat[i+64] = mSunShadowMatrix[4].m[i];
+ mat[i+80] = mSunShadowMatrix[5].m[i];
+ }
+
+ shader.uniformMatrix4fv("shadow_matrix[0]", 6, FALSE, mat);
+ shader.uniformMatrix4fv("shadow_matrix", 6, FALSE, mat);
+
+ stop_glerror();
+
+ channel = shader.enableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+ if (channel > -1)
+ {
+ LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+ if (cube_map)
+ {
+ cube_map->enable(channel);
+ cube_map->bind();
+ F64* m = gGLModelView;
+
+
+ F32 mat[] = { m[0], m[1], m[2],
+ m[4], m[5], m[6],
+ m[8], m[9], m[10] };
+
+ shader.uniform3fv("env_mat[0]", 3, mat);
+ shader.uniform3fv("env_mat", 3, mat);
+ }
+ }
+
+ shader.uniform4fv("shadow_clip", 1, mSunClipPlanes.mV);
+ shader.uniform1f("sun_wash", gSavedSettings.getF32("RenderDeferredSunWash"));
+ shader.uniform1f("shadow_noise", gSavedSettings.getF32("RenderShadowNoise"));
+ shader.uniform1f("blur_size", gSavedSettings.getF32("RenderShadowBlurSize"));
+
+ shader.uniform1f("ssao_radius", gSavedSettings.getF32("RenderSSAOScale"));
+ shader.uniform1f("ssao_max_radius", gSavedSettings.getU32("RenderSSAOMaxScale"));
+
+ F32 ssao_factor = gSavedSettings.getF32("RenderSSAOFactor");
+ shader.uniform1f("ssao_factor", ssao_factor);
+ shader.uniform1f("ssao_factor_inv", 1.0/ssao_factor);
+
+ LLVector3 ssao_effect = gSavedSettings.getVector3("RenderSSAOEffect");
+ F32 matrix_diag = (ssao_effect[0] + 2.0*ssao_effect[1])/3.0;
+ F32 matrix_nondiag = (ssao_effect[0] - ssao_effect[1])/3.0;
+ // This matrix scales (proj of color onto <1/rt(3),1/rt(3),1/rt(3)>) by
+ // value factor, and scales remainder by saturation factor
+ F32 ssao_effect_mat[] = { matrix_diag, matrix_nondiag, matrix_nondiag,
+ matrix_nondiag, matrix_diag, matrix_nondiag,
+ matrix_nondiag, matrix_nondiag, matrix_diag};
+ shader.uniformMatrix3fv("ssao_effect_mat", 1, GL_FALSE, ssao_effect_mat);
+
+ F32 shadow_offset_error = 1.f + gSavedSettings.getF32("RenderShadowOffsetError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
+ F32 shadow_bias_error = 1.f + gSavedSettings.getF32("RenderShadowBiasError") * fabsf(LLViewerCamera::getInstance()->getOrigin().mV[2]);
+
+ shader.uniform2f("screen_res", mDeferredScreen.getWidth(), mDeferredScreen.getHeight());
+ shader.uniform1f("near_clip", LLViewerCamera::getInstance()->getNear()*2.f);
+ shader.uniform1f ("shadow_offset", gSavedSettings.getF32("RenderShadowOffset")*shadow_offset_error);
+ shader.uniform1f("shadow_bias", gSavedSettings.getF32("RenderShadowBias")*shadow_bias_error);
+ shader.uniform1f ("spot_shadow_offset", gSavedSettings.getF32("RenderSpotShadowOffset"));
+ shader.uniform1f("spot_shadow_bias", gSavedSettings.getF32("RenderSpotShadowBias"));
+
+ shader.uniform1f("lum_scale", gSavedSettings.getF32("RenderLuminanceScale"));
+ shader.uniform1f("sun_lum_scale", gSavedSettings.getF32("RenderSunLuminanceScale"));
+ shader.uniform1f("sun_lum_offset", gSavedSettings.getF32("RenderSunLuminanceOffset"));
+ shader.uniform1f("lum_lod", gSavedSettings.getF32("RenderLuminanceDetail"));
+ shader.uniform1f("gi_range", gSavedSettings.getF32("RenderGIRange"));
+ shader.uniform1f("gi_brightness", gSavedSettings.getF32("RenderGIBrightness"));
+ shader.uniform1f("gi_luminance", gSavedSettings.getF32("RenderGILuminance"));
+ shader.uniform1f("gi_edge_weight", gSavedSettings.getF32("RenderGIBlurEdgeWeight"));
+ shader.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness"));
+ shader.uniform1f("gi_sample_width", mGILightRadius);
+ shader.uniform1f("gi_noise", gSavedSettings.getF32("RenderGINoise"));
+ shader.uniform1f("gi_attenuation", gSavedSettings.getF32("RenderGIAttenuation"));
+ shader.uniform1f("gi_ambiance", gSavedSettings.getF32("RenderGIAmbiance"));
+ shader.uniform2f("shadow_res", mShadow[0].getWidth(), mShadow[0].getHeight());
+ shader.uniform2f("proj_shadow_res", mShadow[4].getWidth(), mShadow[4].getHeight());
+ shader.uniform1f("depth_cutoff", gSavedSettings.getF32("RenderEdgeDepthCutoff"));
+ shader.uniform1f("norm_cutoff", gSavedSettings.getF32("RenderEdgeNormCutoff"));
+
+ if (shader.getUniformLocation("norm_mat") >= 0)
+ {
+ glh::matrix4f norm_mat = glh_get_current_modelview().inverse().transpose();
+ shader.uniformMatrix4fv("norm_mat", 1, FALSE, norm_mat.m);
+ }
+}
+
+static LLFastTimer::DeclareTimer FTM_GI_TRACE("Trace");
+static LLFastTimer::DeclareTimer FTM_GI_GATHER("Gather");
+static LLFastTimer::DeclareTimer FTM_SUN_SHADOW("Shadow Map");
+static LLFastTimer::DeclareTimer FTM_SOFTEN_SHADOW("Shadow Soften");
+static LLFastTimer::DeclareTimer FTM_EDGE_DETECTION("Find Edges");
+static LLFastTimer::DeclareTimer FTM_LOCAL_LIGHTS("Local Lights");
+static LLFastTimer::DeclareTimer FTM_ATMOSPHERICS("Atmospherics");
+static LLFastTimer::DeclareTimer FTM_FULLSCREEN_LIGHTS("Fullscreen Lights");
+static LLFastTimer::DeclareTimer FTM_PROJECTORS("Projectors");
+static LLFastTimer::DeclareTimer FTM_POST("Post");
+
+
+void LLPipeline::renderDeferredLighting()
+{
+ if (!sCull)
+ {
+ return;
+ }
+
+ {
+ LLFastTimer ftm(FTM_RENDER_DEFERRED);
+
+ LLViewerCamera* camera = LLViewerCamera::getInstance();
+ {
+ LLGLDepthTest depth(GL_TRUE);
+ mDeferredDepth.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+ 0, 0, mDeferredDepth.getWidth(), mDeferredDepth.getHeight(), GL_DEPTH_BUFFER_BIT, GL_NEAREST);
+ }
+
+ LLGLEnable multisample(GL_MULTISAMPLE_ARB);
+
+ if (gPipeline.hasRenderType(LLPipeline::RENDER_TYPE_HUD))
+ {
+ gPipeline.toggleRenderType(LLPipeline::RENDER_TYPE_HUD);
+ }
+
+ //ati doesn't seem to love actually using the stencil buffer on FBO's
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ glStencilFunc(GL_EQUAL, 1, 0xFFFFFFFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+
+ gGL.setColorMask(true, true);
+
+ //draw a cube around every light
+ LLVertexBuffer::unbind();
+
+ LLGLEnable cull(GL_CULL_FACE);
+ LLGLEnable blend(GL_BLEND);
+
+ glh::matrix4f mat = glh_copy_matrix(gGLModelView);
+
+ F32 vert[] =
+ {
+ -1,1,
+ -1,-3,
+ 3,1,
+ };
+ glVertexPointer(2, GL_FLOAT, 0, vert);
+ glColor3f(1,1,1);
+
+ {
+ setupHWLights(NULL); //to set mSunDir;
+ LLVector4 dir(mSunDir, 0.f);
+ glh::vec4f tc(dir.mV);
+ mat.mult_matrix_vec(tc);
+ glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], 0);
+ }
+
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ mDeferredLight[0].bindTarget();
+
+ if (gSavedSettings.getBOOL("RenderDeferredSSAO") || gSavedSettings.getS32("RenderShadowDetail") > 0)
+ {
+ { //paint shadow/SSAO light map (direct lighting lightmap)
+ LLFastTimer ftm(FTM_SUN_SHADOW);
+ bindDeferredShader(gDeferredSunProgram, 0);
+
+ glClearColor(1,1,1,1);
+ mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0,0,0,0);
+
+ glh::matrix4f inv_trans = glh_get_current_modelview().inverse().transpose();
+
+ const U32 slice = 32;
+ F32 offset[slice*3];
+ for (U32 i = 0; i < 4; i++)
+ {
+ for (U32 j = 0; j < 8; j++)
+ {
+ glh::vec3f v;
+ v.set_value(sinf(6.284f/8*j), cosf(6.284f/8*j), -(F32) i);
+ v.normalize();
+ inv_trans.mult_matrix_vec(v);
+ v.normalize();
+ offset[(i*8+j)*3+0] = v.v[0];
+ offset[(i*8+j)*3+1] = v.v[2];
+ offset[(i*8+j)*3+2] = v.v[1];
+ }
+ }
+
+ gDeferredSunProgram.uniform3fv("offset", slice, offset);
+ gDeferredSunProgram.uniform2f("screenRes", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ stop_glerror();
+ }
+
+ unbindDeferredShader(gDeferredSunProgram);
+ }
+ }
+ else
+ {
+ glClearColor(1,1,1,1);
+ mDeferredLight[0].clear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0,0,0,0);
+ }
+
+ mDeferredLight[0].flush();
+
+ { //global illumination specific block (still experimental)
+ if (gSavedSettings.getBOOL("RenderDeferredBlurLight") &&
+ gSavedSettings.getBOOL("RenderDeferredGI"))
+ {
+ LLFastTimer ftm(FTM_EDGE_DETECTION);
+ //generate edge map
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+
+ {
+ gDeferredEdgeProgram.bind();
+ mEdgeMap.bindTarget();
+ bindDeferredShader(gDeferredEdgeProgram);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ unbindDeferredShader(gDeferredEdgeProgram);
+ mEdgeMap.flush();
+ }
+ }
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ { //get luminance map from previous frame's light map
+ LLGLEnable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+
+ //static F32 fade = 1.f;
+
+ {
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ gLuminanceGatherProgram.bind();
+ gLuminanceGatherProgram.uniform2f("screen_res", mDeferredLight[0].getWidth(), mDeferredLight[0].getHeight());
+ mLuminanceMap.bindTarget();
+ bindDeferredShader(gLuminanceGatherProgram);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ unbindDeferredShader(gLuminanceGatherProgram);
+ mLuminanceMap.flush();
+ gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, mLuminanceMap.getTexture(), true);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_TRILINEAR);
+ glGenerateMipmapEXT(GL_TEXTURE_2D);
+ }
+ }
+
+ { //paint noisy GI map (bounce lighting lightmap)
+ LLFastTimer ftm(FTM_GI_TRACE);
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ mGIMapPost[0].bindTarget();
+
+ bindDeferredShader(gDeferredGIProgram, 0, &mGIMap, 0, mTrueNoiseMap);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ unbindDeferredShader(gDeferredGIProgram);
+ mGIMapPost[0].flush();
+ }
+
+ U32 pass_count = 0;
+ if (gSavedSettings.getBOOL("RenderDeferredBlurLight"))
+ {
+ pass_count = llclamp(gSavedSettings.getU32("RenderGIBlurPasses"), (U32) 1, (U32) 128);
+ }
+
+ for (U32 i = 0; i < pass_count; ++i)
+ { //gather/soften indirect lighting map
+ LLFastTimer ftm(FTM_GI_GATHER);
+ bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[0], NULL, mTrueNoiseMap);
+ F32 blur_size = gSavedSettings.getF32("RenderGIBlurSize")/((F32) i * gSavedSettings.getF32("RenderGIBlurIncrement")+1.f);
+ gDeferredPostGIProgram.uniform2f("delta", 1.f, 0.f);
+ gDeferredPostGIProgram.uniform1f("kern_scale", blur_size);
+ gDeferredPostGIProgram.uniform1f("gi_blur_brightness", gSavedSettings.getF32("RenderGIBlurBrightness"));
+
+ mGIMapPost[1].bindTarget();
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_FALSE);
+ stop_glerror();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ stop_glerror();
+ }
+
+ mGIMapPost[1].flush();
+ unbindDeferredShader(gDeferredPostGIProgram);
+ bindDeferredShader(gDeferredPostGIProgram, 0, &mGIMapPost[1], NULL, mTrueNoiseMap);
+ mGIMapPost[0].bindTarget();
+
+ gDeferredPostGIProgram.uniform2f("delta", 0.f, 1.f);
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_FALSE);
+ stop_glerror();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+ stop_glerror();
+ }
+ mGIMapPost[0].flush();
+ unbindDeferredShader(gDeferredPostGIProgram);
+ }
+ }
+ }
+
+ if (gSavedSettings.getBOOL("RenderDeferredSSAO"))
+ { //soften direct lighting lightmap
+ LLFastTimer ftm(FTM_SOFTEN_SHADOW);
+ //blur lightmap
+ mDeferredLight[1].bindTarget();
+
+ glClearColor(1,1,1,1);
+ mDeferredLight[1].clear(GL_COLOR_BUFFER_BIT);
+ glClearColor(0,0,0,0);
+
+ bindDeferredShader(gDeferredBlurLightProgram);
+
+ LLVector3 go = gSavedSettings.getVector3("RenderShadowGaussian");
+ const U32 kern_length = 4;
+ F32 blur_size = gSavedSettings.getF32("RenderShadowBlurSize");
+ F32 dist_factor = gSavedSettings.getF32("RenderShadowBlurDistFactor");
+
+ // sample symmetrically with the middle sample falling exactly on 0.0
+ F32 x = 0.f;
+
+ LLVector3 gauss[32]; // xweight, yweight, offset
+
+ for (U32 i = 0; i < kern_length; i++)
+ {
+ gauss[i].mV[0] = llgaussian(x, go.mV[0]);
+ gauss[i].mV[1] = llgaussian(x, go.mV[1]);
+ gauss[i].mV[2] = x;
+ x += 1.f;
+ }
+
+ gDeferredBlurLightProgram.uniform2f("delta", 1.f, 0.f);
+ gDeferredBlurLightProgram.uniform1f("dist_factor", dist_factor);
+ gDeferredBlurLightProgram.uniform3fv("kern[0]", kern_length, gauss[0].mV);
+ gDeferredBlurLightProgram.uniform3fv("kern", kern_length, gauss[0].mV);
+ gDeferredBlurLightProgram.uniform1f("kern_scale", blur_size * (kern_length/2.f - 0.5f));
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ stop_glerror();
+ }
+
+ mDeferredLight[1].flush();
+ unbindDeferredShader(gDeferredBlurLightProgram);
+
+ bindDeferredShader(gDeferredBlurLightProgram, 1);
+ mDeferredLight[0].bindTarget();
+
+ gDeferredBlurLightProgram.uniform2f("delta", 0.f, 1.f);
+
+ {
+ LLGLDisable blend(GL_BLEND);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE, GL_ALWAYS);
+ stop_glerror();
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ stop_glerror();
+ }
+ mDeferredLight[0].flush();
+ unbindDeferredShader(gDeferredBlurLightProgram);
+ }
+
+ stop_glerror();
+ glPopMatrix();
+ stop_glerror();
+ glMatrixMode(GL_MODELVIEW);
+ stop_glerror();
+ glPopMatrix();
+ stop_glerror();
+
+ //copy depth and stencil from deferred screen
+ //mScreen.copyContents(mDeferredScreen, 0, 0, mDeferredScreen.getWidth(), mDeferredScreen.getHeight(),
+ // 0, 0, mScreen.getWidth(), mScreen.getHeight(), GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT, GL_NEAREST);
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ mDeferredLight[1].bindTarget();
+ // clear color buffer here (GI) - zeroing alpha (glow) is important or it will accumulate against sky
+ glClearColor(0,0,0,0);
+ mScreen.clear(GL_COLOR_BUFFER_BIT);
+ }
+ else
+ {
+ mScreen.bindTarget();
+ // clear color buffer here - zeroing alpha (glow) is important or it will accumulate against sky
+ glClearColor(0,0,0,0);
+ mScreen.clear(GL_COLOR_BUFFER_BIT);
+ }
+
+ if (gSavedSettings.getBOOL("RenderDeferredAtmospheric"))
+ { //apply sunlight contribution
+ LLFastTimer ftm(FTM_ATMOSPHERICS);
+ bindDeferredShader(gDeferredSoftenProgram, 0, &mGIMapPost[0]);
+ {
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+
+ //full screen blit
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glVertexPointer(2, GL_FLOAT, 0, vert);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+
+ unbindDeferredShader(gDeferredSoftenProgram);
+ }
+
+ { //render sky
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ gPipeline.pushRenderTypeMask();
+
+ gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::END_RENDER_TYPES);
+
+
+ renderGeomPostDeferred(*LLViewerCamera::getInstance());
+ gPipeline.popRenderTypeMask();
+ }
+
+ BOOL render_local = gSavedSettings.getBOOL("RenderDeferredLocalLights");
+ BOOL render_fullscreen = gSavedSettings.getBOOL("RenderDeferredFullscreenLights");
+
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ mDeferredLight[1].flush();
+ mDeferredLight[2].bindTarget();
+ mDeferredLight[2].clear(GL_COLOR_BUFFER_BIT);
+ }
+
+ if (render_local || render_fullscreen)
+ {
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+ std::list<LLVector4> fullscreen_lights;
+ LLDrawable::drawable_list_t spot_lights;
+ LLDrawable::drawable_list_t fullscreen_spot_lights;
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ mTargetShadowSpotLight[i] = NULL;
+ }
+
+ std::list<LLVector4> light_colors;
+
+ F32 v[24];
+ glVertexPointer(3, GL_FLOAT, 0, v);
+ BOOL render_local = gSavedSettings.getBOOL("RenderDeferredLocalLights");
+
+ {
+ bindDeferredShader(gDeferredLightProgram);
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ for (LLDrawable::drawable_set_t::iterator iter = mLights.begin(); iter != mLights.end(); ++iter)
+ {
+ LLDrawable* drawablep = *iter;
+
+ LLVOVolume* volume = drawablep->getVOVolume();
+ if (!volume)
+ {
+ continue;
+ }
+
+ if (volume->isAttachment())
+ {
+ if (!sRenderAttachedLights)
+ {
+ continue;
+ }
+ }
+
+
+ LLVector3 center = drawablep->getPositionAgent();
+ F32* c = center.mV;
+ F32 s = volume->getLightRadius()*1.5f;
+
+ LLColor3 col = volume->getLightColor();
+ col *= volume->getLightIntensity();
+
+ if (col.magVecSquared() < 0.001f)
+ {
+ continue;
+ }
+
+ if (s <= 0.001f)
+ {
+ continue;
+ }
+
+ if (camera->AABBInFrustumNoFarClip(center, LLVector3(s,s,s)) == 0)
+ {
+ continue;
+ }
+
+ sVisibleLightCount++;
+
+ glh::vec3f tc(c);
+ mat.mult_matrix_vec(tc);
+
+ //vertex positions are encoded so the 3 bits of their vertex index
+ //correspond to their axis facing, with bit position 3,2,1 matching
+ //axis facing x,y,z, bit set meaning positive facing, bit clear
+ //meaning negative facing
+ v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000
+ v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001
+ v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010
+ v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011
+
+ v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
+ v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
+ v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
+ v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
+
+ if (camera->getOrigin().mV[0] > c[0] + s + 0.2f ||
+ camera->getOrigin().mV[0] < c[0] - s - 0.2f ||
+ camera->getOrigin().mV[1] > c[1] + s + 0.2f ||
+ camera->getOrigin().mV[1] < c[1] - s - 0.2f ||
+ camera->getOrigin().mV[2] > c[2] + s + 0.2f ||
+ camera->getOrigin().mV[2] < c[2] - s - 0.2f)
+ { //draw box if camera is outside box
+ if (render_local)
+ {
+ if (volume->isLightSpotlight())
+ {
+ drawablep->getVOVolume()->updateSpotLightPriority();
+ spot_lights.push_back(drawablep);
+ continue;
+ }
+
+ LLFastTimer ftm(FTM_LOCAL_LIGHTS);
+ glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+ glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+ glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+ GL_UNSIGNED_BYTE, get_box_fan_indices(camera, center));
+ stop_glerror();
+ }
+ }
+ else if (render_fullscreen)
+ {
+ if (volume->isLightSpotlight())
+ {
+ drawablep->getVOVolume()->updateSpotLightPriority();
+ fullscreen_spot_lights.push_back(drawablep);
+ continue;
+ }
+
+ fullscreen_lights.push_back(LLVector4(tc.v[0], tc.v[1], tc.v[2], s*s));
+ light_colors.push_back(LLVector4(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f));
+ }
+ }
+ unbindDeferredShader(gDeferredLightProgram);
+ }
+
+ if (!spot_lights.empty())
+ {
+ LLGLDepthTest depth(GL_TRUE, GL_FALSE);
+ bindDeferredShader(gDeferredSpotLightProgram);
+
+ gDeferredSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+
+ for (LLDrawable::drawable_list_t::iterator iter = spot_lights.begin(); iter != spot_lights.end(); ++iter)
+ {
+ LLFastTimer ftm(FTM_PROJECTORS);
+ LLDrawable* drawablep = *iter;
+
+ LLVOVolume* volume = drawablep->getVOVolume();
+
+ LLVector3 center = drawablep->getPositionAgent();
+ F32* c = center.mV;
+ F32 s = volume->getLightRadius()*1.5f;
+
+ sVisibleLightCount++;
+
+ glh::vec3f tc(c);
+ mat.mult_matrix_vec(tc);
+
+ setupSpotLight(gDeferredSpotLightProgram, drawablep);
+
+ LLColor3 col = volume->getLightColor();
+ col *= volume->getLightIntensity();
+
+ //vertex positions are encoded so the 3 bits of their vertex index
+ //correspond to their axis facing, with bit position 3,2,1 matching
+ //axis facing x,y,z, bit set meaning positive facing, bit clear
+ //meaning negative facing
+ v[0] = c[0]-s; v[1] = c[1]-s; v[2] = c[2]-s; // 0 - 0000
+ v[3] = c[0]-s; v[4] = c[1]-s; v[5] = c[2]+s; // 1 - 0001
+ v[6] = c[0]-s; v[7] = c[1]+s; v[8] = c[2]-s; // 2 - 0010
+ v[9] = c[0]-s; v[10] = c[1]+s; v[11] = c[2]+s; // 3 - 0011
+
+ v[12] = c[0]+s; v[13] = c[1]-s; v[14] = c[2]-s; // 4 - 0100
+ v[15] = c[0]+s; v[16] = c[1]-s; v[17] = c[2]+s; // 5 - 0101
+ v[18] = c[0]+s; v[19] = c[1]+s; v[20] = c[2]-s; // 6 - 0110
+ v[21] = c[0]+s; v[22] = c[1]+s; v[23] = c[2]+s; // 7 - 0111
+
+ glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+ glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+ glDrawRangeElements(GL_TRIANGLE_FAN, 0, 7, 8,
+ GL_UNSIGNED_BYTE, get_box_fan_indices(camera, center));
+ }
+ gDeferredSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+ unbindDeferredShader(gDeferredSpotLightProgram);
+ }
+
+ {
+ bindDeferredShader(gDeferredMultiLightProgram);
+
+ LLGLDepthTest depth(GL_FALSE);
+
+ //full screen blit
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ U32 count = 0;
+
+ const U32 max_count = 8;
+ LLVector4 light[max_count];
+ LLVector4 col[max_count];
+
+ glVertexPointer(2, GL_FLOAT, 0, vert);
+
+ F32 far_z = 0.f;
+
+ while (!fullscreen_lights.empty())
+ {
+ LLFastTimer ftm(FTM_FULLSCREEN_LIGHTS);
+ light[count] = fullscreen_lights.front();
+ fullscreen_lights.pop_front();
+ col[count] = light_colors.front();
+ light_colors.pop_front();
+
+ far_z = llmin(light[count].mV[2]-sqrtf(light[count].mV[3]), far_z);
+
+ count++;
+ if (count == max_count || fullscreen_lights.empty())
+ {
+ gDeferredMultiLightProgram.uniform1i("light_count", count);
+ gDeferredMultiLightProgram.uniform4fv("light[0]", count, (GLfloat*) light);
+ gDeferredMultiLightProgram.uniform4fv("light", count, (GLfloat*) light);
+ gDeferredMultiLightProgram.uniform4fv("light_col[0]", count, (GLfloat*) col);
+ gDeferredMultiLightProgram.uniform4fv("light_col", count, (GLfloat*) col);
+ gDeferredMultiLightProgram.uniform1f("far_z", far_z);
+ far_z = 0.f;
+ count = 0;
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ }
+ }
+
+ unbindDeferredShader(gDeferredMultiLightProgram);
+
+ bindDeferredShader(gDeferredMultiSpotLightProgram);
+
+ gDeferredMultiSpotLightProgram.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+
+ for (LLDrawable::drawable_list_t::iterator iter = fullscreen_spot_lights.begin(); iter != fullscreen_spot_lights.end(); ++iter)
+ {
+ LLFastTimer ftm(FTM_PROJECTORS);
+ LLDrawable* drawablep = *iter;
+
+ LLVOVolume* volume = drawablep->getVOVolume();
+
+ LLVector3 center = drawablep->getPositionAgent();
+ F32* c = center.mV;
+ F32 s = volume->getLightRadius()*1.5f;
+
+ sVisibleLightCount++;
+
+ glh::vec3f tc(c);
+ mat.mult_matrix_vec(tc);
+
+ setupSpotLight(gDeferredMultiSpotLightProgram, drawablep);
+
+ LLColor3 col = volume->getLightColor();
+ col *= volume->getLightIntensity();
+
+ glTexCoord4f(tc.v[0], tc.v[1], tc.v[2], s*s);
+ glColor4f(col.mV[0], col.mV[1], col.mV[2], volume->getLightFalloff()*0.5f);
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);
+ }
+
+ gDeferredMultiSpotLightProgram.disableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+ unbindDeferredShader(gDeferredMultiSpotLightProgram);
+
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ }
+ }
+
+ gGL.setColorMask(true, true);
+
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) > 2)
+ {
+ mDeferredLight[2].flush();
+
+ mScreen.bindTarget();
+ mScreen.clear(GL_COLOR_BUFFER_BIT);
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+
+ { //mix various light maps (local, sun, gi)
+ LLFastTimer ftm(FTM_POST);
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable test(GL_ALPHA_TEST);
+ LLGLDepthTest depth(GL_FALSE);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+
+ bindDeferredShader(gDeferredPostProgram, 0, &mGIMapPost[0]);
+
+ gDeferredPostProgram.bind();
+
+ LLVertexBuffer::unbind();
+
+ glVertexPointer(2, GL_FLOAT, 0, vert);
+ glColor3f(1,1,1);
+
+ glPushMatrix();
+ glLoadIdentity();
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glDrawArrays(GL_TRIANGLES, 0, 3);
+
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ unbindDeferredShader(gDeferredPostProgram);
+ }
+ }
+ }
+
+ { //render non-deferred geometry (alpha, fullbright, glow)
+ LLGLDisable blend(GL_BLEND);
+ LLGLDisable stencil(GL_STENCIL_TEST);
+
+ pushRenderTypeMask();
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_ALPHA,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_GLOW,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_POST_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_GLOW,
+ LLPipeline::RENDER_TYPE_PASS_GRASS,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+ LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ END_RENDER_TYPES);
+
+ renderGeomPostDeferred(*LLViewerCamera::getInstance());
+ popRenderTypeMask();
+ }
+
+ {
+ //render highlights, etc.
+ renderHighlights();
+ mHighlightFaces.clear();
+
+ renderDebug();
+
+ LLVertexBuffer::unbind();
+
+ if (gPipeline.hasRenderDebugFeatureMask(LLPipeline::RENDER_DEBUG_FEATURE_UI))
+ {
+ // Render debugging beacons.
+ gObjectList.renderObjectBeacons();
+ gObjectList.resetObjectBeacons();
+ }
+ }
+
+ mScreen.flush();
+
+}
+
+void LLPipeline::setupSpotLight(LLGLSLShader& shader, LLDrawable* drawablep)
+{
+ //construct frustum
+ LLVOVolume* volume = drawablep->getVOVolume();
+ LLVector3 params = volume->getSpotLightParams();
+
+ F32 fov = params.mV[0];
+ F32 focus = params.mV[1];
+
+ LLVector3 pos = drawablep->getPositionAgent();
+ LLQuaternion quat = volume->getRenderRotation();
+ LLVector3 scale = volume->getScale();
+
+ //get near clip plane
+ LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+ at_axis *= quat;
+
+ LLVector3 np = pos+at_axis;
+ at_axis.normVec();
+
+ //get origin that has given fov for plane np, at_axis, and given scale
+ F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+
+ LLVector3 origin = np - at_axis*dist;
+
+ //matrix from volume space to agent space
+ LLMatrix4 light_mat(quat, LLVector4(origin,1.f));
+
+ glh::matrix4f light_to_agent((F32*) light_mat.mMatrix);
+ glh::matrix4f light_to_screen = glh_get_current_modelview() * light_to_agent;
+
+ glh::matrix4f screen_to_light = light_to_screen.inverse();
+
+ F32 s = volume->getLightRadius()*1.5f;
+ F32 near_clip = dist;
+ F32 width = scale.mV[VX];
+ F32 height = scale.mV[VY];
+ F32 far_clip = s+dist-scale.mV[VZ];
+
+ F32 fovy = fov * RAD_TO_DEG;
+ F32 aspect = width/height;
+
+ glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ glh::vec3f p1(0, 0, -(near_clip+0.01f));
+ glh::vec3f p2(0, 0, -(near_clip+1.f));
+
+ glh::vec3f screen_origin(0, 0, 0);
+
+ light_to_screen.mult_matrix_vec(p1);
+ light_to_screen.mult_matrix_vec(p2);
+ light_to_screen.mult_matrix_vec(screen_origin);
+
+ glh::vec3f n = p2-p1;
+ n.normalize();
+
+ F32 proj_range = far_clip - near_clip;
+ glh::matrix4f light_proj = gl_perspective(fovy, aspect, near_clip, far_clip);
+ screen_to_light = trans * light_proj * screen_to_light;
+ shader.uniformMatrix4fv("proj_mat", 1, FALSE, screen_to_light.m);
+ shader.uniform1f("proj_near", near_clip);
+ shader.uniform3fv("proj_p", 1, p1.v);
+ shader.uniform3fv("proj_n", 1, n.v);
+ shader.uniform3fv("proj_origin", 1, screen_origin.v);
+ shader.uniform1f("proj_range", proj_range);
+ shader.uniform1f("proj_ambiance", params.mV[2]);
+ S32 s_idx = -1;
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ if (mShadowSpotLight[i] == drawablep)
+ {
+ s_idx = i;
+ }
+ }
+
+ shader.uniform1i("proj_shadow_idx", s_idx);
+
+ if (s_idx >= 0)
+ {
+ shader.uniform1f("shadow_fade", 1.f-mSpotLightFade[s_idx]);
+ }
+ else
+ {
+ shader.uniform1f("shadow_fade", 1.f);
+ }
+
+ {
+ LLDrawable* potential = drawablep;
+ //determine if this is a good light for casting shadows
+ F32 m_pri = volume->getSpotLightPriority();
+
+ for (U32 i = 0; i < 2; i++)
+ {
+ F32 pri = 0.f;
+
+ if (mTargetShadowSpotLight[i].notNull())
+ {
+ pri = mTargetShadowSpotLight[i]->getVOVolume()->getSpotLightPriority();
+ }
+
+ if (m_pri > pri)
+ {
+ LLDrawable* temp = mTargetShadowSpotLight[i];
+ mTargetShadowSpotLight[i] = potential;
+ potential = temp;
+ m_pri = pri;
+ }
+ }
+ }
+
+ LLViewerTexture* img = volume->getLightTexture();
+
+ S32 channel = shader.enableTexture(LLViewerShaderMgr::DEFERRED_PROJECTION);
+
+ if (channel > -1 && img)
+ {
+ gGL.getTexUnit(channel)->bind(img);
+
+ F32 lod_range = logf(img->getWidth())/logf(2.f);
+
+ shader.uniform1f("proj_focus", focus);
+ shader.uniform1f("proj_lod", lod_range);
+ shader.uniform1f("proj_ambient_lod", llclamp((proj_range-focus)/proj_range*lod_range, 0.f, 1.f));
+ }
+}
+
+void LLPipeline::unbindDeferredShader(LLGLSLShader &shader)
+{
+ stop_glerror();
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_POSITION, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_NORMAL, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_DIFFUSE, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_SPECULAR, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_DEPTH, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_EDGE, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_SUN_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_LOCAL_LIGHT, LLTexUnit::TT_RECT_TEXTURE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_LUMINANCE);
+ shader.disableTexture(LLViewerShaderMgr::DIFFUSE_MAP);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIP);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_BLOOM);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_NORMAL);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DIFFUSE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_SPECULAR);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_DEPTH);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MIN_POS);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_MAX_POS);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_NORMAL);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_DIFFUSE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MIN_POS);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_GI_LAST_MAX_POS);
+
+ for (U32 i = 0; i < 4; i++)
+ {
+ if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i, LLTexUnit::TT_RECT_TEXTURE) > -1)
+ {
+ glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ }
+ }
+
+ for (U32 i = 4; i < 6; i++)
+ {
+ if (shader.disableTexture(LLViewerShaderMgr::DEFERRED_SHADOW0+i) > -1)
+ {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE_ARB, GL_NONE);
+ }
+ }
+
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_NOISE);
+ shader.disableTexture(LLViewerShaderMgr::DEFERRED_LIGHTFUNC);
+
+ S32 channel = shader.disableTexture(LLViewerShaderMgr::ENVIRONMENT_MAP, LLTexUnit::TT_CUBE_MAP);
+ if (channel > -1)
+ {
+ LLCubeMap* cube_map = gSky.mVOSkyp ? gSky.mVOSkyp->getCubeMap() : NULL;
+ if (cube_map)
+ {
+ cube_map->disable();
+ }
+ }
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ gGL.getTexUnit(0)->activate();
+ shader.unbind();
+
+ LLGLState::checkTextureChannels();
+}
+
+inline float sgn(float a)
+{
+ if (a > 0.0F) return (1.0F);
+ if (a < 0.0F) return (-1.0F);
+ return (0.0F);
+}
+
+void LLPipeline::generateWaterReflection(LLCamera& camera_in)
+{
+ if (LLPipeline::sWaterReflections && assertInitialized() && LLDrawPoolWater::sNeedsReflectionUpdate)
+ {
+ BOOL skip_avatar_update = FALSE;
+ if (!isAgentAvatarValid() || gAgentCamera.getCameraAnimating() || gAgentCamera.getCameraMode() != CAMERA_MODE_MOUSELOOK)
+ {
+ skip_avatar_update = TRUE;
+ }
+
+ if (!skip_avatar_update)
+ {
+ gAgentAvatarp->updateAttachmentVisibility(CAMERA_MODE_THIRD_PERSON);
+ }
+ LLVertexBuffer::unbind();
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ LLCamera camera = camera_in;
+ camera.setFar(camera.getFar()*0.87654321f);
+ LLPipeline::sReflectionRender = TRUE;
+ S32 occlusion = LLPipeline::sUseOcclusion;
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_WORLD;
+
+ LLPipeline::sUseOcclusion = llmin(occlusion, 1);
+
+ gPipeline.pushRenderTypeMask();
+
+ glh::matrix4f projection = glh_get_current_projection();
+ glh::matrix4f mat;
+
+ stop_glerror();
+ LLPlane plane;
+
+ F32 height = gAgent.getRegion()->getWaterHeight();
+ F32 to_clip = fabsf(camera.getOrigin().mV[2]-height);
+ F32 pad = -to_clip*0.05f; //amount to "pad" clip plane by
+
+ //plane params
+ LLVector3 pnorm;
+ F32 pd;
+
+ S32 water_clip = 0;
+ if (!LLViewerCamera::getInstance()->cameraUnderWater())
+ { //camera is above water, clip plane points up
+ pnorm.setVec(0,0,1);
+ pd = -height;
+ plane.setVec(pnorm, pd);
+ water_clip = -1;
+ }
+ else
+ { //camera is below water, clip plane points down
+ pnorm = LLVector3(0,0,-1);
+ pd = height;
+ plane.setVec(pnorm, pd);
+ water_clip = 1;
+ }
+
+ if (!LLViewerCamera::getInstance()->cameraUnderWater())
+ { //generate planar reflection map
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ glClearColor(0,0,0,0);
+ mWaterRef.bindTarget();
+ gGL.setColorMask(true, true);
+ mWaterRef.clear();
+ gGL.setColorMask(true, false);
+
+ mWaterRef.getViewport(gGLViewport);
+
+ stop_glerror();
+
+ glPushMatrix();
+
+ mat.set_scale(glh::vec3f(1,1,-1));
+ mat.set_translate(glh::vec3f(0,0,height*2.f));
+
+ glh::matrix4f current = glh_get_current_modelview();
+
+ mat = current * mat;
+
+ glh_set_current_modelview(mat);
+ glLoadMatrixf(mat.m);
+
+ LLViewerCamera::updateFrustumPlanes(camera, FALSE, TRUE);
+
+ glh::matrix4f inv_mat = mat.inverse();
+
+ glh::vec3f origin(0,0,0);
+ inv_mat.mult_matrix_vec(origin);
+
+ camera.setOrigin(origin.v);
+
+ glCullFace(GL_FRONT);
+
+ static LLCullResult ref_result;
+
+ if (LLDrawPoolWater::sNeedsDistortionUpdate)
+ {
+ //initial sky pass (no user clip plane)
+ { //mask out everything but the sky
+ gPipeline.pushRenderTypeMask();
+ gPipeline.andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::END_RENDER_TYPES);
+ static LLCullResult result;
+ updateCull(camera, result);
+ stateSort(camera, result);
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ LLPipeline::END_RENDER_TYPES);
+
+ renderGeom(camera, TRUE);
+ gPipeline.popRenderTypeMask();
+ }
+
+ gPipeline.pushRenderTypeMask();
+
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::END_RENDER_TYPES);
+
+ S32 detail = gSavedSettings.getS32("RenderReflectionDetail");
+ if (detail > 0)
+ { //mask out selected geometry based on reflection detail
+ if (detail < 4)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_PARTICLES, END_RENDER_TYPES);
+ if (detail < 3)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
+ if (detail < 2)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME, END_RENDER_TYPES);
+ }
+ }
+ }
+
+ LLGLUserClipPlane clip_plane(plane, mat, projection);
+ LLGLDisable cull(GL_CULL_FACE);
+ updateCull(camera, ref_result, 1);
+ stateSort(camera, ref_result);
+ }
+
+ if (LLDrawPoolWater::sNeedsDistortionUpdate)
+ {
+ if (gSavedSettings.getS32("RenderReflectionDetail") > 0)
+ {
+ gPipeline.grabReferences(ref_result);
+ LLGLUserClipPlane clip_plane(plane, mat, projection);
+ renderGeom(camera);
+ }
+ }
+
+ gPipeline.popRenderTypeMask();
+ }
+ glCullFace(GL_BACK);
+ glPopMatrix();
+ mWaterRef.flush();
+ glh_set_current_modelview(current);
+ }
+
+ camera.setOrigin(camera_in.getOrigin());
+ //render distortion map
+ static BOOL last_update = TRUE;
+ if (last_update)
+ {
+ camera.setFar(camera_in.getFar());
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_GROUND,
+ END_RENDER_TYPES);
+ stop_glerror();
+
+ LLPipeline::sUnderWaterRender = LLViewerCamera::getInstance()->cameraUnderWater() ? FALSE : TRUE;
+
+ if (LLPipeline::sUnderWaterRender)
+ {
+ clearRenderTypeMask(LLPipeline::RENDER_TYPE_GROUND,
+ LLPipeline::RENDER_TYPE_SKY,
+ LLPipeline::RENDER_TYPE_CLOUDS,
+ LLPipeline::RENDER_TYPE_WL_SKY,
+ END_RENDER_TYPES);
+ }
+ LLViewerCamera::updateFrustumPlanes(camera);
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ LLColor4& col = LLDrawPoolWater::sWaterFogColor;
+ glClearColor(col.mV[0], col.mV[1], col.mV[2], 0.f);
+ mWaterDis.bindTarget();
+ mWaterDis.getViewport(gGLViewport);
+
+ if (!LLPipeline::sUnderWaterRender || LLDrawPoolWater::sNeedsReflectionUpdate)
+ {
+ //clip out geometry on the same side of water as the camera
+ mat = glh_get_current_modelview();
+ LLGLUserClipPlane clip_plane(LLPlane(-pnorm, -(pd+pad)), mat, projection);
+ static LLCullResult result;
+ updateCull(camera, result, water_clip);
+ stateSort(camera, result);
+
+ gGL.setColorMask(true, true);
+ mWaterDis.clear();
+ gGL.setColorMask(true, false);
+
+ renderGeom(camera);
+ }
+
+ LLPipeline::sUnderWaterRender = FALSE;
+ mWaterDis.flush();
+ }
+ last_update = LLDrawPoolWater::sNeedsReflectionUpdate && LLDrawPoolWater::sNeedsDistortionUpdate;
+
+ LLRenderTarget::unbindTarget();
+
+ LLPipeline::sReflectionRender = FALSE;
+
+ if (!LLRenderTarget::sUseFBO)
+ {
+ glClear(GL_DEPTH_BUFFER_BIT);
+ }
+ glClearColor(0.f, 0.f, 0.f, 0.f);
+ gViewerWindow->setup3DViewport();
+ gPipeline.popRenderTypeMask();
+ LLDrawPoolWater::sNeedsReflectionUpdate = FALSE;
+ LLDrawPoolWater::sNeedsDistortionUpdate = FALSE;
+ LLViewerCamera::getInstance()->setUserClipPlane(LLPlane(-pnorm, -pd));
+ LLPipeline::sUseOcclusion = occlusion;
+
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ if (!skip_avatar_update)
+ {
+ gAgentAvatarp->updateAttachmentVisibility(gAgentCamera.getCameraMode());
+ }
+ }
+}
+
+glh::matrix4f look(const LLVector3 pos, const LLVector3 dir, const LLVector3 up)
+{
+ glh::matrix4f ret;
+
+ LLVector3 dirN;
+ LLVector3 upN;
+ LLVector3 lftN;
+
+ lftN = dir % up;
+ lftN.normVec();
+
+ upN = lftN % dir;
+ upN.normVec();
+
+ dirN = dir;
+ dirN.normVec();
+
+ ret.m[ 0] = lftN[0];
+ ret.m[ 1] = upN[0];
+ ret.m[ 2] = -dirN[0];
+ ret.m[ 3] = 0.f;
+
+ ret.m[ 4] = lftN[1];
+ ret.m[ 5] = upN[1];
+ ret.m[ 6] = -dirN[1];
+ ret.m[ 7] = 0.f;
+
+ ret.m[ 8] = lftN[2];
+ ret.m[ 9] = upN[2];
+ ret.m[10] = -dirN[2];
+ ret.m[11] = 0.f;
+
+ ret.m[12] = -(lftN*pos);
+ ret.m[13] = -(upN*pos);
+ ret.m[14] = dirN*pos;
+ ret.m[15] = 1.f;
+
+ return ret;
+}
+
+glh::matrix4f scale_translate_to_fit(const LLVector3 min, const LLVector3 max)
+{
+ glh::matrix4f ret;
+ ret.m[ 0] = 2/(max[0]-min[0]);
+ ret.m[ 4] = 0;
+ ret.m[ 8] = 0;
+ ret.m[12] = -(max[0]+min[0])/(max[0]-min[0]);
+
+ ret.m[ 1] = 0;
+ ret.m[ 5] = 2/(max[1]-min[1]);
+ ret.m[ 9] = 0;
+ ret.m[13] = -(max[1]+min[1])/(max[1]-min[1]);
+
+ ret.m[ 2] = 0;
+ ret.m[ 6] = 0;
+ ret.m[10] = 2/(max[2]-min[2]);
+ ret.m[14] = -(max[2]+min[2])/(max[2]-min[2]);
+
+ ret.m[ 3] = 0;
+ ret.m[ 7] = 0;
+ ret.m[11] = 0;
+ ret.m[15] = 1;
+
+ return ret;
+}
+
+static LLFastTimer::DeclareTimer FTM_SHADOW_RENDER("Render Shadows");
+static LLFastTimer::DeclareTimer FTM_SHADOW_ALPHA("Alpha Shadow");
+static LLFastTimer::DeclareTimer FTM_SHADOW_SIMPLE("Simple Shadow");
+
+void LLPipeline::renderShadow(glh::matrix4f& view, glh::matrix4f& proj, LLCamera& shadow_cam, LLCullResult &result, BOOL use_shader, BOOL use_occlusion)
+{
+ LLFastTimer t(FTM_SHADOW_RENDER);
+
+ //clip out geometry on the same side of water as the camera
+ S32 occlude = LLPipeline::sUseOcclusion;
+ if (!use_occlusion)
+ {
+ LLPipeline::sUseOcclusion = 0;
+ }
+ LLPipeline::sShadowRender = TRUE;
+
+ U32 types[] = { LLRenderPass::PASS_SIMPLE, LLRenderPass::PASS_FULLBRIGHT, LLRenderPass::PASS_SHINY, LLRenderPass::PASS_BUMP, LLRenderPass::PASS_FULLBRIGHT_SHINY };
+ LLGLEnable cull(GL_CULL_FACE);
+
+ if (use_shader)
+ {
+ gDeferredShadowProgram.bind();
+ }
+
+ updateCull(shadow_cam, result);
+ stateSort(shadow_cam, result);
+
+ //generate shadow map
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(proj.m);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf(view.m);
+
+ stop_glerror();
+ gGLLastMatrix = NULL;
+
+ {
+ LLGLDepthTest depth(GL_TRUE);
+ glClear(GL_DEPTH_BUFFER_BIT);
+ }
+
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ glColor4f(1,1,1,1);
+
+ stop_glerror();
+
+ gGL.setColorMask(false, false);
+
+ //glCullFace(GL_FRONT);
+
+ {
+ LLFastTimer ftm(FTM_SHADOW_SIMPLE);
+ LLGLDisable test(GL_ALPHA_TEST);
+ gGL.getTexUnit(0)->disable();
+ for (U32 i = 0; i < sizeof(types)/sizeof(U32); ++i)
+ {
+ renderObjects(types[i], LLVertexBuffer::MAP_VERTEX, FALSE);
+ }
+ gGL.getTexUnit(0)->enable(LLTexUnit::TT_TEXTURE);
+ }
+
+ if (use_shader)
+ {
+ gDeferredShadowProgram.unbind();
+ renderGeomShadow(shadow_cam);
+ gDeferredShadowProgram.bind();
+ }
+ else
+ {
+ renderGeomShadow(shadow_cam);
+ }
+
+ {
+ LLFastTimer ftm(FTM_SHADOW_ALPHA);
+ LLGLEnable test(GL_ALPHA_TEST);
+ gGL.setAlphaRejectSettings(LLRender::CF_GREATER, 0.6f);
+ renderObjects(LLRenderPass::PASS_ALPHA_SHADOW, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0 | LLVertexBuffer::MAP_COLOR, TRUE);
+ glColor4f(1,1,1,1);
+ renderObjects(LLRenderPass::PASS_GRASS, LLVertexBuffer::MAP_VERTEX | LLVertexBuffer::MAP_TEXCOORD0, TRUE);
+ gGL.setAlphaRejectSettings(LLRender::CF_DEFAULT);
+ }
+
+ //glCullFace(GL_BACK);
+
+ gGLLastMatrix = NULL;
+ glLoadMatrixd(gGLModelView);
+ doOcclusion(shadow_cam);
+
+ if (use_shader)
+ {
+ gDeferredShadowProgram.unbind();
+ }
+
+ gGL.setColorMask(true, true);
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ gGLLastMatrix = NULL;
+
+ LLPipeline::sUseOcclusion = occlude;
+ LLPipeline::sShadowRender = FALSE;
+}
+
+static LLFastTimer::DeclareTimer FTM_VISIBLE_CLOUD("Visible Cloud");
+BOOL LLPipeline::getVisiblePointCloud(LLCamera& camera, LLVector3& min, LLVector3& max, std::vector<LLVector3>& fp, LLVector3 light_dir)
+{
+ LLFastTimer t(FTM_VISIBLE_CLOUD);
+ //get point cloud of intersection of frust and min, max
+
+ if (getVisibleExtents(camera, min, max))
+ {
+ return FALSE;
+ }
+
+ //get set of planes on bounding box
+ std::vector<LLPlane> bp;
+
+ bp.push_back(LLPlane(min, LLVector3(-1,0,0)));
+ bp.push_back(LLPlane(min, LLVector3(0,-1,0)));
+ bp.push_back(LLPlane(min, LLVector3(0,0,-1)));
+ bp.push_back(LLPlane(max, LLVector3(1,0,0)));
+ bp.push_back(LLPlane(max, LLVector3(0,1,0)));
+ bp.push_back(LLPlane(max, LLVector3(0,0,1)));
+
+ //potential points
+ std::vector<LLVector3> pp;
+
+ //add corners of AABB
+ pp.push_back(LLVector3(min.mV[0], min.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], min.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(min.mV[0], max.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], max.mV[1], min.mV[2]));
+ pp.push_back(LLVector3(min.mV[0], min.mV[1], max.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], min.mV[1], max.mV[2]));
+ pp.push_back(LLVector3(min.mV[0], max.mV[1], max.mV[2]));
+ pp.push_back(LLVector3(max.mV[0], max.mV[1], max.mV[2]));
+
+ //add corners of camera frustum
+ for (U32 i = 0; i < 8; i++)
+ {
+ pp.push_back(camera.mAgentFrustum[i]);
+ }
+
+
+ //bounding box line segments
+ U32 bs[] =
+ {
+ 0,1,
+ 1,3,
+ 3,2,
+ 2,0,
+
+ 4,5,
+ 5,7,
+ 7,6,
+ 6,4,
+
+ 0,4,
+ 1,5,
+ 3,7,
+ 2,6
+ };
+
+ for (U32 i = 0; i < 12; i++)
+ { //for each line segment in bounding box
+ for (U32 j = 0; j < 6; j++)
+ { //for each plane in camera frustum
+ const LLPlane& cp = camera.getAgentPlane(j);
+ const LLVector3& v1 = pp[bs[i*2+0]];
+ const LLVector3& v2 = pp[bs[i*2+1]];
+ const LLVector3 n(cp.mV);
+
+ LLVector3 line = v1-v2;
+
+ F32 d1 = line*n;
+ F32 d2 = -cp.dist(v2);
+
+ F32 t = d2/d1;
+
+ if (t > 0.f && t < 1.f)
+ {
+ LLVector3 intersect = v2+line*t;
+ pp.push_back(intersect);
+ }
+ }
+ }
+
+ //camera frustum line segments
+ const U32 fs[] =
+ {
+ 0,1,
+ 1,2,
+ 2,3,
+ 3,1,
+
+ 4,5,
+ 5,6,
+ 6,7,
+ 7,4,
+
+ 0,4,
+ 1,5,
+ 2,6,
+ 3,7
+ };
+
+ LLVector3 center = (max+min)*0.5f;
+ LLVector3 size = (max-min)*0.5f;
+
+ for (U32 i = 0; i < 12; i++)
+ {
+ for (U32 j = 0; j < 6; ++j)
+ {
+ const LLVector3& v1 = pp[fs[i*2+0]+8];
+ const LLVector3& v2 = pp[fs[i*2+1]+8];
+ const LLPlane& cp = bp[j];
+ const LLVector3 n(cp.mV);
+
+ LLVector3 line = v1-v2;
+
+ F32 d1 = line*n;
+ F32 d2 = -cp.dist(v2);
+
+ F32 t = d2/d1;
+
+ if (t > 0.f && t < 1.f)
+ {
+ LLVector3 intersect = v2+line*t;
+ pp.push_back(intersect);
+ }
+ }
+ }
+
+ LLVector3 ext[] = { min-LLVector3(0.05f,0.05f,0.05f),
+ max+LLVector3(0.05f,0.05f,0.05f) };
+
+ for (U32 i = 0; i < pp.size(); ++i)
+ {
+ bool found = true;
+
+ const F32* p = pp[i].mV;
+
+ for (U32 j = 0; j < 3; ++j)
+ {
+ if (p[j] < ext[0].mV[j] ||
+ p[j] > ext[1].mV[j])
+ {
+ found = false;
+ break;
+ }
+ }
+
+ for (U32 j = 0; j < 6; ++j)
+ {
+ const LLPlane& cp = camera.getAgentPlane(j);
+ F32 dist = cp.dist(pp[i]);
+ if (dist > 0.05f) //point is above some plane, not contained
+ {
+ found = false;
+ break;
+ }
+ }
+
+ if (found)
+ {
+ fp.push_back(pp[i]);
+ }
+ }
+
+ if (fp.empty())
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+void LLPipeline::generateGI(LLCamera& camera, LLVector3& lightDir, std::vector<LLVector3>& vpc)
+{
+ if (LLViewerShaderMgr::instance()->getVertexShaderLevel(LLViewerShaderMgr::SHADER_DEFERRED) < 3)
+ {
+ return;
+ }
+
+ LLVector3 up;
+
+ //LLGLEnable depth_clamp(GL_DEPTH_CLAMP_NV);
+
+ if (lightDir.mV[2] > 0.5f)
+ {
+ up = LLVector3(1,0,0);
+ }
+ else
+ {
+ up = LLVector3(0, 0, 1);
+ }
+
+
+ F32 gi_range = gSavedSettings.getF32("RenderGIRange");
+
+ U32 res = mGIMap.getWidth();
+
+ F32 atten = llmax(gSavedSettings.getF32("RenderGIAttenuation"), 0.001f);
+
+ //set radius to range at which distance attenuation of incoming photons is near 0
+
+ F32 lrad = sqrtf(1.f/(atten*0.01f));
+
+ F32 lrange = lrad+gi_range*0.5f;
+
+ LLVector3 pad(lrange,lrange,lrange);
+
+ glh::matrix4f view = look(LLVector3(128.f,128.f,128.f), lightDir, up);
+
+ LLVector3 cp = camera.getOrigin()+camera.getAtAxis()*(gi_range*0.5f);
+
+ glh::vec3f scp(cp.mV);
+ view.mult_matrix_vec(scp);
+ cp.setVec(scp.v);
+
+ F32 pix_width = lrange/(res*0.5f);
+
+ //move cp to the nearest pix_width
+ for (U32 i = 0; i < 3; i++)
+ {
+ cp.mV[i] = llround(cp.mV[i], pix_width);
+ }
+
+ LLVector3 min = cp-pad;
+ LLVector3 max = cp+pad;
+
+ //set mGIRange to range in tc space[0,1] that covers texture block of intersecting lights around a point
+ mGIRange.mV[0] = (max.mV[0]-min.mV[0])/res;
+ mGIRange.mV[1] = (max.mV[1]-min.mV[1])/res;
+ mGILightRadius = lrad/lrange*0.5f;
+
+ glh::matrix4f proj = gl_ortho(min.mV[0], max.mV[0],
+ min.mV[1], max.mV[1],
+ -max.mV[2], -min.mV[2]);
+
+ LLCamera sun_cam = camera;
+
+ glh::matrix4f eye_view = glh_get_current_modelview();
+
+ //get eye space to camera space matrix
+ mGIMatrix = view*eye_view.inverse();
+ mGINormalMatrix = mGIMatrix.inverse().transpose();
+ mGIInvProj = proj.inverse();
+ mGIMatrixProj = proj*mGIMatrix;
+
+ //translate and scale to [0,1]
+ glh::matrix4f trans(.5f, 0.f, 0.f, .5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ mGIMatrixProj = trans*mGIMatrixProj;
+
+ glh_set_current_modelview(view);
+ glh_set_current_projection(proj);
+
+ LLViewerCamera::updateFrustumPlanes(sun_cam, TRUE, FALSE, TRUE);
+
+ sun_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
+ static LLCullResult result;
+
+ pushRenderTypeMask();
+
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_TREE,
+ LLPipeline::RENDER_TYPE_TERRAIN,
+ LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ END_RENDER_TYPES);
+
+
+
+ S32 occlude = LLPipeline::sUseOcclusion;
+ //LLPipeline::sUseOcclusion = 0;
+ LLPipeline::sShadowRender = TRUE;
+
+ //only render large objects into GI map
+ sMinRenderSize = gSavedSettings.getF32("RenderGIMinRenderSize");
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_GI_SOURCE;
+ mGIMap.bindTarget();
+
+ F64 last_modelview[16];
+ F64 last_projection[16];
+ for (U32 i = 0; i < 16; i++)
+ {
+ last_modelview[i] = gGLLastModelView[i];
+ last_projection[i] = gGLLastProjection[i];
+ gGLLastModelView[i] = mGIModelview.m[i];
+ gGLLastProjection[i] = mGIProjection.m[i];
+ }
+
+ sun_cam.setOrigin(0.f, 0.f, 0.f);
+ updateCull(sun_cam, result);
+ stateSort(sun_cam, result);
+
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLLastModelView[i] = last_modelview[i];
+ gGLLastProjection[i] = last_projection[i];
+ }
+
+ mGIProjection = proj;
+ mGIModelview = view;
+
+ LLGLEnable cull(GL_CULL_FACE);
+
+ //generate GI map
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadMatrixf(proj.m);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadMatrixf(view.m);
+
+ stop_glerror();
+ gGLLastMatrix = NULL;
+
+ mGIMap.clear();
+
+ {
+ //LLGLEnable enable(GL_DEPTH_CLAMP_NV);
+ renderGeomDeferred(camera);
+ }
+
+ mGIMap.flush();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ gGLLastMatrix = NULL;
+
+ LLPipeline::sUseOcclusion = occlude;
+ LLPipeline::sShadowRender = FALSE;
+ sMinRenderSize = 0.f;
+
+ popRenderTypeMask();
+
+}
+
+void LLPipeline::renderHighlight(const LLViewerObject* obj, F32 fade)
+{
+ if (obj && obj->getVolume())
+ {
+ for (LLViewerObject::child_list_t::const_iterator iter = obj->getChildren().begin(); iter != obj->getChildren().end(); ++iter)
+ {
+ renderHighlight(*iter, fade);
+ }
+
+ LLDrawable* drawable = obj->mDrawable;
+ if (drawable)
+ {
+ for (S32 i = 0; i < drawable->getNumFaces(); ++i)
+ {
+ LLFace* face = drawable->getFace(i);
+ if (face)
+ {
+ face->renderSelected(LLViewerTexture::sNullImagep, LLColor4(1,1,1,fade));
+ }
+ }
+ }
+ }
+}
+
+void LLPipeline::generateHighlight(LLCamera& camera)
+{
+ //render highlighted object as white into offscreen render target
+ if (mHighlightObject.notNull())
+ {
+ mHighlightSet.insert(HighlightItem(mHighlightObject));
+ }
+
+ if (!mHighlightSet.empty())
+ {
+ F32 transition = gFrameIntervalSeconds/gSavedSettings.getF32("RenderHighlightFadeTime");
+
+ LLGLDisable test(GL_ALPHA_TEST);
+ LLGLDepthTest depth(GL_FALSE);
+ mHighlight.bindTarget();
+ disableLights();
+ gGL.setColorMask(true, true);
+ mHighlight.clear();
+
+ gGL.getTexUnit(0)->bind(LLViewerFetchedTexture::sWhiteImagep);
+ for (std::set<HighlightItem>::iterator iter = mHighlightSet.begin(); iter != mHighlightSet.end(); )
+ {
+ std::set<HighlightItem>::iterator cur_iter = iter++;
+
+ if (cur_iter->mItem.isNull())
+ {
+ mHighlightSet.erase(cur_iter);
+ continue;
+ }
+
+ if (cur_iter->mItem == mHighlightObject)
+ {
+ cur_iter->incrFade(transition);
+ }
+ else
+ {
+ cur_iter->incrFade(-transition);
+ if (cur_iter->mFade <= 0.f)
+ {
+ mHighlightSet.erase(cur_iter);
+ continue;
+ }
+ }
+
+ renderHighlight(cur_iter->mItem->getVObj(), cur_iter->mFade);
+ }
+
+ mHighlight.flush();
+ gGL.setColorMask(true, false);
+ gViewerWindow->setup3DViewport();
+ }
+}
+
+
+void LLPipeline::generateSunShadow(LLCamera& camera)
+{
+ if (!sRenderDeferred || gSavedSettings.getS32("RenderShadowDetail") <= 0)
+ {
+ return;
+ }
+
+ F64 last_modelview[16];
+ F64 last_projection[16];
+ for (U32 i = 0; i < 16; i++)
+ { //store last_modelview of world camera
+ last_modelview[i] = gGLLastModelView[i];
+ last_projection[i] = gGLLastProjection[i];
+ }
+
+ pushRenderTypeMask();
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_SIMPLE,
+ LLPipeline::RENDER_TYPE_ALPHA,
+ LLPipeline::RENDER_TYPE_GRASS,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_TREE,
+ LLPipeline::RENDER_TYPE_TERRAIN,
+ LLPipeline::RENDER_TYPE_WATER,
+ LLPipeline::RENDER_TYPE_VOIDWATER,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_SHADOW,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_BUMP,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+ END_RENDER_TYPES);
+
+ gGL.setColorMask(false, false);
+
+ //get sun view matrix
+
+ //store current projection/modelview matrix
+ glh::matrix4f saved_proj = glh_get_current_projection();
+ glh::matrix4f saved_view = glh_get_current_modelview();
+ glh::matrix4f inv_view = saved_view.inverse();
+
+ glh::matrix4f view[6];
+ glh::matrix4f proj[6];
+
+ //clip contains parallel split distances for 3 splits
+ LLVector3 clip = gSavedSettings.getVector3("RenderShadowClipPlanes");
+
+ //F32 slope_threshold = gSavedSettings.getF32("RenderShadowSlopeThreshold");
+
+ //far clip on last split is minimum of camera view distance and 128
+ mSunClipPlanes = LLVector4(clip, clip.mV[2] * clip.mV[2]/clip.mV[1]);
+
+ clip = gSavedSettings.getVector3("RenderShadowOrthoClipPlanes");
+ mSunOrthoClipPlanes = LLVector4(clip, clip.mV[2]*clip.mV[2]/clip.mV[1]);
+
+ //currently used for amount to extrude frusta corners for constructing shadow frusta
+ LLVector3 n = gSavedSettings.getVector3("RenderShadowNearDist");
+ //F32 nearDist[] = { n.mV[0], n.mV[1], n.mV[2], n.mV[2] };
+
+ LLVector3 lightDir = -mSunDir;
+ lightDir.normVec();
+
+ glh::vec3f light_dir(lightDir.mV);
+
+ //create light space camera matrix
+
+ LLVector3 at = lightDir;
+
+ LLVector3 up = camera.getAtAxis();
+
+ if (fabsf(up*lightDir) > 0.75f)
+ {
+ up = camera.getUpAxis();
+ }
+
+ /*LLVector3 left = up%at;
+ up = at%left;*/
+
+ up.normVec();
+ at.normVec();
+
+
+ LLCamera main_camera = camera;
+
+ F32 near_clip = 0.f;
+ {
+ //get visible point cloud
+ std::vector<LLVector3> fp;
+
+ main_camera.calcAgentFrustumPlanes(main_camera.mAgentFrustum);
+
+ LLVector3 min,max;
+ getVisiblePointCloud(main_camera,min,max,fp);
+
+ if (fp.empty())
+ {
+ if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowCamera[0] = main_camera;
+ mShadowExtents[0][0] = min;
+ mShadowExtents[0][1] = max;
+
+ mShadowFrustPoints[0].clear();
+ mShadowFrustPoints[1].clear();
+ mShadowFrustPoints[2].clear();
+ mShadowFrustPoints[3].clear();
+ }
+ popRenderTypeMask();
+ return;
+ }
+
+ generateGI(camera, lightDir, fp);
+
+ //get good split distances for frustum
+ for (U32 i = 0; i < fp.size(); ++i)
+ {
+ glh::vec3f v(fp[i].mV);
+ saved_view.mult_matrix_vec(v);
+ fp[i].setVec(v.v);
+ }
+
+ min = fp[0];
+ max = fp[0];
+
+ //get camera space bounding box
+ for (U32 i = 1; i < fp.size(); ++i)
+ {
+ update_min_max(min, max, fp[i]);
+ }
+
+ near_clip = -max.mV[2];
+ F32 far_clip = -min.mV[2]*2.f;
+
+ far_clip = llmin(far_clip, 128.f);
+ far_clip = llmin(far_clip, camera.getFar());
+
+ F32 range = far_clip-near_clip;
+
+ LLVector3 split_exp = gSavedSettings.getVector3("RenderShadowSplitExponent");
+
+ F32 da = 1.f-llmax( fabsf(lightDir*up), fabsf(lightDir*camera.getLeftAxis()) );
+
+ da = powf(da, split_exp.mV[2]);
+
+
+ F32 sxp = split_exp.mV[1] + (split_exp.mV[0]-split_exp.mV[1])*da;
+
+
+ for (U32 i = 0; i < 4; ++i)
+ {
+ F32 x = (F32)(i+1)/4.f;
+ x = powf(x, sxp);
+ mSunClipPlanes.mV[i] = near_clip+range*x;
+ }
+ }
+
+ // convenience array of 4 near clip plane distances
+ F32 dist[] = { near_clip, mSunClipPlanes.mV[0], mSunClipPlanes.mV[1], mSunClipPlanes.mV[2], mSunClipPlanes.mV[3] };
+
+ for (S32 j = 0; j < 4; j++)
+ {
+ if (!hasRenderDebugMask(RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowFrustPoints[j].clear();
+ }
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+j;
+
+ //restore render matrices
+ glh_set_current_modelview(saved_view);
+ glh_set_current_projection(saved_proj);
+
+ LLVector3 eye = camera.getOrigin();
+
+ //camera used for shadow cull/render
+ LLCamera shadow_cam;
+
+ //create world space camera frustum for this split
+ shadow_cam = camera;
+ shadow_cam.setFar(16.f);
+
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+ LLVector3* frust = shadow_cam.mAgentFrustum;
+
+ LLVector3 pn = shadow_cam.getAtAxis();
+
+ LLVector3 min, max;
+
+ //construct 8 corners of split frustum section
+ for (U32 i = 0; i < 4; i++)
+ {
+ LLVector3 delta = frust[i+4]-eye;
+ delta += (frust[i+4]-frust[(i+2)%4+4])*0.05f;
+ delta.normVec();
+ F32 dp = delta*pn;
+ frust[i] = eye + (delta*dist[j]*0.95f)/dp;
+ frust[i+4] = eye + (delta*dist[j+1]*1.05f)/dp;
+ }
+
+ shadow_cam.calcAgentFrustumPlanes(frust);
+ shadow_cam.mFrustumCornerDist = 0.f;
+
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowCamera[j] = shadow_cam;
+ }
+
+ std::vector<LLVector3> fp;
+
+ if (!gPipeline.getVisiblePointCloud(shadow_cam, min, max, fp, lightDir))
+ {
+ //no possible shadow receivers
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowExtents[j][0] = LLVector3();
+ mShadowExtents[j][1] = LLVector3();
+ mShadowCamera[j+4] = shadow_cam;
+ }
+
+ mShadow[j].bindTarget();
+ {
+ LLGLDepthTest depth(GL_TRUE);
+ mShadow[j].clear();
+ }
+ mShadow[j].flush();
+
+ mShadowError.mV[j] = 0.f;
+ mShadowFOV.mV[j] = 0.f;
+
+ continue;
+ }
+
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowExtents[j][0] = min;
+ mShadowExtents[j][1] = max;
+ mShadowFrustPoints[j] = fp;
+ }
+
+
+ //find a good origin for shadow projection
+ LLVector3 origin;
+
+ //get a temporary view projection
+ view[j] = look(camera.getOrigin(), lightDir, -up);
+
+ std::vector<LLVector3> wpf;
+
+ for (U32 i = 0; i < fp.size(); i++)
+ {
+ glh::vec3f p = glh::vec3f(fp[i].mV);
+ view[j].mult_matrix_vec(p);
+ wpf.push_back(LLVector3(p.v));
+ }
+
+ min = wpf[0];
+ max = wpf[0];
+
+ for (U32 i = 0; i < fp.size(); ++i)
+ { //get AABB in camera space
+ update_min_max(min, max, wpf[i]);
+ }
+
+ // Construct a perspective transform with perspective along y-axis that contains
+ // points in wpf
+ //Known:
+ // - far clip plane
+ // - near clip plane
+ // - points in frustum
+ //Find:
+ // - origin
+
+ //get some "interesting" points of reference
+ LLVector3 center = (min+max)*0.5f;
+ LLVector3 size = (max-min)*0.5f;
+ LLVector3 near_center = center;
+ near_center.mV[1] += size.mV[1]*2.f;
+
+
+ //put all points in wpf in quadrant 0, reletive to center of min/max
+ //get the best fit line using least squares
+ F32 bfm = 0.f;
+ F32 bfb = 0.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ wpf[i] -= center;
+ wpf[i].mV[0] = fabsf(wpf[i].mV[0]);
+ wpf[i].mV[2] = fabsf(wpf[i].mV[2]);
+ }
+
+ if (!wpf.empty())
+ {
+ F32 sx = 0.f;
+ F32 sx2 = 0.f;
+ F32 sy = 0.f;
+ F32 sxy = 0.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ sx += wpf[i].mV[0];
+ sx2 += wpf[i].mV[0]*wpf[i].mV[0];
+ sy += wpf[i].mV[1];
+ sxy += wpf[i].mV[0]*wpf[i].mV[1];
+ }
+
+ bfm = (sy*sx-wpf.size()*sxy)/(sx*sx-wpf.size()*sx2);
+ bfb = (sx*sxy-sy*sx2)/(sx*sx-bfm*sx2);
+ }
+
+ {
+ // best fit line is y=bfm*x+bfb
+
+ //find point that is furthest to the right of line
+ F32 off_x = -1.f;
+ LLVector3 lp;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ //y = bfm*x+bfb
+ //x = (y-bfb)/bfm
+ F32 lx = (wpf[i].mV[1]-bfb)/bfm;
+
+ lx = wpf[i].mV[0]-lx;
+
+ if (off_x < lx)
+ {
+ off_x = lx;
+ lp = wpf[i];
+ }
+ }
+
+ //get line with slope bfm through lp
+ // bfb = y-bfm*x
+ bfb = lp.mV[1]-bfm*lp.mV[0];
+
+ //calculate error
+ mShadowError.mV[j] = 0.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ F32 lx = (wpf[i].mV[1]-bfb)/bfm;
+ mShadowError.mV[j] += fabsf(wpf[i].mV[0]-lx);
+ }
+
+ mShadowError.mV[j] /= wpf.size();
+ mShadowError.mV[j] /= size.mV[0];
+
+ if (mShadowError.mV[j] > gSavedSettings.getF32("RenderShadowErrorCutoff"))
+ { //just use ortho projection
+ mShadowFOV.mV[j] = -1.f;
+ origin.clearVec();
+ proj[j] = gl_ortho(min.mV[0], max.mV[0],
+ min.mV[1], max.mV[1],
+ -max.mV[2], -min.mV[2]);
+ }
+ else
+ {
+ //origin is where line x = 0;
+ origin.setVec(0,bfb,0);
+
+ F32 fovz = 1.f;
+ F32 fovx = 1.f;
+
+ LLVector3 zp;
+ LLVector3 xp;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ LLVector3 atz = wpf[i]-origin;
+ atz.mV[0] = 0.f;
+ atz.normVec();
+ if (fovz > -atz.mV[1])
+ {
+ zp = wpf[i];
+ fovz = -atz.mV[1];
+ }
+
+ LLVector3 atx = wpf[i]-origin;
+ atx.mV[2] = 0.f;
+ atx.normVec();
+ if (fovx > -atx.mV[1])
+ {
+ fovx = -atx.mV[1];
+ xp = wpf[i];
+ }
+ }
+
+ fovx = acos(fovx);
+ fovz = acos(fovz);
+
+ F32 cutoff = llmin(gSavedSettings.getF32("RenderShadowFOVCutoff"), 1.4f);
+
+ mShadowFOV.mV[j] = fovx;
+
+ if (fovx < cutoff && fovz > cutoff)
+ {
+ //x is a good fit, but z is too big, move away from zp enough so that fovz matches cutoff
+ F32 d = zp.mV[2]/tan(cutoff);
+ F32 ny = zp.mV[1] + fabsf(d);
+
+ origin.mV[1] = ny;
+
+ fovz = 1.f;
+ fovx = 1.f;
+
+ for (U32 i = 0; i < wpf.size(); ++i)
+ {
+ LLVector3 atz = wpf[i]-origin;
+ atz.mV[0] = 0.f;
+ atz.normVec();
+ fovz = llmin(fovz, -atz.mV[1]);
+
+ LLVector3 atx = wpf[i]-origin;
+ atx.mV[2] = 0.f;
+ atx.normVec();
+ fovx = llmin(fovx, -atx.mV[1]);
+ }
+
+ fovx = acos(fovx);
+ fovz = acos(fovz);
+
+ if (fovx > cutoff || llround(fovz, 0.01f) > cutoff)
+ {
+ // llerrs << "WTF?" << llendl;
+ }
+
+ mShadowFOV.mV[j] = cutoff;
+ }
+
+
+ origin += center;
+
+ F32 ynear = -(max.mV[1]-origin.mV[1]);
+ F32 yfar = -(min.mV[1]-origin.mV[1]);
+
+ if (ynear < 0.1f) //keep a sensible near clip plane
+ {
+ F32 diff = 0.1f-ynear;
+ origin.mV[1] += diff;
+ ynear += diff;
+ yfar += diff;
+ }
+
+ if (fovx > cutoff)
+ { //just use ortho projection
+ origin.clearVec();
+ mShadowError.mV[j] = -1.f;
+ proj[j] = gl_ortho(min.mV[0], max.mV[0],
+ min.mV[1], max.mV[1],
+ -max.mV[2], -min.mV[2]);
+ }
+ else
+ {
+ //get perspective projection
+ view[j] = view[j].inverse();
+
+ glh::vec3f origin_agent(origin.mV);
+
+ //translate view to origin
+ view[j].mult_matrix_vec(origin_agent);
+
+ eye = LLVector3(origin_agent.v);
+
+ if (!hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ mShadowFrustOrigin[j] = eye;
+ }
+
+ view[j] = look(LLVector3(origin_agent.v), lightDir, -up);
+
+ F32 fx = 1.f/tanf(fovx);
+ F32 fz = 1.f/tanf(fovz);
+
+ proj[j] = glh::matrix4f(-fx, 0, 0, 0,
+ 0, (yfar+ynear)/(ynear-yfar), 0, (2.f*yfar*ynear)/(ynear-yfar),
+ 0, 0, -fz, 0,
+ 0, -1.f, 0, 0);
+ }
+ }
+ }
+
+ shadow_cam.setFar(128.f);
+ shadow_cam.setOriginAndLookAt(eye, up, center);
+
+ shadow_cam.setOrigin(0,0,0);
+
+ glh_set_current_modelview(view[j]);
+ glh_set_current_projection(proj[j]);
+
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+ shadow_cam.ignoreAgentFrustumPlane(LLCamera::AGENT_PLANE_NEAR);
+
+ //translate and scale to from [-1, 1] to [0, 1]
+ glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ glh_set_current_modelview(view[j]);
+ glh_set_current_projection(proj[j]);
+
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLLastModelView[i] = mShadowModelview[j].m[i];
+ gGLLastProjection[i] = mShadowProjection[j].m[i];
+ }
+
+ mShadowModelview[j] = view[j];
+ mShadowProjection[j] = proj[j];
+
+
+ mSunShadowMatrix[j] = trans*proj[j]*view[j]*inv_view;
+
+ stop_glerror();
+
+ mShadow[j].bindTarget();
+ mShadow[j].getViewport(gGLViewport);
+
+ {
+ static LLCullResult result[4];
+
+ //LLGLEnable enable(GL_DEPTH_CLAMP_NV);
+ renderShadow(view[j], proj[j], shadow_cam, result[j], TRUE);
+ }
+
+ mShadow[j].flush();
+
+ if (!gPipeline.hasRenderDebugMask(LLPipeline::RENDER_DEBUG_SHADOW_FRUSTA))
+ {
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+ mShadowCamera[j+4] = shadow_cam;
+ }
+ }
+
+
+ //hack to disable projector shadows
+ static bool clear = true;
+ bool gen_shadow = gSavedSettings.getS32("RenderShadowDetail") > 1;
+
+ if (gen_shadow)
+ {
+ clear = true;
+ F32 fade_amt = gFrameIntervalSeconds * llmax(LLViewerCamera::getInstance()->getVelocityStat()->getCurrentPerSec(), 1.f);
+
+ //update shadow targets
+ for (U32 i = 0; i < 2; i++)
+ { //for each current shadow
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW4+i;
+
+ if (mShadowSpotLight[i].notNull() &&
+ (mShadowSpotLight[i] == mTargetShadowSpotLight[0] ||
+ mShadowSpotLight[i] == mTargetShadowSpotLight[1]))
+ { //keep this spotlight
+ mSpotLightFade[i] = llmin(mSpotLightFade[i]+fade_amt, 1.f);
+ }
+ else
+ { //fade out this light
+ mSpotLightFade[i] = llmax(mSpotLightFade[i]-fade_amt, 0.f);
+
+ if (mSpotLightFade[i] == 0.f || mShadowSpotLight[i].isNull())
+ { //faded out, grab one of the pending spots (whichever one isn't already taken)
+ if (mTargetShadowSpotLight[0] != mShadowSpotLight[(i+1)%2])
+ {
+ mShadowSpotLight[i] = mTargetShadowSpotLight[0];
+ }
+ else
+ {
+ mShadowSpotLight[i] = mTargetShadowSpotLight[1];
+ }
+ }
+ }
+ }
+
+ for (S32 i = 0; i < 2; i++)
+ {
+ glh_set_current_modelview(saved_view);
+ glh_set_current_projection(saved_proj);
+
+ if (mShadowSpotLight[i].isNull())
+ {
+ continue;
+ }
+
+ LLVOVolume* volume = mShadowSpotLight[i]->getVOVolume();
+
+ if (!volume)
+ {
+ mShadowSpotLight[i] = NULL;
+ continue;
+ }
+
+ LLDrawable* drawable = mShadowSpotLight[i];
+
+ LLVector3 params = volume->getSpotLightParams();
+ F32 fov = params.mV[0];
+
+ //get agent->light space matrix (modelview)
+ LLVector3 center = drawable->getPositionAgent();
+ LLQuaternion quat = volume->getRenderRotation();
+
+ //get near clip plane
+ LLVector3 scale = volume->getScale();
+ LLVector3 at_axis(0,0,-scale.mV[2]*0.5f);
+ at_axis *= quat;
+
+ LLVector3 np = center+at_axis;
+ at_axis.normVec();
+
+ //get origin that has given fov for plane np, at_axis, and given scale
+ F32 dist = (scale.mV[1]*0.5f)/tanf(fov*0.5f);
+
+ LLVector3 origin = np - at_axis*dist;
+
+ LLMatrix4 mat(quat, LLVector4(origin, 1.f));
+
+ view[i+4] = glh::matrix4f((F32*) mat.mMatrix);
+
+ view[i+4] = view[i+4].inverse();
+
+ //get perspective matrix
+ F32 near_clip = dist+0.01f;
+ F32 width = scale.mV[VX];
+ F32 height = scale.mV[VY];
+ F32 far_clip = dist+volume->getLightRadius()*1.5f;
+
+ F32 fovy = fov * RAD_TO_DEG;
+ F32 aspect = width/height;
+
+ proj[i+4] = gl_perspective(fovy, aspect, near_clip, far_clip);
+
+ //translate and scale to from [-1, 1] to [0, 1]
+ glh::matrix4f trans(0.5f, 0.f, 0.f, 0.5f,
+ 0.f, 0.5f, 0.f, 0.5f,
+ 0.f, 0.f, 0.5f, 0.5f,
+ 0.f, 0.f, 0.f, 1.f);
+
+ glh_set_current_modelview(view[i+4]);
+ glh_set_current_projection(proj[i+4]);
+
+ mSunShadowMatrix[i+4] = trans*proj[i+4]*view[i+4]*inv_view;
+
+ for (U32 j = 0; j < 16; j++)
+ {
+ gGLLastModelView[j] = mShadowModelview[i+4].m[j];
+ gGLLastProjection[j] = mShadowProjection[i+4].m[j];
+ }
+
+ mShadowModelview[i+4] = view[i+4];
+ mShadowProjection[i+4] = proj[i+4];
+
+ LLCamera shadow_cam = camera;
+ shadow_cam.setFar(far_clip);
+ shadow_cam.setOrigin(origin);
+
+ LLViewerCamera::updateFrustumPlanes(shadow_cam, FALSE, FALSE, TRUE);
+
+ stop_glerror();
+
+ mShadow[i+4].bindTarget();
+ mShadow[i+4].getViewport(gGLViewport);
+
+ static LLCullResult result[2];
+
+ LLViewerCamera::sCurCameraID = LLViewerCamera::CAMERA_SHADOW0+i+4;
+
+ renderShadow(view[i+4], proj[i+4], shadow_cam, result[i], FALSE, FALSE);
+
+ mShadow[i+4].flush();
+ }
+ }
+ else
+ {
+ if (clear)
+ {
+ clear = false;
+ for (U32 i = 4; i < 6; i++)
+ {
+ mShadow[i].bindTarget();
+ mShadow[i].clear();
+ mShadow[i].flush();
+ }
+ }
+ }
+
+ if (!gSavedSettings.getBOOL("CameraOffset"))
+ {
+ glh_set_current_modelview(saved_view);
+ glh_set_current_projection(saved_proj);
+ }
+ else
+ {
+ glh_set_current_modelview(view[1]);
+ glh_set_current_projection(proj[1]);
+ glLoadMatrixf(view[1].m);
+ glMatrixMode(GL_PROJECTION);
+ glLoadMatrixf(proj[1].m);
+ glMatrixMode(GL_MODELVIEW);
+ }
+ gGL.setColorMask(true, false);
+
+ for (U32 i = 0; i < 16; i++)
+ {
+ gGLLastModelView[i] = last_modelview[i];
+ gGLLastProjection[i] = last_projection[i];
+ }
+
+ popRenderTypeMask();
+}
+
+void LLPipeline::renderGroups(LLRenderPass* pass, U32 type, U32 mask, BOOL texture)
+{
+ for (LLCullResult::sg_list_t::iterator i = sCull->beginVisibleGroups(); i != sCull->endVisibleGroups(); ++i)
+ {
+ LLSpatialGroup* group = *i;
+ if (!group->isDead() &&
+ (!sUseOcclusion || !group->isOcclusionState(LLSpatialGroup::OCCLUDED)) &&
+ gPipeline.hasRenderType(group->mSpatialPartition->mDrawableType) &&
+ group->mDrawMap.find(type) != group->mDrawMap.end())
+ {
+ pass->renderGroup(group,type,mask,texture);
+ }
+ }
+}
+
+void LLPipeline::generateImpostor(LLVOAvatar* avatar)
+{
+ LLMemType mt_gi(LLMemType::MTYPE_PIPELINE_GENERATE_IMPOSTOR);
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+
+ static LLCullResult result;
+ result.clear();
+ grabReferences(result);
+
+ if (!avatar || !avatar->mDrawable)
+ {
+ return;
+ }
+
+ assertInitialized();
+
+ BOOL muted = LLMuteList::getInstance()->isMuted(avatar->getID());
+
+ pushRenderTypeMask();
+
+ if (muted)
+ {
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_AVATAR, END_RENDER_TYPES);
+ }
+ else
+ {
+ andRenderTypeMask(LLPipeline::RENDER_TYPE_VOLUME,
+ LLPipeline::RENDER_TYPE_AVATAR,
+ LLPipeline::RENDER_TYPE_BUMP,
+ LLPipeline::RENDER_TYPE_GRASS,
+ LLPipeline::RENDER_TYPE_SIMPLE,
+ LLPipeline::RENDER_TYPE_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_ALPHA,
+ LLPipeline::RENDER_TYPE_INVISIBLE,
+ LLPipeline::RENDER_TYPE_PASS_SIMPLE,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA,
+ LLPipeline::RENDER_TYPE_PASS_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_ALPHA_MASK,
+ LLPipeline::RENDER_TYPE_PASS_FULLBRIGHT_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_SHINY,
+ LLPipeline::RENDER_TYPE_PASS_INVISIBLE,
+ LLPipeline::RENDER_TYPE_PASS_INVISI_SHINY,
+ END_RENDER_TYPES);
+ }
+
+ S32 occlusion = sUseOcclusion;
+ sUseOcclusion = 0;
+ sReflectionRender = sRenderDeferred ? FALSE : TRUE;
+ sShadowRender = TRUE;
+ sImpostorRender = TRUE;
+
+ LLViewerCamera* viewer_camera = LLViewerCamera::getInstance();
+ markVisible(avatar->mDrawable, *viewer_camera);
+ LLVOAvatar::sUseImpostors = FALSE;
+
+ LLVOAvatar::attachment_map_t::iterator iter;
+ for (iter = avatar->mAttachmentPoints.begin();
+ iter != avatar->mAttachmentPoints.end();
+ ++iter)
+ {
+ LLViewerJointAttachment *attachment = iter->second;
+ for (LLViewerJointAttachment::attachedobjs_vec_t::iterator attachment_iter = attachment->mAttachedObjects.begin();
+ attachment_iter != attachment->mAttachedObjects.end();
+ ++attachment_iter)
+ {
+ if (LLViewerObject* attached_object = (*attachment_iter))
+ {
+ markVisible(attached_object->mDrawable->getSpatialBridge(), *viewer_camera);
+ }
+ }
+ }
+
+ stateSort(*LLViewerCamera::getInstance(), result);
+
+ const LLVector3* ext = avatar->mDrawable->getSpatialExtents();
+ LLVector3 pos(avatar->getRenderPosition()+avatar->getImpostorOffset());
+
+ LLCamera camera = *viewer_camera;
+
+ camera.lookAt(viewer_camera->getOrigin(), pos, viewer_camera->getUpAxis());
+
+ LLVector2 tdim;
+
+ LLVector3 half_height = (ext[1]-ext[0])*0.5f;
+
+ LLVector3 left = camera.getLeftAxis();
+ left *= left;
+ left.normalize();
+
+ LLVector3 up = camera.getUpAxis();
+ up *= up;
+ up.normalize();
+
+ tdim.mV[0] = fabsf(half_height * left);
+ tdim.mV[1] = fabsf(half_height * up);
+
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ //glh::matrix4f ortho = gl_ortho(-tdim.mV[0], tdim.mV[0], -tdim.mV[1], tdim.mV[1], 1.0, 256.0);
+ F32 distance = (pos-camera.getOrigin()).length();
+ F32 fov = atanf(tdim.mV[1]/distance)*2.f*RAD_TO_DEG;
+ F32 aspect = tdim.mV[0]/tdim.mV[1]; //128.f/256.f;
+ glh::matrix4f persp = gl_perspective(fov, aspect, 1.f, 256.f);
+ glh_set_current_projection(persp);
+ glLoadMatrixf(persp.m);
+
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glh::matrix4f mat;
+ camera.getOpenGLTransform(mat.m);
+
+ mat = glh::matrix4f((GLfloat*) OGL_TO_CFR_ROTATION) * mat;
+
+ glLoadMatrixf(mat.m);
+ glh_set_current_modelview(mat);
+
+ glClearColor(0.0f,0.0f,0.0f,0.0f);
+ gGL.setColorMask(true, true);
+ glStencilMask(0xFFFFFFFF);
+ glClearStencil(0);
+
+ // get the number of pixels per angle
+ F32 pa = gViewerWindow->getWindowHeightRaw() / (RAD_TO_DEG * viewer_camera->getView());
+
+ //get resolution based on angle width and height of impostor (double desired resolution to prevent aliasing)
+ U32 resY = llmin(nhpo2((U32) (fov*pa)), (U32) 512);
+ U32 resX = llmin(nhpo2((U32) (atanf(tdim.mV[0]/distance)*2.f*RAD_TO_DEG*pa)), (U32) 512);
+
+ if (!avatar->mImpostor.isComplete() || resX != avatar->mImpostor.getWidth() ||
+ resY != avatar->mImpostor.getHeight())
+ {
+ avatar->mImpostor.allocate(resX,resY,GL_RGBA,TRUE,TRUE);
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ addDeferredAttachments(avatar->mImpostor);
+ }
+
+ gGL.getTexUnit(0)->bind(&avatar->mImpostor);
+ gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_POINT);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+ }
+
+ LLGLEnable stencil(GL_STENCIL_TEST);
+ glStencilMask(0xFFFFFFFF);
+ glStencilFunc(GL_ALWAYS, 1, 0xFFFFFFFF);
+ glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE);
+
+ {
+ LLGLEnable scissor(GL_SCISSOR_TEST);
+ glScissor(0, 0, resX, resY);
+ avatar->mImpostor.bindTarget();
+ avatar->mImpostor.clear();
+ }
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ stop_glerror();
+ renderGeomDeferred(camera);
+ renderGeomPostDeferred(camera);
+ }
+ else
+ {
+ renderGeom(camera);
+ }
+
+ glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
+ glStencilFunc(GL_EQUAL, 1, 0xFFFFFF);
+
+ { //create alpha mask based on stencil buffer (grey out if muted)
+ LLVector3 left = camera.getLeftAxis()*tdim.mV[0]*2.f;
+ LLVector3 up = camera.getUpAxis()*tdim.mV[1]*2.f;
+
+ if (LLPipeline::sRenderDeferred)
+ {
+ GLuint buff = GL_COLOR_ATTACHMENT0_EXT;
+ glDrawBuffersARB(1, &buff);
+ }
+
+ LLGLEnable blend(muted ? 0 : GL_BLEND);
+
+ if (muted)
+ {
+ gGL.setColorMask(true, true);
+ }
+ else
+ {
+ gGL.setColorMask(false, true);
+ }
+
+ gGL.setSceneBlendType(LLRender::BT_ADD);
+ gGL.getTexUnit(0)->unbind(LLTexUnit::TT_TEXTURE);
+
+ LLGLDepthTest depth(GL_FALSE, GL_FALSE);
+
+ gGL.color4f(1,1,1,1);
+ gGL.color4ub(64,64,64,255);
+ gGL.begin(LLRender::QUADS);
+ gGL.vertex3fv((pos+left-up).mV);
+ gGL.vertex3fv((pos-left-up).mV);
+ gGL.vertex3fv((pos-left+up).mV);
+ gGL.vertex3fv((pos+left+up).mV);
+ gGL.end();
+ gGL.flush();
+
+ gGL.setSceneBlendType(LLRender::BT_ALPHA);
+ }
+
+
+ avatar->mImpostor.flush();
+
+ avatar->setImpostorDim(tdim);
+
+ LLVOAvatar::sUseImpostors = TRUE;
+ sUseOcclusion = occlusion;
+ sReflectionRender = FALSE;
+ sImpostorRender = FALSE;
+ sShadowRender = FALSE;
+ popRenderTypeMask();
+
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+
+ avatar->mNeedsImpostorUpdate = FALSE;
+ avatar->cacheImpostorValues();
+
+ LLVertexBuffer::unbind();
+ LLGLState::checkStates();
+ LLGLState::checkTextureChannels();
+ LLGLState::checkClientArrays();
+}
+
+BOOL LLPipeline::hasRenderBatches(const U32 type) const
+{
+ return sCull->getRenderMapSize(type) > 0;
+}
+
+LLCullResult::drawinfo_list_t::iterator LLPipeline::beginRenderMap(U32 type)
+{
+ return sCull->beginRenderMap(type);
+}
+
+LLCullResult::drawinfo_list_t::iterator LLPipeline::endRenderMap(U32 type)
+{
+ return sCull->endRenderMap(type);
+}
+
+LLCullResult::sg_list_t::iterator LLPipeline::beginAlphaGroups()
+{
+ return sCull->beginAlphaGroups();
+}
+
+LLCullResult::sg_list_t::iterator LLPipeline::endAlphaGroups()
+{
+ return sCull->endAlphaGroups();
+}
+
+BOOL LLPipeline::hasRenderType(const U32 type) const
+{
+ // STORM-365 : LLViewerJointAttachment::setAttachmentVisibility() is setting type to 0 to actually mean "do not render"
+ // We then need to test that value here and return FALSE to prevent attachment to render (in mouselook for instance)
+ // TODO: reintroduce RENDER_TYPE_NONE in LLRenderTypeMask and initialize its mRenderTypeEnabled[RENDER_TYPE_NONE] to FALSE explicitely
+ return (type == 0 ? FALSE : mRenderTypeEnabled[type]);
+}
+
+void LLPipeline::setRenderTypeMask(U32 type, ...)
+{
+ va_list args;
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ mRenderTypeEnabled[type] = TRUE;
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+}
+
+BOOL LLPipeline::hasAnyRenderType(U32 type, ...) const
+{
+ va_list args;
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ if (mRenderTypeEnabled[type])
+ {
+ return TRUE;
+ }
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+
+ return FALSE;
+}
+
+void LLPipeline::pushRenderTypeMask()
+{
+ std::string cur_mask;
+ cur_mask.assign((const char*) mRenderTypeEnabled, sizeof(mRenderTypeEnabled));
+ mRenderTypeEnableStack.push(cur_mask);
+}
+
+void LLPipeline::popRenderTypeMask()
+{
+ if (mRenderTypeEnableStack.empty())
+ {
+ llerrs << "Depleted render type stack." << llendl;
+ }
+
+ memcpy(mRenderTypeEnabled, mRenderTypeEnableStack.top().data(), sizeof(mRenderTypeEnabled));
+ mRenderTypeEnableStack.pop();
+}
+
+void LLPipeline::andRenderTypeMask(U32 type, ...)
+{
+ va_list args;
+
+ BOOL tmp[NUM_RENDER_TYPES];
+ for (U32 i = 0; i < NUM_RENDER_TYPES; ++i)
+ {
+ tmp[i] = FALSE;
+ }
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ if (mRenderTypeEnabled[type])
+ {
+ tmp[type] = TRUE;
+ }
+
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+
+ for (U32 i = 0; i < LLPipeline::NUM_RENDER_TYPES; ++i)
+ {
+ mRenderTypeEnabled[i] = tmp[i];
+ }
+
+}
+
+void LLPipeline::clearRenderTypeMask(U32 type, ...)
+{
+ va_list args;
+
+ va_start(args, type);
+ while (type < END_RENDER_TYPES)
+ {
+ mRenderTypeEnabled[type] = FALSE;
+
+ type = va_arg(args, U32);
+ }
+ va_end(args);
+
+ if (type > END_RENDER_TYPES)
+ {
+ llerrs << "Invalid render type." << llendl;
+ }
+}
+
+
diff --git a/indra/newview/skins/default/xui/en/main_view.xml b/indra/newview/skins/default/xui/en/main_view.xml
index d9991fcae9..e5ae0b950a 100644
--- a/indra/newview/skins/default/xui/en/main_view.xml
+++ b/indra/newview/skins/default/xui/en/main_view.xml
@@ -80,6 +80,13 @@
user_resize="false"
name="hud container"
width="500">
+ <view top="0"
+ follows="all"
+ height="500"
+ left="0"
+ mouse_opaque="false"
+ name="floater_snap_region"
+ width="500"/>
<panel follows="left|top"
height="19"
left="0"
diff --git a/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml b/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml
index 50ad3f834e..5e7b16ed4a 100644
--- a/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml
+++ b/indra/newview/skins/default/xui/en/menu_inspect_self_gear.xml
@@ -1,63 +1,249 @@
-<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<toggleable_menu
- create_jump_keys="true"
- layout="topleft"
- mouse_opaque="false"
- visible="false"
- name="Gear Menu">
+ layout="topleft"
+ name="Self Pie">
<menu_item_call
label="Sit Down"
- enabled="true"
- name="sit_down_here">
+ layout="topleft"
+ name="Sit Down Here">
<menu_item_call.on_click
function="Self.SitDown"
parameter="" />
- <menu_item_call.on_visible
+ <menu_item_call.on_enable
function="Self.EnableSitDown" />
</menu_item_call>
<menu_item_call
label="Stand Up"
- enabled="true"
- name="stand_up">
+ layout="topleft"
+ name="Stand Up">
<menu_item_call.on_click
function="Self.StandUp"
parameter="" />
- <menu_item_call.on_visible
+ <menu_item_call.on_enable
function="Self.EnableStandUp" />
</menu_item_call>
+ <context_menu
+ label="Take Off"
+ layout="topleft"
+ name="Take Off &gt;">
+ <context_menu
+ label="Clothes"
+ layout="topleft"
+ name="Clothes &gt;">
+ <menu_item_call
+ enabled="false"
+ label="Shirt"
+ layout="topleft"
+ name="Shirt">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="shirt" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="shirt" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Pants"
+ layout="topleft"
+ name="Pants">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="pants" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="pants" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Skirt"
+ layout="topleft"
+ name="Skirt">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="skirt" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="skirt" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Shoes"
+ layout="topleft"
+ name="Shoes">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="shoes" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="shoes" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Socks"
+ layout="topleft"
+ name="Socks">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="socks" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="socks" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Jacket"
+ layout="topleft"
+ name="Jacket">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="jacket" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="jacket" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Gloves"
+ layout="topleft"
+ name="Gloves">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="gloves" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="gloves" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Undershirt"
+ layout="topleft"
+ name="Self Undershirt">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="undershirt" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="undershirt" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Underpants"
+ layout="topleft"
+ name="Self Underpants">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="underpants" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="underpants" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Tattoo"
+ layout="topleft"
+ name="Self Tattoo">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="tattoo" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="tattoo" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Alpha"
+ layout="topleft"
+ name="Self Alpha">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="alpha" />
+ <menu_item_call.on_enable
+ function="Edit.EnableTakeOff"
+ parameter="alpha" />
+ </menu_item_call>
+ <menu_item_separator
+ layout="topleft" />
+ <menu_item_call
+ label="All Clothes"
+ layout="topleft"
+ name="All Clothes">
+ <menu_item_call.on_click
+ function="Edit.TakeOff"
+ parameter="all" />
+ </menu_item_call>
+ </context_menu>
+ <context_menu
+ label="HUD"
+ layout="topleft"
+ name="Object Detach HUD" />
+ <context_menu
+ label="Detach"
+ layout="topleft"
+ name="Object Detach" />
+ <menu_item_call
+ label="Detach All"
+ layout="topleft"
+ name="Detach All">
+ <menu_item_call.on_click
+ function="Self.RemoveAllAttachments"
+ parameter="" />
+ <menu_item_call.on_enable
+ function="Self.EnableRemoveAllAttachments" />
+ </menu_item_call>
+ </context_menu>
<menu_item_call
- label="Change Outfit"
- name="change_outfit">
+ label="Change Outfit"
+ layout="topleft"
+ name="Chenge Outfit">
<menu_item_call.on_click
function="CustomizeAvatar" />
<menu_item_call.on_enable
function="Edit.EnableCustomizeAvatar" />
</menu_item_call>
- <menu_item_call
- label="My Profile"
- enabled="true"
- name="my_profile">
+ <menu_item_call label="Edit My Outfit"
+ layout="topleft"
+ name="Edit Outfit">
<menu_item_call.on_click
- function="ShowAgentProfile"
- parameter="agent" />
+ function="EditOutfit" />
+ <menu_item_call.on_enable
+ function="Edit.EnableCustomizeAvatar" />
+ </menu_item_call>
+ <menu_item_call label="Edit My Shape"
+ layout="topleft"
+ name="Edit My Shape">
+ <menu_item_call.on_click
+ function="EditShape" />
+ <menu_item_call.on_enable
+ function="Edit.EnableEditShape" />
</menu_item_call>
<menu_item_call
- label="My Friends"
- name="my_friends">
+ label="My Friends"
+ layout="topleft"
+ name="Friends...">
<menu_item_call.on_click
- function="SideTray.PanelPeopleTab"
- parameter="friends_panel" />
+ function="SideTray.PanelPeopleTab"
+ parameter="friends_panel" />
</menu_item_call>
<menu_item_call
label="My Groups"
- name="my_groups">
+ layout="topleft"
+ name="Groups...">
<menu_item_call.on_click
function="SideTray.PanelPeopleTab"
parameter="groups_panel" />
</menu_item_call>
<menu_item_call
- label="Debug Textures"
- name="Debug...">
+ label="My Profile"
+ layout="topleft"
+ name="Profile...">
+ <menu_item_call.on_click
+ function="ShowAgentProfile"
+ parameter="agent" />
+ </menu_item_call>
+ <menu_item_call
+ label="Debug Textures"
+ name="Debug...">
<menu_item_call.on_click
function="Avatar.Debug" />
<menu_item_call.on_visible
diff --git a/indra/newview/skins/default/xui/en/notifications.xml b/indra/newview/skins/default/xui/en/notifications.xml
index f008042a81..6ecaef1bf3 100644
--- a/indra/newview/skins/default/xui/en/notifications.xml
+++ b/indra/newview/skins/default/xui/en/notifications.xml
@@ -104,6 +104,7 @@
Your version of [APP_NAME] does not know how to display the notification it just received. Please verify that you have the latest Viewer installed.
Error details: The notification called &apos;[_NAME]&apos; was not found in notifications.xml.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -116,6 +117,7 @@ Error details: The notification called &apos;[_NAME]&apos; was not found in noti
Floater error: Could not find the following controls:
[CONTROLS]
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -126,6 +128,7 @@ Floater error: Could not find the following controls:
name="TutorialNotFound"
type="alertmodal">
No tutorial is currently available.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -154,6 +157,7 @@ No tutorial is currently available.
name="BadInstallation"
type="alertmodal">
An error occurred while updating [APP_NAME]. Please [http://get.secondlife.com download the latest version] of the Viewer.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -163,8 +167,9 @@ No tutorial is currently available.
icon="alertmodal.tga"
name="LoginFailedNoNetwork"
type="alertmodal">
-Could not connect to the [SECOND_LIFE_GRID].
-&apos;[DIAGNOSTIC]&apos;
+ <tag>fail</tag>
+ Could not connect to the [SECOND_LIFE_GRID].
+ &apos;[DIAGNOSTIC]&apos;
Make sure your Internet connection is working properly.
<usetemplate
name="okbutton"
@@ -176,6 +181,7 @@ Make sure your Internet connection is working properly.
name="MessageTemplateNotFound"
type="alertmodal">
Message Template [PATH] not found.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -198,6 +204,7 @@ Save changes to current clothing/body part?
name="CompileQueueSaveText"
type="alertmodal">
There was a problem uploading the text for a script due to the following reason: [REASON]. Please try again later.
+ <tag>fail</tag>
</notification>
<notification
@@ -205,6 +212,7 @@ There was a problem uploading the text for a script due to the following reason:
name="CompileQueueSaveBytecode"
type="alertmodal">
There was a problem uploading the compiled script due to the following reason: [REASON]. Please try again later.
+ <tag>fail</tag>
</notification>
<notification
@@ -212,6 +220,7 @@ There was a problem uploading the compiled script due to the following reason: [
name="WriteAnimationFail"
type="alertmodal">
There was a problem writing animation data. Please try again later.
+ <tag>fail</tag>
</notification>
<notification
@@ -219,6 +228,7 @@ There was a problem writing animation data. Please try again later.
name="UploadAuctionSnapshotFail"
type="alertmodal">
There was a problem uploading the auction snapshot due to the following reason: [REASON]
+ <tag>fail</tag>
</notification>
<notification
@@ -227,6 +237,7 @@ There was a problem uploading the auction snapshot due to the following reason:
type="alertmodal">
Unable to view the contents of more than one item at a time.
Please select only one object and try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -234,7 +245,8 @@ Please select only one object and try again.
name="SaveClothingBodyChanges"
type="alertmodal">
Save all changes to clothing/body parts?
- <usetemplate
+<tag>confirm</tag>
+<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
notext="Don&apos;t Save"
@@ -267,6 +279,7 @@ Save all changes to clothing/body parts?
type="alertmodal">
Granting modify rights to another Resident allows them to change, delete or take ANY objects you may have in-world. Be VERY careful when handing out this permission.
Do you want to grant modify rights for [NAME]?
+<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="No"
@@ -279,6 +292,7 @@ Do you want to grant modify rights for [NAME]?
type="alertmodal">
Granting modify rights to another Resident allows them to change ANY objects you may have in-world. Be VERY careful when handing out this permission.
Do you want to grant modify rights for the selected Residents?
+<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="No"
@@ -290,6 +304,7 @@ Do you want to grant modify rights for the selected Residents?
name="RevokeModifyRights"
type="alertmodal">
Do you want to revoke modify rights for [NAME]?
+<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="No"
@@ -301,6 +316,7 @@ Do you want to revoke modify rights for [NAME]?
name="RevokeModifyRightsMultiple"
type="alertmodal">
Do you want to revoke modify rights for the selected Residents?
+<tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="No"
@@ -313,7 +329,9 @@ Do you want to revoke modify rights for the selected Residents?
type="alertmodal">
Unable to create group.
[MESSAGE]
- <usetemplate
+ <tag>group</tag>
+ <tag>fail</tag>
+ <usetemplate
name="okbutton"
yestext="OK"/>
</notification>
@@ -324,7 +342,9 @@ Unable to create group.
type="alertmodal">
[NEEDS_APPLY_MESSAGE]
[WANT_APPLY_MESSAGE]
- <usetemplate
+ <tag>confirm</tag>
+ <tag>group</tag>
+ <usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
notext="Ignore Changes"
@@ -336,7 +356,9 @@ Unable to create group.
name="MustSpecifyGroupNoticeSubject"
type="alertmodal">
You must specify a subject to send a group notice.
- <usetemplate
+ <tag>group</tag>
+ <tag>fail</tag>
+ <usetemplate
name="okbutton"
yestext="OK"/>
</notification>
@@ -349,6 +371,8 @@ You are about to add group members to the role of [ROLE_NAME].
Members cannot be removed from that role.
The members must resign from the role themselves.
Are you sure you want to continue?
+ <tag>group</tag>
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm before I add a new group Owner"
name="okcancelignore"
@@ -394,6 +418,7 @@ Add this Ability to &apos;[ROLE_NAME]&apos;?
type="alertmodal">
You are about to drop your attachment.
Are you sure you want to continue?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm before dropping attachments"
name="okcancelignore"
@@ -406,6 +431,9 @@ Add this Ability to &apos;[ROLE_NAME]&apos;?
type="alertmodal">
Joining this group costs L$[COST].
Do you wish to proceed?
+ <tag>confirm</tag>
+ <tag>funds</tag>
+ <tag>group</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -418,6 +446,8 @@ Do you wish to proceed?
type="alertmodal">
You are joining group [NAME].
Do you wish to proceed?
+ <tag>group</tag>
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -431,6 +461,9 @@ Do you wish to proceed?
type="alertmodal">
Joining this group costs L$[COST].
You do not have enough L$ to join this group.
+ <tag>group</tag>
+ <tag>fail</tag>
+ <tag>funds</tag>
</notification>
<notification
@@ -440,6 +473,8 @@ You do not have enough L$ to join this group.
Creating this group will cost L$100.
Groups need more than one member, or they are deleted forever.
Please invite members within 48 hours.
+ <tag>group</tag>
+ <tag>funds</tag>
<usetemplate
canceltext="Cancel"
name="okcancelbuttons"
@@ -453,6 +488,8 @@ Please invite members within 48 hours.
type="alertmodal">
<tag>fail</tag>
For L$[COST] you can enter this land (&apos;[PARCEL_NAME]&apos;) for [TIME] hours. Buy a pass?
+ <tag>funds</tag>
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -465,6 +502,7 @@ For L$[COST] you can enter this land (&apos;[PARCEL_NAME]&apos;) for [TIME] hour
type="alertmodal">
Sale price must be set to more than L$0 if selling to anyone.
Please select an individual to sell to if selling for L$0.
+ <tag>fail</tag>
</notification>
<notification
@@ -474,6 +512,7 @@ Please select an individual to sell to if selling for L$0.
type="alertmodal">
The selected [LAND_SIZE] m² land is being set for sale.
Your selling price will be L$[SALE_PRICE] and will be authorized for sale to [NAME].
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -488,6 +527,7 @@ ATTENTION: Clicking &apos;sell to anyone&apos; makes your land available to the
The selected [LAND_SIZE] m² land is being set for sale.
Your selling price will be L$[SALE_PRICE] and will be authorized for sale to [NAME].
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -503,6 +543,8 @@ Are you sure you want to return all objects shared with the group &apos;[NAME]&a
*WARNING* This will delete the non-transferable objects deeded to the group!
Objects: [N]
+ <tag>confirm</tag>
+ <tag>group</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -516,6 +558,7 @@ Objects: [N]
Are you sure you want to return all objects owned by the Resident &apos;[NAME]&apos; on this parcel of land back to their inventory?
Objects: [N]
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -529,6 +572,7 @@ Objects: [N]
Are you sure you want to return all objects owned by you on this parcel of land back to your inventory?
Objects: [N]
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -545,6 +589,7 @@ Transferable objects deeded to a group will be returned to their previous owners
*WARNING* This will delete the non-transferable objects deeded to the group!
Objects: [N]
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -561,6 +606,7 @@ Transferable objects deeded to a group will be returned to their previous owners
*WARNING* This will delete the non-transferable objects deeded to the group!
Objects: [N]
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -572,6 +618,7 @@ Objects: [N]
name="ReturnAllTopObjects"
type="alertmodal">
Are you sure you want to return all listed objects back to their owner&apos;s inventory?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -583,6 +630,7 @@ Are you sure you want to return all listed objects back to their owner&apos;s in
name="DisableAllTopObjects"
type="alertmodal">
Are you sure you want to disable all objects in this region?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -596,6 +644,8 @@ Are you sure you want to disable all objects in this region?
Return the objects on this parcel of land that are NOT shared with the group [NAME] back to their owners?
Objects: [N]
+ <tag>confirm</tag>
+ <tag>group</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -609,6 +659,7 @@ Objects: [N]
Can not disable scripts.
This entire region is damage enabled.
Scripts must be allowed to run for weapons to work.
+ <tag>fail</tag>
</notification>
<notification
@@ -618,6 +669,7 @@ Scripts must be allowed to run for weapons to work.
Multiple faces are currently selected.
If you continue this action, separate instances of media will be set on multiple faces of the object.
To place the media on only one face, choose Select Face and click on the desired face of that object then click Add.
+ <tag>confirm</tag>
<usetemplate
ignoretext="Media will be set on multiple selected faces"
name="okcancelignore"
@@ -630,6 +682,7 @@ To place the media on only one face, choose Select Face and click on the desired
name="MustBeInParcel"
type="alertmodal">
You must be standing inside the land parcel to set its Landing Point.
+ <tag>fail</tag>
</notification>
<notification
@@ -637,6 +690,7 @@ You must be standing inside the land parcel to set its Landing Point.
name="PromptRecipientEmail"
type="alertmodal">
Please enter a valid email address for the recipient(s).
+ <tag>fail</tag>
</notification>
<notification
@@ -644,6 +698,7 @@ Please enter a valid email address for the recipient(s).
name="PromptSelfEmail"
type="alertmodal">
Please enter your email address.
+ <tag>fail</tag>
</notification>
<notification
@@ -651,6 +706,7 @@ Please enter your email address.
name="PromptMissingSubjMsg"
type="alertmodal">
Email snapshot with the default subject or message?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -662,6 +718,7 @@ Email snapshot with the default subject or message?
name="ErrorProcessingSnapshot"
type="alertmodal">
Error processing snapshot data
+ <tag>fail</tag>
</notification>
<notification
@@ -669,6 +726,7 @@ Error processing snapshot data
name="ErrorEncodingSnapshot"
type="alertmodal">
Error encoding snapshot.
+ <tag>fail</tag>
</notification>
<notification
@@ -676,6 +734,7 @@ Error encoding snapshot.
name="ErrorUploadingPostcard"
type="alertmodal">
There was a problem sending a snapshot due to the following reason: [REASON]
+ <tag>fail</tag>
</notification>
<notification
@@ -683,12 +742,14 @@ There was a problem sending a snapshot due to the following reason: [REASON]
name="ErrorUploadingReportScreenshot"
type="alertmodal">
There was a problem uploading a report screenshot due to the following reason: [REASON]
+ <tag>fail</tag>
</notification>
<notification
icon="alertmodal.tga"
name="MustAgreeToLogIn"
type="alertmodal">
+ <tag>fail</tag>
You must agree to the Terms of Service to continue logging into [SECOND_LIFE].
</notification>
@@ -698,6 +759,7 @@ You must agree to the Terms of Service to continue logging into [SECOND_LIFE].
type="alertmodal">
Could not put on outfit.
The outfit folder contains no clothing, body parts, or attachments.
+ <tag>fail</tag>
</notification>
<notification
@@ -705,6 +767,7 @@ The outfit folder contains no clothing, body parts, or attachments.
name="CannotWearTrash"
type="alertmodal">
You can not wear clothes or body parts that are in the trash
+ <tag>fail</tag>
</notification>
<notification
@@ -713,6 +776,7 @@ You can not wear clothes or body parts that are in the trash
type="alertmodal">
Could not attach object.
Exceeds the attachments limit of [MAX_ATTACHMENTS] objects. Please detach another object first.
+ <tag>fail</tag>
</notification>
<notification
@@ -720,16 +784,19 @@ Exceeds the attachments limit of [MAX_ATTACHMENTS] objects. Please detach anothe
name="CannotWearInfoNotComplete"
type="alertmodal">
You can not wear that item because it has not yet loaded. Please try again in a minute.
+ <tag>fail</tag>
</notification>
<notification
icon="alertmodal.tga"
name="MustHaveAccountToLogIn"
type="alertmodal">
+ <tag>fail</tag>
Oops! Something was left blank.
You need to enter the Username name of your avatar.
You need an account to enter [SECOND_LIFE]. Would you like to create one now?
+ <tag>confirm</tag>
<url
option="0"
name="url"
@@ -747,6 +814,7 @@ You need an account to enter [SECOND_LIFE]. Would you like to create one now?
icon="alertmodal.tga"
name="InvalidCredentialFormat"
type="alertmodal">
+ <tag>fail</tag>
You need to enter either the Username or both the First and Last name of your avatar into the Username field, then login again.
</notification>
@@ -759,6 +827,7 @@ Classified ads appear in the &apos;Classified&apos; section of the Search direct
Fill out your ad, then click &apos;Publish...&apos; to add it to the directory.
You&apos;ll be asked for a price to pay when clicking Publish.
Paying more makes your ad appear higher in the list, and also appear higher when people search for keywords.
+ <tag>confirm</tag>
<usetemplate
ignoretext="How to create a new Classified ad"
name="okcancelignore"
@@ -772,6 +841,7 @@ Paying more makes your ad appear higher in the list, and also appear higher when
type="alertmodal">
Delete classified &apos;[NAME]&apos;?
There is no reimbursement for fees paid.
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -785,6 +855,7 @@ There is no reimbursement for fees paid.
type="alertmodal">
You have selected to delete the media associated with this face.
Are you sure you want to continue?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm before I delete media from an object"
name="okcancelignore"
@@ -797,6 +868,7 @@ Are you sure you want to continue?
name="ClassifiedSave"
type="alertmodal">
Save changes to classified [NAME]?
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -809,6 +881,7 @@ Save changes to classified [NAME]?
name="ClassifiedInsufficientFunds"
type="alertmodal">
Insufficient funds to create classified.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -819,6 +892,7 @@ Insufficient funds to create classified.
name="DeleteAvatarPick"
type="alertmodal">
Delete pick &lt;nolink&gt;[PICK]&lt;/nolink&gt;?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -830,6 +904,7 @@ Delete pick &lt;nolink&gt;[PICK]&lt;/nolink&gt;?
name="DeleteOutfits"
type="alertmodal">
Delete the selected outfit?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -841,6 +916,7 @@ Delete pick &lt;nolink&gt;[PICK]&lt;/nolink&gt;?
name="PromptGoToEventsPage"
type="alertmodal">
Go to the [SECOND_LIFE] events web page?
+ <tag>confirm</tag>
<url option="0" name="url">
http://secondlife.com/events/
@@ -856,6 +932,7 @@ Go to the [SECOND_LIFE] events web page?
name="SelectProposalToView"
type="alertmodal">
Please select a proposal to view.
+ <tag>fail</tag>
</notification>
<notification
@@ -863,6 +940,7 @@ Please select a proposal to view.
name="SelectHistoryItemToView"
type="alertmodal">
Please select a history item to view.
+ <tag>fail</tag>
</notification>
<!--
@@ -929,9 +1007,9 @@ Changing language will take effect after you restart [APP_NAME].
icon="alertmodal.tga"
name="GoToAuctionPage"
type="alertmodal">
-Go to the [SECOND_LIFE] web page to see auction details or make a bid?
+ Go to the [SECOND_LIFE] web page to see auction details or make a bid?
+ <tag>confirm</tag>
<url option="0" name="url">
-
http://secondlife.com/auctions/auction-detail.php?id=[AUCTION_ID]
</url>
<usetemplate
@@ -945,6 +1023,7 @@ Go to the [SECOND_LIFE] web page to see auction details or make a bid?
name="SaveChanges"
type="alertmodal">
Save Changes?
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -959,6 +1038,7 @@ Save Changes?
Gesture save failed.
This gesture has too many steps.
Try removing some steps, then save again.
+<tag>fail</tag>
</notification>
<notification
@@ -966,6 +1046,7 @@ Try removing some steps, then save again.
name="GestureSaveFailedTryAgain"
type="alertmodal">
Gesture save failed. Please try again in a minute.
+<tag>fail</tag>
</notification>
<notification
@@ -974,6 +1055,7 @@ Gesture save failed. Please try again in a minute.
type="alertmodal">
Could not save gesture because the object or the associated object inventory could not be found.
The object may be out of range or may have been deleted.
+<tag>fail</tag>
</notification>
<notification
@@ -981,6 +1063,7 @@ The object may be out of range or may have been deleted.
name="GestureSaveFailedReason"
type="alertmodal">
There was a problem saving a gesture due to the following reason: [REASON]. Please try resaving the gesture later.
+<tag>fail</tag>
</notification>
<notification
@@ -989,6 +1072,7 @@ There was a problem saving a gesture due to the following reason: [REASON]. Ple
type="alertmodal">
Could not save notecard because the object or the associated object inventory could not be found.
The object may be out of range or may have been deleted.
+<tag>fail</tag>
</notification>
<notification
@@ -996,6 +1080,7 @@ The object may be out of range or may have been deleted.
name="SaveNotecardFailReason"
type="alertmodal">
There was a problem saving a notecard due to the following reason: [REASON]. Please try re-saving the notecard later.
+<tag>fail</tag>
</notification>
<notification
@@ -1005,6 +1090,7 @@ There was a problem saving a notecard due to the following reason: [REASON]. Pl
Could not undo all changes in your version of the script.
Would you like to load the server&apos;s last saved version?
(**Warning** This operation cannot be undone.)
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -1016,6 +1102,7 @@ Would you like to load the server&apos;s last saved version?
name="SaveScriptFailReason"
type="alertmodal">
There was a problem saving a script due to the following reason: [REASON]. Please try re-saving the script later.
+<tag>fail</tag>
</notification>
<notification
@@ -1024,6 +1111,7 @@ There was a problem saving a script due to the following reason: [REASON]. Plea
type="alertmodal">
Could not save the script because the object it is in could not be found.
The object may be out of range or may have been deleted.
+<tag>fail</tag>
</notification>
<notification
@@ -1031,6 +1119,7 @@ The object may be out of range or may have been deleted.
name="SaveBytecodeFailReason"
type="alertmodal">
There was a problem saving a compiled script due to the following reason: [REASON]. Please try re-saving the script later.
+<tag>fail</tag>
</notification>
<notification
@@ -1039,6 +1128,7 @@ There was a problem saving a compiled script due to the following reason: [REASO
type="alertmodal">
Oops, Your Start Region is not defined.
Please type the Region name in Start Location box or choose My Last Location or My Home as your Start Location.
+<tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -1050,6 +1140,7 @@ Please type the Region name in Start Location box or choose My Last Location or
type="alertmodal">
Could not start or stop the script because the object it is on could not be found.
The object may be out of range or may have been deleted.
+ <tag>fail</tag>
</notification>
<notification
@@ -1057,6 +1148,7 @@ The object may be out of range or may have been deleted.
name="CannotDownloadFile"
type="alertmodal">
Unable to download file
+ <tag>fail</tag>
</notification>
<notification
@@ -1064,6 +1156,7 @@ Unable to download file
name="CannotWriteFile"
type="alertmodal">
Unable to write file [[FILE]]
+ <tag>fail</tag>
</notification>
<notification
@@ -1073,6 +1166,7 @@ Unable to write file [[FILE]]
Just so you know, your computer does not meet [APP_NAME]&apos;s minimum system requirements. You may experience poor performance. Unfortunately, the [SUPPORT_SITE] can't provide technical support for unsupported system configurations.
Visit [_URL] for more information?
+ <tag>confirm</tag>
<url option="0" name="url">
http://www.secondlife.com/corporate/sysreqs.php
@@ -1082,6 +1176,7 @@ Visit [_URL] for more information?
name="okcancelignore"
notext="No"
yestext="Yes"/>
+ <tag>fail</tag>
</notification>
<notification
@@ -1095,6 +1190,7 @@ This is often the case with new hardware that hasn&apos;t been tested yet with [
<ignore name="ignore"
text="My graphics card could not be identified"/>
</form>
+ <tag>fail</tag>
</notification>
<notification
@@ -1105,6 +1201,7 @@ This is often the case with new hardware that hasn&apos;t been tested yet with [
Graphics Quality will be set to Low to avoid some common driver errors. This will disable some graphics features.
We recommend updating your graphics card drivers.
Graphics Quality can be raised in Preferences &gt; Graphics.
+ <tag>fail</tag>
</notification>
<notification
@@ -1112,6 +1209,7 @@ Graphics Quality can be raised in Preferences &gt; Graphics.
name="RegionNoTerraforming"
type="alertmodal">
The region [REGION] does not allow terraforming.
+ <tag>fail</tag>
</notification>
<notification
@@ -1121,10 +1219,12 @@ The region [REGION] does not allow terraforming.
You do not have permission to copy the following items:
[ITEMS]
and will lose it from your inventory if you give it away. Do you really want to offer these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="No"
yestext="Yes"/>
+ <tag>fail</tag>
</notification>
<notification
@@ -1132,6 +1232,7 @@ and will lose it from your inventory if you give it away. Do you really want to
name="CannotGiveItem"
type="alertmodal">
Unable to give inventory item.
+ <tag>fail</tag>
</notification>
<notification
@@ -1146,6 +1247,7 @@ Transaction cancelled.
name="TooManyItems"
type="alertmodal">
Cannot give more than 42 items in a single inventory transfer.
+ <tag>fail</tag>
</notification>
<notification
@@ -1153,6 +1255,7 @@ Cannot give more than 42 items in a single inventory transfer.
name="NoItems"
type="alertmodal">
You do not have permission to transfer the selected items.
+ <tag>fail</tag>
</notification>
<notification
@@ -1161,6 +1264,8 @@ You do not have permission to transfer the selected items.
type="alertmodal">
You do not have permission to copy [COUNT] of the selected items. You will lose these items from your inventory.
Do you really want to give these items?
+ <tag>confirm</tag>
+ <tag>fail</tag>
<usetemplate
name="okcancelbuttons"
notext="No"
@@ -1172,6 +1277,7 @@ Do you really want to give these items?
name="CannotGiveCategory"
type="alertmodal">
You do not have permission to transfer the selected folder.
+ <tag>fail</tag>
</notification>
<notification
@@ -1180,6 +1286,7 @@ You do not have permission to transfer the selected folder.
type="alertmodal">
Freeze this avatar?
He or she will temporarily be unable to move, chat, or interact with the world.
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -1193,6 +1300,7 @@ He or she will temporarily be unable to move, chat, or interact with the world.
type="alertmodal">
Freeze [AVATAR_NAME]?
He or she will temporarily be unable to move, chat, or interact with the world.
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -1205,6 +1313,7 @@ He or she will temporarily be unable to move, chat, or interact with the world.
name="EjectAvatarFullname"
type="alertmodal">
Eject [AVATAR_NAME] from your land?
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -1217,6 +1326,7 @@ Eject [AVATAR_NAME] from your land?
name="EjectAvatarNoBan"
type="alertmodal">
Eject this avatar from your land?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -1228,6 +1338,7 @@ Eject this avatar from your land?
name="EjectAvatarFullnameNoBan"
type="alertmodal">
Eject [AVATAR_NAME] from your land?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -1240,6 +1351,7 @@ Eject [AVATAR_NAME] from your land?
persist="true"
type="notify">
You ejected [AVATAR_NAME] from group [GROUP_NAME]
+ <tag>group</tag>
</notification>
<notification
@@ -1247,6 +1359,7 @@ You ejected [AVATAR_NAME] from group [GROUP_NAME]
name="AcquireErrorTooManyObjects"
type="alertmodal">
ACQUIRE ERROR: Too many objects selected.
+ <tag>fail</tag>
</notification>
<notification
@@ -1255,6 +1368,7 @@ ACQUIRE ERROR: Too many objects selected.
type="alertmodal">
ACQUIRE ERROR: Objects span more than one region.
Please move all objects to be acquired onto the same region.
+ <tag>fail</tag>
</notification>
<notification
@@ -1264,6 +1378,7 @@ Please move all objects to be acquired onto the same region.
[EXTRA]
Go to [_URL] for information on purchasing L$?
+ <tag>confirm</tag>
<url option="0" name="url">
http://secondlife.com/app/currency/
@@ -1280,6 +1395,7 @@ Go to [_URL] for information on purchasing L$?
type="alertmodal">
Unable to link these [COUNT] objects.
You can link a maximum of [MAX] objects.
+ <tag>fail</tag>
</notification>
<notification
@@ -1287,6 +1403,7 @@ You can link a maximum of [MAX] objects.
name="CannotLinkIncompleteSet"
type="alertmodal">
You can only link complete sets of objects, and must select more than one object.
+ <tag>fail</tag>
</notification>
<notification
@@ -1296,6 +1413,7 @@ You can only link complete sets of objects, and must select more than one object
Unable to link because you don&apos;t have modify permission on all the objects.
Please make sure none are locked, and that you own all of them.
+ <tag>fail</tag>
</notification>
<notification
@@ -1305,6 +1423,7 @@ Please make sure none are locked, and that you own all of them.
Unable to link because not all of the objects have the same owner.
Please make sure you own all of the selected objects.
+ <tag>fail</tag>
</notification>
<notification
@@ -1314,6 +1433,7 @@ Please make sure you own all of the selected objects.
No file extension for the file: &apos;[FILE]&apos;
Please make sure the file has a correct file extension.
+ <tag>fail</tag>
</notification>
<notification
@@ -1325,6 +1445,7 @@ Expected [VALIDS]
<usetemplate
name="okbutton"
yestext="OK"/>
+ <tag>fail</tag>
</notification>
<notification
@@ -1333,6 +1454,7 @@ Expected [VALIDS]
type="alertmodal">
Couldn&apos;t open uploaded sound file for reading:
[FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1341,6 +1463,7 @@ Couldn&apos;t open uploaded sound file for reading:
type="alertmodal">
File does not appear to be a RIFF WAVE file:
[FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1349,6 +1472,7 @@ File does not appear to be a RIFF WAVE file:
type="alertmodal">
File does not appear to be a PCM WAVE audio file:
[FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1357,6 +1481,7 @@ File does not appear to be a PCM WAVE audio file:
type="alertmodal">
File has invalid number of channels (must be mono or stereo):
[FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1365,6 +1490,7 @@ File has invalid number of channels (must be mono or stereo):
type="alertmodal">
File does not appear to be a supported sample rate (must be 44.1k):
[FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1373,6 +1499,7 @@ File does not appear to be a supported sample rate (must be 44.1k):
type="alertmodal">
File does not appear to be a supported word size (must be 8 or 16 bit):
[FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1381,6 +1508,7 @@ File does not appear to be a supported word size (must be 8 or 16 bit):
type="alertmodal">
Could not find &apos;data&apos; chunk in WAV header:
[FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1389,6 +1517,7 @@ Could not find &apos;data&apos; chunk in WAV header:
type="alertmodal">
Wrong chunk size in WAV file:
[FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1397,6 +1526,7 @@ Wrong chunk size in WAV file:
type="alertmodal">
Audio file is too long (10 second maximum):
[FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1406,6 +1536,7 @@ Audio file is too long (10 second maximum):
Problem with file [FILE]:
[ERROR]
+ <tag>fail</tag>
</notification>
<notification
@@ -1413,6 +1544,7 @@ Problem with file [FILE]:
name="CannotOpenTemporarySoundFile"
type="alertmodal">
Couldn&apos;t open temporary compressed sound file for writing: [FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1420,6 +1552,7 @@ Couldn&apos;t open temporary compressed sound file for writing: [FILE]
name="UnknownVorbisEncodeFailure"
type="alertmodal">
Unknown Vorbis encode failure on: [FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1427,6 +1560,7 @@ Unknown Vorbis encode failure on: [FILE]
name="CannotEncodeFile"
type="alertmodal">
Unable to encode file: [FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1435,6 +1569,7 @@ Unable to encode file: [FILE]
type="alertmodal">
We can't fill in your username and password. This may happen when you change network setup
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -1445,6 +1580,7 @@ Unable to encode file: [FILE]
name="CorruptResourceFile"
type="alertmodal">
Corrupt resource file: [FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1452,6 +1588,7 @@ Corrupt resource file: [FILE]
name="UnknownResourceFileVersion"
type="alertmodal">
Unknown Linden resource file version in file: [FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1459,6 +1596,7 @@ Unknown Linden resource file version in file: [FILE]
name="UnableToCreateOutputFile"
type="alertmodal">
Unable to create output file: [FILE]
+ <tag>fail</tag>
</notification>
<notification
@@ -1466,6 +1604,7 @@ Unable to create output file: [FILE]
name="DoNotSupportBulkAnimationUpload"
type="alertmodal">
[APP_NAME] does not currently support bulk upload of animation files.
+ <tag>fail</tag>
</notification>
<notification
@@ -1474,6 +1613,7 @@ Unable to create output file: [FILE]
type="alertmodal">
Unable to upload [FILE] due to the following reason: [REASON]
Please try again later.
+ <tag>fail</tag>
</notification>
<notification
@@ -1491,6 +1631,7 @@ You already have a landmark for this location.
<usetemplate
name="okbutton"
yestext="OK"/>
+ <tag>fail</tag>
</notification>
<notification
@@ -1498,6 +1639,7 @@ You already have a landmark for this location.
name="CannotCreateLandmarkNotOwner"
type="alertmodal">
You cannot create a landmark here because the owner of the land doesn&apos;t allow it.
+ <tag>fail</tag>
</notification>
<notification
@@ -1506,6 +1648,7 @@ You cannot create a landmark here because the owner of the land doesn&apos;t all
type="alertmodal">
Not able to perform &apos;recompilation&apos;.
Select an object with a script.
+ <tag>fail</tag>
</notification>
<notification
@@ -1515,6 +1658,7 @@ Select an object with a script.
Not able to perform &apos;recompilation&apos;.
Select objects with scripts that you have permission to modify.
+ <tag>fail</tag>
</notification>
<notification
@@ -1524,6 +1668,7 @@ Select objects with scripts that you have permission to modify.
Not able to perform &apos;reset&apos;.
Select objects with scripts.
+ <tag>fail</tag>
</notification>
<notification
@@ -1533,6 +1678,7 @@ Select objects with scripts.
Not able to perform &apos;reset&apos;.
Select objects with scripts that you have permission to modify.
+ <tag>fail</tag>
</notification>
<notification
@@ -1540,6 +1686,7 @@ Select objects with scripts that you have permission to modify.
name="CannotOpenScriptObjectNoMod"
type="alertmodal">
Unable to open script in object without modify permissions.
+ <tag>fail</tag>
</notification>
<notification
@@ -1549,6 +1696,7 @@ Select objects with scripts that you have permission to modify.
Not able to set any scripts to &apos;running&apos;.
Select objects with scripts.
+ <tag>fail</tag>
</notification>
<notification
@@ -1558,6 +1706,7 @@ Select objects with scripts.
Unable to set any scripts to &apos;not running&apos;.
Select objects with scripts.
+ <tag>fail</tag>
</notification>
<notification
@@ -1565,6 +1714,7 @@ Select objects with scripts.
name="NoFrontmostFloater"
type="alertmodal">
No frontmost floater to save.
+ <tag>fail</tag>
</notification>
<notification
@@ -1581,6 +1731,7 @@ Searched for: [FINALQUERY]
name="SeachFilteredOnShortWordsEmpty"
type="alertmodal">
Your search terms were too short so no search was performed.
+ <tag>fail</tag>
</notification>
<!-- Generic Teleport failure modes - strings will be inserted from
@@ -1591,6 +1742,7 @@ Your search terms were too short so no search was performed.
type="alertmodal">
Teleport failed.
[REASON]
+ <tag>fail</tag>
</notification>
<!-- Teleport failure modes not delivered via the generic mechanism
@@ -1603,6 +1755,7 @@ Teleport failed.
type="alertmodal">
Problem encountered processing your teleport request. You may need to log back in before you can teleport.
If you continue to get this message, please check the [SUPPORT_SITE].
+ <tag>fail</tag>
</notification>
<notification
icon="alertmodal.tga"
@@ -1610,19 +1763,21 @@ If you continue to get this message, please check the [SUPPORT_SITE].
type="alertmodal">
Problem encountered processing your region crossing. You may need to log back in before you can cross regions.
If you continue to get this message, please check the [SUPPORT_SITE].
+ <tag>fail</tag>
</notification>
<notification
icon="alertmodal.tga"
name="blocked_tport"
type="alertmodal">
- <tag>fail</tag>
Sorry, teleport is currently blocked. Try again in a moment. If you still cannot teleport, please log out and log back in to resolve the problem.
+ <tag>fail</tag>
</notification>
<notification
icon="alertmodal.tga"
name="nolandmark_tport"
type="alertmodal">
Sorry, but system was unable to locate landmark destination.
+ <tag>fail</tag>
</notification>
<notification
icon="alertmodal.tga"
@@ -1678,6 +1833,7 @@ Unable to find teleport destination. The destination may be temporarily unavaila
name="no_inventory_host"
type="alertmodal">
The inventory system is currently unavailable.
+ <tag>fail</tag>
</notification>
<notification
@@ -1686,6 +1842,7 @@ The inventory system is currently unavailable.
type="alertmodal">
Unable to set land owner:
No parcel selected.
+ <tag>fail</tag>
</notification>
<notification
@@ -1693,6 +1850,7 @@ No parcel selected.
name="CannotSetLandOwnerMultipleRegions"
type="alertmodal">
Unable to force land ownership because selection spans multiple regions. Please select a smaller area and try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -1701,6 +1859,7 @@ Unable to force land ownership because selection spans multiple regions. Please
type="alertmodal">
This parcel is up for auction. Forcing ownership will cancel the auction and potentially make some Residents unhappy if bidding has begun.
Force ownership?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -1713,6 +1872,7 @@ Force ownership?
type="alertmodal">
Unable to contentify:
No parcel selected.
+ <tag>fail</tag>
</notification>
<notification
@@ -1721,6 +1881,7 @@ No parcel selected.
type="alertmodal">
Unable to contentify:
No region selected.
+ <tag>fail</tag>
</notification>
<notification
@@ -1729,6 +1890,7 @@ No region selected.
type="alertmodal">
Unable to abandon land:
No parcel selected.
+ <tag>fail</tag>
</notification>
<notification
@@ -1737,6 +1899,7 @@ No parcel selected.
type="alertmodal">
Unable to abandon land:
Cannot find region.
+ <tag>fail</tag>
</notification>
<notification
@@ -1745,6 +1908,7 @@ Cannot find region.
type="alertmodal">
Unable to buy land:
No parcel selected.
+ <tag>fail</tag>
</notification>
<notification
@@ -1753,6 +1917,7 @@ No parcel selected.
type="alertmodal">
Unable to buy land:
Cannot find the region this land is in.
+ <tag>fail</tag>
</notification>
<notification
@@ -1760,6 +1925,7 @@ Cannot find the region this land is in.
name="CannotCloseFloaterBuyLand"
type="alertmodal">
You cannot close the Buy Land window until [APP_NAME] estimates the price of this transaction.
+ <tag>fail</tag>
</notification>
<notification
@@ -1768,6 +1934,7 @@ You cannot close the Buy Land window until [APP_NAME] estimates the price of thi
type="alertmodal">
Unable to deed land:
No parcel selected.
+ <tag>fail</tag>
</notification>
<notification
@@ -1776,6 +1943,8 @@ No parcel selected.
type="alertmodal">
Unable to deed land:
No Group selected.
+ <tag>group</tag>
+ <tag>fail</tag>
</notification>
<notification
@@ -1784,6 +1953,7 @@ No Group selected.
type="alertmodal">
Unable to deed land:
Cannot find the region this land is in.
+ <tag>fail</tag>
</notification>
<notification
@@ -1794,6 +1964,7 @@ Unable to deed land:
Multiple parcels selected.
Try selecting a single parcel.
+ <tag>fail</tag>
</notification>
<notification
@@ -1804,6 +1975,7 @@ Unable to deed land:
Waiting for server to report ownership.
Please try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -1812,6 +1984,7 @@ Please try again.
type="alertmodal">
Unable to deed land:
The region [REGION] does not allow transfer of land.
+ <tag>fail</tag>
</notification>
<notification
@@ -1822,6 +1995,7 @@ Unable to abandon land:
Waiting for server to update parcel information.
Try again in a few seconds.
+ <tag>fail</tag>
</notification>
<notification
@@ -1832,6 +2006,7 @@ Unable to abandon land:
You do not own all the parcels selected.
Please select a single parcel.
+ <tag>fail</tag>
</notification>
<notification
@@ -1841,6 +2016,7 @@ Please select a single parcel.
Unable to abandon land:
You don&apos;t have permission to release this parcel.
Parcels you own appear in green.
+ <tag>fail</tag>
</notification>
<notification
@@ -1849,6 +2025,7 @@ Parcels you own appear in green.
type="alertmodal">
Unable to abandon land:
Cannot find the region this land is in.
+ <tag>fail</tag>
</notification>
<notification
@@ -1857,6 +2034,7 @@ Cannot find the region this land is in.
type="alertmodal">
Unable to abandon land:
The region [REGION] does not allow transfer of land.
+ <tag>fail</tag>
</notification>
<notification
@@ -1867,6 +2045,7 @@ Unable to abandon land:
You must select an entire parcel to release it.
Select an entire parcel, or divide your parcel first.
+ <tag>fail</tag>
</notification>
<notification
@@ -1877,6 +2056,7 @@ You are about to release [AREA] m² of land.
Releasing this parcel will remove it from your land holdings, but will not grant any L$.
Release this land?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -1890,6 +2070,7 @@ Release this land?
Unable to divide land:
No parcels selected.
+ <tag>fail</tag>
</notification>
<notification
@@ -1900,6 +2081,7 @@ Unable to divide land:
You have an entire parcel selected.
Try selecting a part of the parcel.
+ <tag>fail</tag>
</notification>
<notification
@@ -1909,6 +2091,7 @@ Try selecting a part of the parcel.
Dividing this land will split this parcel into two and each parcel can have its own settings. Some settings will be reset to defaults after the operation.
Divide land?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -1921,6 +2104,7 @@ Divide land?
type="alertmodal">
Unable to divide land:
Cannot find the region this land is in.
+ <tag>fail</tag>
</notification>
<notification
@@ -1929,6 +2113,7 @@ Cannot find the region this land is in.
type="alertmodal">
Unable to join land:
Cannot find the region this land is in.
+ <tag>fail</tag>
</notification>
<notification
@@ -1937,6 +2122,7 @@ Cannot find the region this land is in.
type="alertmodal">
Unable to join land:
No parcels selected.
+ <tag>fail</tag>
</notification>
<notification
@@ -1947,6 +2133,7 @@ Unable to join land:
You only have one parcel selected.
Select land across both parcels.
+ <tag>fail</tag>
</notification>
<notification
@@ -1957,6 +2144,7 @@ Unable to join land:
You must select more than one parcel.
Select land across both parcels.
+ <tag>fail</tag>
</notification>
<notification
@@ -1967,6 +2155,7 @@ Joining this land will create one large parcel out of all parcels intersecting t
You will need to reset the name and options of the new parcel.
Join land?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -1978,6 +2167,7 @@ Join land?
name="ConfirmNotecardSave"
type="alertmodal">
This notecard needs to be saved before the item can be copied or viewed. Save notecard?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -1989,6 +2179,7 @@ This notecard needs to be saved before the item can be copied or viewed. Save no
name="ConfirmItemCopy"
type="alertmodal">
Copy this item to your inventory?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2000,6 +2191,7 @@ Copy this item to your inventory?
name="ResolutionSwitchFail"
type="alertmodal">
Failed to switch resolution to [RESX] by [RESY]
+ <tag>fail</tag>
</notification>
<notification
@@ -2007,6 +2199,7 @@ Failed to switch resolution to [RESX] by [RESY]
name="ErrorUndefinedGrasses"
type="alertmodal">
Error: Undefined grasses: [SPECIES]
+ <tag>fail</tag>
</notification>
<notification
@@ -2014,6 +2207,7 @@ Error: Undefined grasses: [SPECIES]
name="ErrorUndefinedTrees"
type="alertmodal">
Error: Undefined trees: [SPECIES]
+ <tag>fail</tag>
</notification>
<notification
@@ -2021,6 +2215,7 @@ Error: Undefined trees: [SPECIES]
name="CannotSaveWearableOutOfSpace"
type="alertmodal">
Unable to save &apos;[NAME]&apos; to wearable file. You will need to free up some space on your computer and save the wearable again.
+ <tag>fail</tag>
</notification>
<notification
@@ -2029,6 +2224,7 @@ Unable to save &apos;[NAME]&apos; to wearable file. You will need to free up so
type="alertmodal">
Unable to save [NAME] to central asset store.
This is usually a temporary failure. Please customize and save the wearable again in a few minutes.
+ <tag>fail</tag>
</notification>
<notification
@@ -2049,6 +2245,8 @@ Darn. You have been logged out of [SECOND_LIFE]
type="alertmodal">
Unable to buy land for the group:
You do not have permission to buy land for your active group.
+ <tag>group</tag>
+ <tag>fail</tag>
</notification>
<notification
@@ -2056,9 +2254,11 @@ You do not have permission to buy land for your active group.
label="Add Friend"
name="AddFriendWithMessage"
type="alertmodal">
+ <tag>friendship</tag>
Friends can give permissions to track each other on the map and receive online status updates.
Offer friendship to [NAME]?
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text">
Would you be my friend?
@@ -2082,6 +2282,7 @@ Would you be my friend?
type="alertmodal"
unique="true">
Save what I'm wearing as a new Outfit:
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text">
[DESC] (new)
@@ -2104,6 +2305,7 @@ Would you be my friend?
name="SaveWearableAs"
type="alertmodal">
Save item to my inventory as:
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text">
[DESC] (new)
@@ -2127,6 +2329,7 @@ Would you be my friend?
name="RenameOutfit"
type="alertmodal">
New outfit name:
+ <tag>confirm</tag>
<form name="form">
<input name="new_name" type="text" width="300">
[NAME]
@@ -2147,7 +2350,9 @@ Would you be my friend?
icon="alertmodal.tga"
name="RemoveFromFriends"
type="alertmodal">
+ <tag>friendship</tag>
Do you want to remove [NAME] from your Friends List?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2158,7 +2363,9 @@ Do you want to remove [NAME] from your Friends List?
icon="alertmodal.tga"
name="RemoveMultipleFromFriends"
type="alertmodal">
+ <tag>friendship</tag>
Do you want to remove multiple friends from your Friends list?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2172,6 +2379,7 @@ Do you want to remove multiple friends from your Friends list?
Are you sure you want to delete all scripted objects owned by
** [AVATAR_NAME] **
on all others land in this sim?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2185,6 +2393,7 @@ on all others land in this sim?
Are you sure you want to DELETE ALL scripted objects owned by
** [AVATAR_NAME] **
on ALL LAND in this sim?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2198,6 +2407,7 @@ on ALL LAND in this sim?
Are you sure you want to DELETE ALL objects (scripted or not) owned by
** [AVATAR_NAME] **
on ALL LAND in this sim?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2209,6 +2419,7 @@ on ALL LAND in this sim?
name="BlankClassifiedName"
type="alertmodal">
You must specify a name for your classified.
+ <tag>fail</tag>
</notification>
<notification
@@ -2218,6 +2429,7 @@ You must specify a name for your classified.
Price to pay for listing must be at least L$[MIN_PRICE].
Please enter a higher price.
+ <tag>fail</tag>
</notification>
<notification
@@ -2227,6 +2439,7 @@ Please enter a higher price.
At least one of the items you has link items that point to it. If you delete this item, its links will permanently stop working. It is strongly advised to delete the links first.
Are you sure you want to delete these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2240,6 +2453,7 @@ Are you sure you want to delete these items?
At least one of the items you have selected is locked.
Are you sure you want to delete these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2253,6 +2467,7 @@ Are you sure you want to delete these items?
At least one of the items you have selected is not copyable.
Are you sure you want to delete these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2266,6 +2481,7 @@ Are you sure you want to delete these items?
You do not own least one of the items you have selected.
Are you sure you want to delete these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2280,6 +2496,7 @@ At least one object is locked.
At least one object is not copyable.
Are you sure you want to delete these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2294,6 +2511,7 @@ At least one object is locked.
You do not own least one object.
Are you sure you want to delete these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2308,6 +2526,7 @@ At least one object is not copyable.
You do not own least one object.
Are you sure you want to delete these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2323,6 +2542,7 @@ At least one object is not copyable.
You do not own least one object.
Are you sure you want to delete these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="cancel"
@@ -2336,6 +2556,7 @@ Are you sure you want to delete these items?
At least one object is locked.
Are you sure you want to take these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2350,6 +2571,7 @@ You do not own all of the objects you are taking.
If you continue, next owner permissions will be applied and possibly restrict your ability to modify or copy them.
Are you sure you want to take these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2366,6 +2588,7 @@ If you continue, next owner permissions will be applied and possibly restrict yo
However, you can take the current selection.
Are you sure you want to take these items?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2379,6 +2602,7 @@ Are you sure you want to take these items?
Unable to buy land because selection spans multiple regions.
Please select a smaller area and try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -2389,6 +2613,8 @@ By deeding this parcel, the group will be required to have and maintain sufficie
The purchase price of the land is not refunded to the owner. If a deeded parcel is sold, the sale price will be divided evenly among group members.
Deed this [AREA] m² of land to the group &apos;[GROUP_NAME]&apos;?
+ <tag>group</tag>
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2404,6 +2630,8 @@ The deed will include a simultaneous land contribution to the group from &apos;[
The purchase price of the land is not refunded to the owner. If a deeded parcel is sold, the sale price will be divided evenly among group members.
Deed this [AREA] m² of land to the group &apos;[GROUP_NAME]&apos;?
+ <tag>group</tag>
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2429,6 +2657,7 @@ Display settings have been set to recommended levels based on your system config
name="ErrorMessage"
type="alertmodal">
[ERROR_MESSAGE]
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -2484,6 +2713,7 @@ You can use [SECOND_LIFE] normally and other people will see you correctly.
If this is your first time using [SECOND_LIFE], you will need to create an account before you can log in.
Return to [http://join.secondlife.com secondlife.com] to create a new account?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
@@ -2537,6 +2767,7 @@ Please choose the male or female avatar. You can change your mind later.
name="CantTeleportToGrid"
type="alertmodal">
Could not teleport to [SLURL] as it's on a different grid ([GRID]) than the current grid ([CURRENT_GRID]). Please close your viewer and try again.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -2557,6 +2788,7 @@ SHA1 Fingerprint: [MD5_DIGEST]
Key Usage: [KEYUSAGE]
Extended Key Usage: [EXTENDEDKEYUSAGE]
Subject Key Identifier: [SUBJECTKEYIDENTIFIER]
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -2579,6 +2811,7 @@ Extended Key Usage: [EXTENDEDKEYUSAGE]
Subject Key Identifier: [SUBJECTKEYIDENTIFIER]
Would you like to trust this authority?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2590,6 +2823,8 @@ Would you like to trust this authority?
name="NotEnoughCurrency"
type="alertmodal">
[NAME] L$ [PRICE] You don&apos;t have enough L$ to do that.
+ <tag>fail</tag>
+ <tag>funds</tag>
</notification>
<notification
@@ -2626,6 +2861,7 @@ This is really only useful for debugging.
name="BuyOneObjectOnly"
type="alertmodal">
Unable to buy more than one object at a time. Please select only one object and try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -2634,6 +2870,7 @@ Unable to buy more than one object at a time. Please select only one object and
type="alertmodal">
Unable to copy the contents of more than one item at a time.
Please select only one object and try again.
+ <tag>fail</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2645,6 +2882,7 @@ Please select only one object and try again.
name="KickUsersFromRegion"
type="alertmodal">
Teleport all Residents in this region home?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2656,6 +2894,7 @@ Teleport all Residents in this region home?
name="EstateObjectReturn"
type="alertmodal">
Are you sure you want to return objects owned by [USER_NAME]?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2670,6 +2909,7 @@ Couldn&apos;t set region textures:
Terrain texture [TEXTURE_NUM] has an invalid bit depth of [TEXTURE_BIT_DEPTH].
Replace texture [TEXTURE_NUM] with a 24-bit 512x512 or smaller image then click &quot;Apply&quot; again.
+ <tag>fail</tag>
</notification>
<notification
@@ -2694,6 +2934,7 @@ Upload started. It may take up to two minutes, depending on your connection spee
name="ConfirmBakeTerrain"
type="alertmodal">
Do you really want to bake the current terrain, make it the center for terrain raise/lower limits and the default for the &apos;Revert&apos; tool?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2727,6 +2968,7 @@ Exceeds the [MAX_AGENTS] [LIST_TYPE] limit by [NUM_EXCESS].
name="MaxAllowedGroupsOnRegion"
type="alertmodal">
You can only have [MAX_GROUPS] Allowed Groups.
+ <tag>group</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -2784,6 +3026,7 @@ Finished download of raw terrain file to:
A new version of [APP_NAME] is available.
[MESSAGE]
You must download this update to use [APP_NAME].
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Quit"
@@ -2797,6 +3040,7 @@ You must download this update to use [APP_NAME].
An updated version of [APP_NAME] is available.
[MESSAGE]
This update is not required, but we suggest you install it to improve performance and stability.
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
@@ -2810,6 +3054,7 @@ This update is not required, but we suggest you install it to improve performanc
An updated version of [APP_NAME] is available.
[MESSAGE]
This update is not required, but we suggest you install it to improve performance and stability.
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
@@ -2823,6 +3068,7 @@ This update is not required, but we suggest you install it to improve performanc
A new version of [APP_NAME] is available.
[MESSAGE]
You must download this update to use [APP_NAME].
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Quit"
@@ -2836,6 +3082,7 @@ You must download this update to use [APP_NAME].
An updated version of [APP_NAME] is available.
[MESSAGE]
This update is not required, but we suggest you install it to improve performance and stability.
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
@@ -2849,6 +3096,7 @@ This update is not required, but we suggest you install it to improve performanc
An updated version of [APP_NAME] is available.
[MESSAGE]
This update is not required, but we suggest you install it to improve performance and stability.
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
@@ -2864,6 +3112,7 @@ A new version of [APP_NAME] is available.
You must download this update to use [APP_NAME].
Download to your Applications folder?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Quit"
@@ -2879,6 +3128,7 @@ An updated version of [APP_NAME] is available.
This update is not required, but we suggest you install it to improve performance and stability.
Download to your Applications folder?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
@@ -2894,6 +3144,7 @@ An updated version of [APP_NAME] is available.
This update is not required, but we suggest you install it to improve performance and stability.
Download to your Applications folder?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Continue"
@@ -2921,6 +3172,7 @@ You will be unable to log in until [APP_NAME] has been updated.
Please download and install the latest viewer from
http://secondlife.com/download.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="Quit"/>
@@ -2934,6 +3186,7 @@ There is a required update for your Second Life Installation.
You may download this update from http://www.secondlife.com/downloads
or you can install it now.
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Quit Second Life"
@@ -2946,6 +3199,7 @@ or you can install it now.
type="notify">
We have downloaded an update to your [APP_NAME] installation.
Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update]
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Later..."
@@ -2958,6 +3212,7 @@ Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update]
type="alertmodal">
We have downloaded an update to your [APP_NAME] installation.
Version [VERSION] [[RELEASE_NOTES_FULL_URL] Information about this update]
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Later..."
@@ -2972,6 +3227,7 @@ We have downloaded a required software update.
Version [VERSION]
We must restart [APP_NAME] to install the update.
+ <tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -2982,6 +3238,7 @@ We must restart [APP_NAME] to install the update.
name="RequiredUpdateDownloadedDialog"
type="alertmodal">
We must restart [APP_NAME] to install the update.
+ <tag>confirm</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -2993,6 +3250,8 @@ We must restart [APP_NAME] to install the update.
type="alertmodal">
Deeding this object will cause the group to:
* Receive L$ paid into the object
+ <tag>group</tag>
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm before I deed an object to a group"
name="okcancelignore"
@@ -3005,6 +3264,7 @@ Deeding this object will cause the group to:
name="WebLaunchExternalTarget"
type="alertmodal">
Do you want to open your Web browser to view this content?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Launch my browser to view a web page"
name="okcancelignore"
@@ -3017,6 +3277,7 @@ Do you want to open your Web browser to view this content?
name="WebLaunchJoinNow"
type="alertmodal">
Go to your [http://secondlife.com/account/ Dashboard] to manage your account?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Launch my browser to manage my account"
name="okcancelignore"
@@ -3029,6 +3290,7 @@ Go to your [http://secondlife.com/account/ Dashboard] to manage your account?
name="WebLaunchSecurityIssues"
type="alertmodal">
Visit the [SECOND_LIFE] Wiki for details of how to report a security issue.
+ <tag>confirm</tag>
<usetemplate
ignoretext="Launch my browser to learn how to report a Security Issue"
name="okcancelignore"
@@ -3041,6 +3303,7 @@ Visit the [SECOND_LIFE] Wiki for details of how to report a security issue.
name="WebLaunchQAWiki"
type="alertmodal">
Visit the [SECOND_LIFE] QA Wiki.
+ <tag>confirm</tag>
<usetemplate
ignoretext="Launch my browser to view the QA Wiki"
name="okcancelignore"
@@ -3053,6 +3316,7 @@ Visit the [SECOND_LIFE] QA Wiki.
name="WebLaunchPublicIssue"
type="alertmodal">
Visit the [SECOND_LIFE] Public Issue Tracker, where you can report bugs and other issues.
+ <tag>confirm</tag>
<usetemplate
ignoretext="Launch my browser to use the Public Issue Tracker"
name="okcancelignore"
@@ -3065,6 +3329,7 @@ Visit the [SECOND_LIFE] Public Issue Tracker, where you can report bugs and othe
name="WebLaunchSupportWiki"
type="alertmodal">
Go to the Official Linden Blog, for the latest news and information.
+ <tag>confirm</tag>
<usetemplate
ignoretext="Launch my browser to view the blog"
name="okcancelignore"
@@ -3077,6 +3342,7 @@ Go to the Official Linden Blog, for the latest news and information.
name="WebLaunchLSLGuide"
type="alertmodal">
Do you want to open the Scripting Guide for help with scripting?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Launch my browser to view the Scripting Guide"
name="okcancelignore"
@@ -3089,6 +3355,7 @@ Do you want to open the Scripting Guide for help with scripting?
name="WebLaunchLSLWiki"
type="alertmodal">
Do you want to visit the LSL Portal for help with scripting?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Launch my browser to view the LSL Portal"
name="okcancelignore"
@@ -3103,6 +3370,7 @@ Do you want to visit the LSL Portal for help with scripting?
Are you sure you want to return the selected objects to their owners? Transferable deeded objects will be returned to their previous owners.
*WARNING* No-transfer deeded objects will be deleted!
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm before I return objects to their owners"
name="okcancelignore"
@@ -3116,6 +3384,8 @@ Are you sure you want to return the selected objects to their owners? Transferab
type="alert">
You are currently a member of the group [GROUP].
Leave Group?
+ <tag>group</tag>
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -3127,6 +3397,7 @@ Leave Group?
name="ConfirmKick"
type="alert">
Do you REALLY want to kick all Residents off the grid?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -3138,6 +3409,7 @@ Do you REALLY want to kick all Residents off the grid?
name="MuteLinden"
type="alertmodal">
Sorry, you cannot block a Linden.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -3147,7 +3419,8 @@ Sorry, you cannot block a Linden.
icon="alertmodal.tga"
name="CannotStartAuctionAlreadyForSale"
type="alertmodal">
-You cannot start an auction on a parcel which is already set for sale. Disable the land sale if you are sure you want to start an auction.
+ You cannot start an auction on a parcel which is already set for sale. Disable the land sale if you are sure you want to start an auction.
+ <tag>fail</tag>
</notification>
<notification
@@ -3156,6 +3429,7 @@ You cannot start an auction on a parcel which is already set for sale. Disable
name="MuteByNameFailed"
type="alertmodal">
You already have blocked this name.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -3166,6 +3440,7 @@ You already have blocked this name.
name="RemoveItemWarn"
type="alert">
Though permitted, deleting contents may damage the object. Do you want to delete that item?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -3177,6 +3452,7 @@ Though permitted, deleting contents may damage the object. Do you want to delete
name="CantOfferCallingCard"
type="alert">
Cannot offer a calling card at this time. Please try again in a moment.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -3186,6 +3462,8 @@ Cannot offer a calling card at this time. Please try again in a moment.
icon="alert.tga"
name="CantOfferFriendship"
type="alert">
+ <tag>friendship</tag>
+ <tag>fail</tag>
Cannot offer friendship at this time. Please try again in a moment.
<usetemplate
name="okbutton"
@@ -3210,6 +3488,8 @@ Chat and instant messages will be hidden. Instant messages will get your Busy mo
type="alert">
You have reached your maximum number of groups. Please leave another group before joining this one, or decline the offer.
[NAME] has invited you to join a group as a member.
+ <tag>group</tag>
+ <tag>fail</tag>
<usetemplate
name="okcancelbuttons"
notext="Decline"
@@ -3221,6 +3501,8 @@ You have reached your maximum number of groups. Please leave another group befor
name="JoinedTooManyGroups"
type="alert">
You have reached your maximum number of groups. Please leave some group before joining or creating a new one.
+ <tag>group</tag>
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -3232,6 +3514,7 @@ You have reached your maximum number of groups. Please leave some group before j
type="alert">
<tag>win</tag>
Kick this Resident with what message?
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text">
An administrator has logged you off.
@@ -3254,6 +3537,7 @@ An administrator has logged you off.
type="alert">
<tag>win</tag>
Kick everyone currently on the grid with what message?
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text">
An administrator has logged you off.
@@ -3274,7 +3558,8 @@ An administrator has logged you off.
icon="alert.tga"
name="FreezeUser"
type="alert">
- <tag>win</tag>
+ <tag>win</tag>
+ <tag>confirm</tag>
Freeze this Resident with what message?
<form name="form">
<input name="message" type="text">
@@ -3297,6 +3582,7 @@ You have been frozen. You cannot move or chat. An administrator will contact you
name="UnFreezeUser"
type="alert">
<tag>win</tag>
+ <tag>confirm</tag>
Unfreeze this Resident with what message?
<form name="form">
<input name="message" type="text">
@@ -3328,6 +3614,7 @@ Just like in real life, it takes a while for everyone to learn about a new name.
name="SetDisplayNameBlocked"
type="alert">
Sorry, you cannot change your display name. If you feel this is in error, please contact support.
+ <tag>fail</tag>
</notification>
<notification
@@ -3337,6 +3624,7 @@ Sorry, you cannot change your display name. If you feel this is in error, please
Sorry, that name is too long. Display names can have a maximum of [LENGTH] characters.
Please try a shorter name.
+ <tag>fail</tag>
</notification>
<notification
@@ -3344,6 +3632,7 @@ Please try a shorter name.
name="SetDisplayNameFailedGeneric"
type="alertmodal">
Sorry, we could not set your display name. Please try again later.
+ <tag>fail</tag>
</notification>
<notification
@@ -3351,6 +3640,7 @@ Please try a shorter name.
name="SetDisplayNameMismatch"
type="alertmodal">
The display names you entered do not match. Please re-enter.
+ <tag>fail</tag>
</notification>
<!-- *NOTE: This should never happen -->
@@ -3363,6 +3653,7 @@ Sorry, you have to wait longer before you can change your display name.
See http://wiki.secondlife.com/wiki/Setting_your_display_name
Please try again later.
+ <tag>fail</tag>
</notification>
<notification
@@ -3372,6 +3663,7 @@ Please try again later.
Sorry, we could not set your requested name because it contains a banned word.
Please try a different name.
+ <tag>fail</tag>
</notification>
<notification
@@ -3379,6 +3671,7 @@ Please try again later.
name="AgentDisplayNameSetInvalidUnicode"
type="alertmodal">
The display name you wish to set contains invalid characters.
+ <tag>fail</tag>
</notification>
<notification
@@ -3386,6 +3679,7 @@ Please try again later.
name="AgentDisplayNameSetOnlyPunctuation"
type="alertmodal">
Your display name must contain letters other than punctuation.
+ <tag>fail</tag>
</notification>
@@ -3401,6 +3695,7 @@ Please try again later.
name="OfferTeleport"
type="alertmodal">
Offer a teleport to your location with the following message?
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text">
Join me in [REGION]
@@ -3422,6 +3717,7 @@ Join me in [REGION]
name="OfferTeleportFromGod"
type="alertmodal">
God summon Resident to your location?
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text">
Join me in [REGION]
@@ -3443,6 +3739,7 @@ Join me in [REGION]
name="TeleportFromLandmark"
type="alertmodal">
Are you sure you want to teleport to &lt;nolink&gt;[LOCATION]&lt;/nolink&gt;?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm that I want to teleport to a landmark"
name="okcancelignore"
@@ -3454,7 +3751,8 @@ Are you sure you want to teleport to &lt;nolink&gt;[LOCATION]&lt;/nolink&gt;?
icon="alertmodal.tga"
name="TeleportToPick"
type="alertmodal">
-Teleport to [PICK]?
+ Teleport to [PICK]?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm that I want to teleport to a location in Picks"
name="okcancelignore"
@@ -3467,6 +3765,7 @@ Teleport to [PICK]?
name="TeleportToClassified"
type="alertmodal">
Teleport to [CLASSIFIED]?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm that I want to teleport to a location in Classifieds"
name="okcancelignore"
@@ -3479,6 +3778,7 @@ Teleport to [PICK]?
name="TeleportToHistoryEntry"
type="alertmodal">
Teleport to [HISTORY_ENTRY]?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm that I want to teleport to a history location"
name="okcancelignore"
@@ -3492,6 +3792,7 @@ Teleport to [HISTORY_ENTRY]?
name="MessageEstate"
type="alert">
Type a short announcement which will be sent to everyone currently in your estate.
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text"/>
<button
@@ -3516,6 +3817,7 @@ You are about to change a Linden owned estate (mainland, teen grid, orientation,
This is EXTREMELY DANGEROUS because it can fundamentally affect the Resident experience. On the mainland, it will change thousands of regions and make the spaceserver hiccup.
Proceed?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -3531,6 +3833,7 @@ You are about to change the access list for a Linden owned estate (mainland, tee
This is DANGEROUS and should only be done to invoke the hack allowing objects/L$ to be transfered in/out of a grid.
It will change thousands of regions and make the spaceserver hiccup.
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -3543,6 +3846,7 @@ It will change thousands of regions and make the spaceserver hiccup.
name="EstateAllowedAgentAdd"
type="alert">
Add to allowed list for this estate only or for [ALL_ESTATES]?
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -3556,6 +3860,7 @@ Add to allowed list for this estate only or for [ALL_ESTATES]?
name="EstateAllowedAgentRemove"
type="alert">
Remove from allowed list for this estate only or for [ALL_ESTATES]?
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -3569,6 +3874,8 @@ Remove from allowed list for this estate only or for [ALL_ESTATES]?
name="EstateAllowedGroupAdd"
type="alert">
Add to group allowed list for this estate only or for [ALL_ESTATES]?
+ <tag>group</tag>
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -3582,6 +3889,8 @@ Add to group allowed list for this estate only or for [ALL_ESTATES]?
name="EstateAllowedGroupRemove"
type="alert">
Remove from group allowed list for this estate only or [ALL_ESTATES]?
+ <tag>group</tag>
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -3595,6 +3904,7 @@ Remove from group allowed list for this estate only or [ALL_ESTATES]?
name="EstateBannedAgentAdd"
type="alert">
Deny access for this estate only or for [ALL_ESTATES]?
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -3608,6 +3918,7 @@ Deny access for this estate only or for [ALL_ESTATES]?
name="EstateBannedAgentRemove"
type="alert">
Remove this Resident from the ban list for access for this estate only or for [ALL_ESTATES]?
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -3621,6 +3932,7 @@ Remove this Resident from the ban list for access for this estate only or for [
name="EstateManagerAdd"
type="alert">
Add estate manager for this estate only or for [ALL_ESTATES]?
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -3634,6 +3946,7 @@ Add estate manager for this estate only or for [ALL_ESTATES]?
name="EstateManagerRemove"
type="alert">
Remove estate manager for this estate only or for [ALL_ESTATES]?
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -3647,6 +3960,7 @@ Remove estate manager for this estate only or for [ALL_ESTATES]?
name="EstateKickUser"
type="alert">
Kick [EVIL_USER] from this estate?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -3658,6 +3972,7 @@ Kick [EVIL_USER] from this estate?
name="EstateChangeCovenant"
type="alertmodal">
Are you sure you want to change the Estate Covenant?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -3682,6 +3997,7 @@ Please verify you have the latest Viewer installed, and go to the Knowledge Base
name="RegionEntryAccessBlocked_KB"
type="alertmodal">
<tag>fail</tag>
+ <tag>confirm</tag>
You are not allowed in that region due to your maturity Rating.
Go to the Knowledge Base for more information about maturity Ratings?
@@ -3708,6 +4024,7 @@ You are not allowed in that region due to your maturity Rating.
name="RegionEntryAccessBlocked_Change"
type="alertmodal">
<tag>fail</tag>
+ <tag>confirm</tag>
You are not allowed in that Region due to your maturity Rating preference.
To enter the desired region, please change your maturity Rating preference. This will allow you to search for and access [REGIONMATURITY] content. To undo any changes, go to Me &gt; Preferences &gt; General.
@@ -3739,6 +4056,7 @@ Your maturity Rating preference is now [RATING].
You cannot claim this land due to your maturity Rating. This may be a result of a lack of information validating your age.
Please verify you have the latest Viewer installed, and go to the Knowledge Base for details on accessing areas with this maturity rating.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -3751,6 +4069,8 @@ Please verify you have the latest Viewer installed, and go to the Knowledge Base
You cannot claim this land due to your maturity Rating.
Go to the Knowledge Base for more information about maturity Ratings?
+ <tag>fail</tag>
+ <tag>confirm</tag>
<url option="0" name="url">
http://wiki.secondlife.com/wiki/Linden_Lab_Official:Maturity_ratings:_an_overview
</url>
@@ -3766,6 +4086,7 @@ Go to the Knowledge Base for more information about maturity Ratings?
name="LandClaimAccessBlocked_Notify"
type="notifytip">
You cannot claim this land due to your maturity Rating.
+ <tag>fail</tag>
</notification>
<notification
@@ -3775,6 +4096,8 @@ You cannot claim this land due to your maturity Rating.
You cannot claim this land due to your maturity Rating preference.
You can click &apos;Change Preference&apos; to raise your maturity Rating preference now and allow you to enter. You will be able to search and access [REGIONMATURITY] content from now on. If you later want to change this setting back, go to Me &gt; Preferences &gt; General.
+ <tag>fail</tag>
+ <tag>confirm</tag>
<usetemplate
name="okcancelignore"
yestext="Change Preference"
@@ -3789,6 +4112,7 @@ You can click &apos;Change Preference&apos; to raise your maturity Rating prefer
You cannot buy this land due to your maturity Rating. This may be a result of a lack of information validating your age.
Please verify you have the latest Viewer installed, and go to the Knowledge Base for details on accessing areas with this maturity rating.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -3801,6 +4125,8 @@ Please verify you have the latest Viewer installed, and go to the Knowledge Base
You cannot buy this land due to your maturity Rating.
Go to the Knowledge Base for more information about maturity Ratings?
+ <tag>confirm</tag>
+ <tag>fail</tag>
<url option="0" name="url">
http://wiki.secondlife.com/wiki/Linden_Lab_Official:Maturity_ratings:_an_overview
</url>
@@ -3816,6 +4142,7 @@ Go to the Knowledge Base for more information about maturity Ratings?
name="LandBuyAccessBlocked_Notify"
type="notifytip">
You cannot buy this land due to your maturity Rating.
+ <tag>fail</tag>
</notification>
<notification
@@ -3825,6 +4152,8 @@ You cannot buy this land due to your maturity Rating.
You cannot buy this land due to your maturity Rating preference.
You can click &apos;Change Preference&apos; to raise your maturity Rating preference now and allow you to enter. You will be able to search and access [REGIONMATURITY] content from now on. If you later want to change this setting back, go to Me &gt; Preferences &gt; General.
+ <tag>confirm</tag>
+ <tag>fail</tag>
<usetemplate
name="okcancelignore"
yestext="Change Preference"
@@ -3837,6 +4166,7 @@ You can click &apos;Change Preference&apos; to raise your maturity Rating prefer
name="TooManyPrimsSelected"
type="alertmodal">
There are too many prims selected. Please select [MAX_PRIM_COUNT] or fewer prims and try again
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -3847,6 +4177,7 @@ There are too many prims selected. Please select [MAX_PRIM_COUNT] or fewer prim
name="ProblemImportingEstateCovenant"
type="alertmodal">
Problem importing estate covenant.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -3857,6 +4188,7 @@ Problem importing estate covenant.
name="ProblemAddingEstateManager"
type="alertmodal">
Problems adding a new estate manager. One or more estates may have a full manager list.
+ <tag>fail</tag>
</notification>
<notification
@@ -3864,6 +4196,7 @@ Problems adding a new estate manager. One or more estates may have a full manag
name="ProblemAddingEstateGeneric"
type="alertmodal">
Problems adding to this estate list. One or more estates may have a full list.
+ <tag>fail</tag>
</notification>
<notification
@@ -3874,6 +4207,7 @@ Unable to load notecard&apos;s asset at this time.
<usetemplate
name="okbutton"
yestext="OK"/>
+ <tag>fail</tag>
</notification>
<notification
@@ -3884,6 +4218,7 @@ Insufficient permissions to view notecard associated with asset ID requested.
<usetemplate
name="okbutton"
yestext="OK"/>
+ <tag>fail</tag>
</notification>
<notification
@@ -3891,6 +4226,7 @@ Insufficient permissions to view notecard associated with asset ID requested.
name="MissingNotecardAssetID"
type="alertmodal">
Asset ID for notecard is missing from database.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -3903,6 +4239,8 @@ Asset ID for notecard is missing from database.
Remember: Classified ad fees are non-refundable.
Publish this classified now for L$[AMOUNT]?
+ <tag>confirm</tag>
+ <tag>funds</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -3914,6 +4252,7 @@ Publish this classified now for L$[AMOUNT]?
name="SetClassifiedMature"
type="alertmodal">
Does this classified contain Moderate content?
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -3926,6 +4265,8 @@ Does this classified contain Moderate content?
name="SetGroupMature"
type="alertmodal">
Does this group contain Moderate content?
+ <tag>group</tag>
+ <tag>confirm</tag>
<usetemplate
canceltext="Cancel"
name="yesnocancelbuttons"
@@ -3939,6 +4280,7 @@ Does this group contain Moderate content?
name="ConfirmRestart"
type="alert">
Do you really want to restart this region in 2 minutes?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -3951,6 +4293,7 @@ Do you really want to restart this region in 2 minutes?
name="MessageRegion"
type="alert">
Type a short announcement which will be sent to everyone in this region.
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text"/>
<button
@@ -3982,6 +4325,8 @@ To enter Adult regions, Residents must be Account Verified, either by age-verifi
name="VoiceVersionMismatch"
type="alertmodal">
This version of [APP_NAME] is not compatible with the Voice Chat feature in this region. In order for Voice Chat to function correctly you will need to update [APP_NAME].
+ <tag>fail</tag>
+ <tag>voice</tag>
</notification>
<notification
@@ -3991,6 +4336,7 @@ This version of [APP_NAME] is not compatible with the Voice Chat feature in this
type="alertmodal">
Cannot buy objects from different owners at the same time.
Please select only one object and try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -4000,6 +4346,7 @@ Please select only one object and try again.
type="alertmodal">
Unable to buy the contents of more than one object at a time.
Please select only one object and try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -4009,6 +4356,7 @@ Please select only one object and try again.
type="alertmodal">
Cannot buy objects from different owners at the same time.
Please select only one object and try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -4021,6 +4369,8 @@ You will be able to:
Modify: [MODIFYPERM]
Copy: [COPYPERM]
Resell or Give Away: [RESELLPERM]
+ <tag>confirm</tag>
+ <tag>funds</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -4037,6 +4387,8 @@ You will be able to:
Modify: [MODIFYPERM]
Copy: [COPYPERM]
Resell or Give Away: [RESELLPERM]
+ <tag>confirm</tag>
+ <tag>funds</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -4053,6 +4405,8 @@ You will be able to:
Modify: [MODIFYPERM]
Copy: [COPYPERM]
Resell or Give Away: [RESELLPERM]
+ <tag>confirm</tag>
+ <tag>funds</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -4069,6 +4423,8 @@ You will be able to:
Modify: [MODIFYPERM]
Copy: [COPYPERM]
Resell or Give Away: [RESELLPERM]
+ <tag>confirm</tag>
+ <tag>funds</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -4081,6 +4437,8 @@ You will be able to:
type="alertmodal">
Buy contents from [OWNER] for L$[PRICE]?
They will be copied to your inventory.
+ <tag>confirm</tag>
+ <tag>funds</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -4093,6 +4451,8 @@ They will be copied to your inventory.
type="alertmodal">
Buy contents for L$[PRICE]?
They will be copied to your inventory.
+ <tag>confirm</tag>
+ <tag>funds</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -4107,6 +4467,8 @@ This transaction will:
[ACTION]
Are you sure you want to proceed with this purchase?
+ <tag>confirm</tag>
+ <tag>funds</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -4122,6 +4484,8 @@ This transaction will:
Are you sure you want to proceed with this purchase?
Please re-enter your password and click OK.
+ <tag>funds</tag>
+ <tag>confirm</tag>
<form name="form">
<input
name="message"
@@ -4157,6 +4521,7 @@ You have selected &apos;no copy&apos; inventory items.
These items will be moved to your inventory, not copied.
Move the inventory item(s)?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Warn me before I move &apos;no-copy&apos; items from an object"
name="okcancelignore"
@@ -4171,7 +4536,8 @@ Move the inventory item(s)?
You have selected &apos;no copy&apos; inventory items. These items will be moved to your inventory, not copied.
Because this object is scripted, moving these items to your inventory may cause the script to malfunction.
-Move the inventory item(s)?
+Move the inventory item(s)?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Warn me before I move &apos;no-copy&apos; items which might break a scripted object"
name="okcancelignore"
@@ -4195,6 +4561,7 @@ Warning: The &apos;Pay object&apos; click action has been set, but it will only
name="OpenObjectCannotCopy"
type="alertmodal">
There are no items in this object that you are allowed to copy.
+ <tag>fail</tag>
</notification>
<notification
@@ -4202,6 +4569,7 @@ There are no items in this object that you are allowed to copy.
name="WebLaunchAccountHistory"
type="alertmodal">
Go to your [http://secondlife.com/account/ Dashboard] to see your account history?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Launch my browser to see my account history"
name="okcancelignore"
@@ -4215,6 +4583,7 @@ Go to your [http://secondlife.com/account/ Dashboard] to see your account histor
type="alertmodal"
unique="true">
Are you sure you want to quit?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm before I quit"
name="okcancelignore"
@@ -4228,6 +4597,7 @@ Are you sure you want to quit?
type="alertmodal"
unique="true">
[QUESTION]
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm before deleting items"
name="okcancelignore"
@@ -4251,6 +4621,7 @@ All reported abuses are investigated and resolved.
type="alertmodal">
Please select a category for this abuse report.
Selecting a category helps us file and process abuse reports.
+ <tag>fail</tag>
</notification>
<notification
@@ -4259,6 +4630,7 @@ Selecting a category helps us file and process abuse reports.
type="alertmodal">
Please enter the name of the abuser.
Entering an accurate value helps us file and process abuse reports.
+ <tag>fail</tag>
</notification>
<notification
@@ -4267,6 +4639,7 @@ Entering an accurate value helps us file and process abuse reports.
type="alertmodal">
Please enter the location where the abuse took place.
Entering an accurate value helps us file and process abuse reports.
+ <tag>fail</tag>
</notification>
<notification
@@ -4275,6 +4648,7 @@ Entering an accurate value helps us file and process abuse reports.
type="alertmodal">
Please enter a summary of the abuse that took place.
Entering an accurate summary helps us file and process abuse reports.
+ <tag>fail</tag>
</notification>
<notification
@@ -4284,6 +4658,7 @@ Entering an accurate summary helps us file and process abuse reports.
Please enter a detailed description of the abuse that took place.
Be as specific as you can, including names and the details of the incident you are reporting.
Entering an accurate description helps us file and process abuse reports.
+ <tag>fail</tag>
</notification>
<notification
@@ -4311,6 +4686,7 @@ Linden Lab
type="alertmodal">
The following required components are missing from [FLOATER]:
[COMPONENTS]
+ <tag>fail</tag>
</notification>
<notification
@@ -4320,6 +4696,7 @@ The following required components are missing from [FLOATER]:
type="alert">
There is already an object attached to this point on your body.
Do you want to replace it with the selected object?
+ <tag>confirm</tag>
<form name="form">
<ignore name="ignore"
save_option="true"
@@ -4346,6 +4723,7 @@ Do you want to replace it with the selected object?
You are in Busy Mode, which means you will not receive any items offered in exchange for this payment.
Would you like to leave Busy Mode before completing this transaction?
+ <tag>confirm</tag>
<form name="form">
<ignore name="ignore"
save_option="true"
@@ -4369,6 +4747,7 @@ Would you like to leave Busy Mode before completing this transaction?
name="ConfirmDeleteProtectedCategory"
type="alertmodal">
The folder &apos;[FOLDERNAME]&apos; is a system folder. Deleting system folders can cause instability. Are you sure you want to delete it?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm before I delete a system folder"
name="okcancelignore"
@@ -4381,6 +4760,7 @@ The folder &apos;[FOLDERNAME]&apos; is a system folder. Deleting system folders
name="ConfirmEmptyTrash"
type="alertmodal">
Are you sure you want to permanently delete the contents of your Trash?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm before I empty the inventory Trash folder"
name="okcancelignore"
@@ -4393,6 +4773,7 @@ Are you sure you want to permanently delete the contents of your Trash?
name="ConfirmClearBrowserCache"
type="alertmodal">
Are you sure you want to delete your travel, web, and search history?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -4404,6 +4785,7 @@ Are you sure you want to delete your travel, web, and search history?
name="ConfirmClearCookies"
type="alertmodal">
Are you sure you want to clear your cookies?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -4415,6 +4797,7 @@ Are you sure you want to clear your cookies?
name="ConfirmClearMediaUrlList"
type="alertmodal">
Are you sure you want to clear your list of saved URLs?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -4426,6 +4809,7 @@ Are you sure you want to clear your list of saved URLs?
name="ConfirmEmptyLostAndFound"
type="alertmodal">
Are you sure you want to permanently delete the contents of your Lost And Found?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Confirm before I empty the inventory Lost And Found folder"
name="okcancelignore"
@@ -4452,6 +4836,7 @@ Link to this from a web page to give others easy access to this location, or try
name="WLSavePresetAlert"
type="alertmodal">
Do you wish to overwrite the saved preset?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="No"
@@ -4463,6 +4848,7 @@ Do you wish to overwrite the saved preset?
name="WLDeletePresetAlert"
type="alertmodal">
Do you wish to delete [SKY]?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="No"
@@ -4474,6 +4860,7 @@ Do you wish to delete [SKY]?
name="WLNoEditDefault"
type="alertmodal">
You cannot edit or delete a default preset.
+ <tag>fail</tag>
</notification>
<notification
@@ -4481,6 +4868,7 @@ You cannot edit or delete a default preset.
name="WLMissingSky"
type="alertmodal">
This day cycle file references a missing sky file: [SKY].
+ <tag>fail</tag>
</notification>
<notification
@@ -4499,6 +4887,7 @@ PostProcess Effect exists. Do you still wish overwrite it?
name="NewSkyPreset"
type="alert">
Give me a name for the new sky.
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text">
New Preset
@@ -4520,6 +4909,7 @@ New Preset
name="ExistsSkyPresetAlert"
type="alertmodal">
Preset already exists!
+ <tag>fail</tag>
</notification>
<notification
@@ -4527,6 +4917,7 @@ Preset already exists!
name="NewWaterPreset"
type="alert">
Give me a name for the new water preset.
+ <tag>confirm</tag>
<form name="form">
<input name="message" type="text">
New Preset
@@ -4548,6 +4939,7 @@ New Preset
name="ExistsWaterPresetAlert"
type="alertmodal">
Preset already exists!
+ <tag>fail</tag>
</notification>
<notification
@@ -4555,6 +4947,7 @@ Preset already exists!
name="WaterNoEditDefault"
type="alertmodal">
You cannot edit or delete a default preset.
+ <tag>fail</tag>
</notification>
<notification
@@ -4563,6 +4956,7 @@ You cannot edit or delete a default preset.
type="alertmodal">
Unable to start a new chat session with [RECIPIENT].
[REASON]
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -4574,6 +4968,7 @@ Unable to start a new chat session with [RECIPIENT].
type="alertmodal">
[EVENT]
[REASON]
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -4595,6 +4990,7 @@ Your chat session with [NAME] must close.
name="Cannot_Purchase_an_Attachment"
type="alertmodal">
You can&apos;t buy an object while it is attached.
+ <tag>fail</tag>
</notification>
<notification
@@ -4613,6 +5009,7 @@ Granting this request gives a script ongoing permission to take Linden dollars (
name="AutoWearNewClothing"
type="alertmodal">
Would you like to automatically wear the clothing you are about to create?
+ <tag>confirm</tag>
<usetemplate
ignoretext="Wear the clothing I create while editing My Appearance"
name="okcancelignore"
@@ -4628,6 +5025,7 @@ Would you like to automatically wear the clothing you are about to create?
You must be age-verified to visit this area. Do you want to go to the [SECOND_LIFE] website and verify your age?
[_URL]
+ <tag>confirm</tag>
<url option="0" name="url">
https://secondlife.com/account/verification.php
@@ -4646,6 +5044,7 @@ You must be age-verified to visit this area. Do you want to go to the [SECOND_L
You must have payment information on file to visit this area. Do you want to go to the [SECOND_LIFE] website and set this up?
[_URL]
+ <tag>confirm</tag>
<url option="0" name="url">
https://secondlife.com/account/
@@ -4662,6 +5061,7 @@ You must have payment information on file to visit this area. Do you want to go
name="MissingString"
type="alertmodal">
The string [STRING_NAME] is missing from strings.xml
+ <tag>fail</tag>
</notification>
<notification
@@ -4712,12 +5112,14 @@ Replaced missing clothing/body part with default.
persist="true"
type="groupnotify">
Topic: [SUBJECT], Message: [MESSAGE]
+ <tag>group</tag>
</notification>
<notification
icon="notifytip.tga"
name="FriendOnline"
type="notifytip">
+ <tag>friendship</tag>
[NAME] is Online
</notification>
@@ -4725,6 +5127,7 @@ Topic: [SUBJECT], Message: [MESSAGE]
icon="notifytip.tga"
name="FriendOffline"
type="notifytip">
+ <tag>friendship</tag>
[NAME] is Offline
</notification>
@@ -4732,6 +5135,7 @@ Topic: [SUBJECT], Message: [MESSAGE]
icon="notifytip.tga"
name="AddSelfFriend"
type="notifytip">
+ <tag>friendship</tag>
Although you&apos;re very nice, you can&apos;t add yourself as a friend.
</notification>
@@ -4749,6 +5153,7 @@ Uploading in-world and web site snapshots...
persist="true"
type="notify">
You paid L$[AMOUNT] to upload.
+<tag>funds</tag>
</notification>
<notification
@@ -4777,6 +5182,7 @@ Terrain.raw downloaded
name="GestureMissing"
type="notifytip">
Hmm. Gesture [NAME] is missing from the database.
+ <tag>fail</tag>
</notification>
<notification
@@ -4784,6 +5190,7 @@ Hmm. Gesture [NAME] is missing from the database.
name="UnableToLoadGesture"
type="notifytip">
Unable to load gesture [NAME].
+ <tag>fail</tag>
</notification>
<notification
@@ -4791,6 +5198,7 @@ Unable to load gesture [NAME].
name="LandmarkMissing"
type="notifytip">
Landmark is missing from database.
+ <tag>fail</tag>
</notification>
<notification
@@ -4798,6 +5206,7 @@ Landmark is missing from database.
name="UnableToLoadLandmark"
type="notifytip">
Unable to load landmark. Please try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -4813,6 +5222,7 @@ This might affect your password.
name="NotecardMissing"
type="notifytip">
Notecard is missing from database.
+ <tag>fail</tag>
</notification>
<notification
@@ -4820,6 +5230,7 @@ Notecard is missing from database.
name="NotecardNoPermissions"
type="notifytip">
You don&apos;t have permission to view this notecard.
+ <tag>fail</tag>
</notification>
<notification
@@ -4827,6 +5238,7 @@ You don&apos;t have permission to view this notecard.
name="RezItemNoPermissions"
type="notifytip">
Insufficient permissions to rez object.
+ <tag>fail</tag>
</notification>
<notification
@@ -4835,6 +5247,7 @@ Insufficient permissions to rez object.
type="notifytip">
Unable to load notecard.
Please try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -4842,6 +5255,7 @@ Please try again.
name="ScriptMissing"
type="notifytip">
Script is missing from database.
+ <tag>fail</tag>
</notification>
<notification
@@ -4849,6 +5263,7 @@ Script is missing from database.
name="ScriptNoPermissions"
type="notifytip">
Insufficient permissions to view script.
+ <tag>fail</tag>
</notification>
<notification
@@ -4856,6 +5271,7 @@ Insufficient permissions to view script.
name="UnableToLoadScript"
type="notifytip">
Unable to load script. Please try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -4863,6 +5279,7 @@ Unable to load script. Please try again.
name="IncompleteInventory"
type="notifytip">
The complete contents you are offering are not yet locally available. Please try offering those items again in a minute.
+ <tag>fail</tag>
</notification>
<notification
@@ -4870,6 +5287,7 @@ The complete contents you are offering are not yet locally available. Please try
name="CannotModifyProtectedCategories"
type="notifytip">
You cannot modify protected categories.
+ <tag>fail</tag>
</notification>
<notification
@@ -4877,6 +5295,7 @@ You cannot modify protected categories.
name="CannotRemoveProtectedCategories"
type="notifytip">
You cannot remove protected categories.
+ <tag>fail</tag>
</notification>
<notification
@@ -4885,6 +5304,7 @@ You cannot remove protected categories.
type="notifytip">
Unable to buy while downloading object data.
Please try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -4893,6 +5313,7 @@ Please try again.
type="notifytip">
Unable to link while downloading object data.
Please try again.
+ <tag>fail</tag>
</notification>
<notification
@@ -4901,6 +5322,7 @@ Please try again.
type="notifytip">
You can only buy objects from one owner at a time.
Please select a single object.
+ <tag>fail</tag>
</notification>
<notification
@@ -4908,6 +5330,7 @@ Please select a single object.
name="ObjectNotForSale"
type="notifytip">
This object is not for sale.
+ <tag>fail</tag>
</notification>
<notification
@@ -4929,6 +5352,7 @@ Now leaving god mode, level [LEVEL]
name="CopyFailed"
type="notifytip">
You don&apos;t have permission to copy this.
+ <tag>fail</tag>
</notification>
<notification
@@ -4990,6 +5414,7 @@ Select the Resident from the list, then click &apos;IM&apos; at the bottom of th
type="notifytip">
Can&apos;t select land across server boundaries.
Try selecting a smaller piece of land.
+ <tag>fail</tag>
</notification>
<notification
@@ -4997,6 +5422,7 @@ Try selecting a smaller piece of land.
name="SearchWordBanned"
type="notifytip">
Some terms in your search query were excluded due to content restrictions as clarified in the Community Standards.
+ <tag>fail</tag>
</notification>
<notification
@@ -5004,6 +5430,7 @@ Some terms in your search query were excluded due to content restrictions as cla
name="NoContentToSearch"
type="notifytip">
Please select at least one type of content to search (General, Moderate, or Adult).
+ <tag>fail</tag>
</notification>
<notification
@@ -5019,6 +5446,7 @@ Please select at least one type of content to search (General, Moderate, or Adul
name="PaymentReceived"
persist="true"
type="notify">
+ <tag>funds</tag>
[MESSAGE]
</notification>
@@ -5027,6 +5455,7 @@ Please select at least one type of content to search (General, Moderate, or Adul
name="PaymentSent"
persist="true"
type="notify">
+ <tag>funds</tag>
[MESSAGE]
</notification>
@@ -5084,13 +5513,16 @@ Deactivated gestures with same trigger:
type="notify">
Apple&apos;s QuickTime software does not appear to be installed on your system.
If you want to view streaming media on parcels that support it you should go to the [http://www.apple.com/quicktime QuickTime site] and install the QuickTime Player.
+ <tag>fail</tag>
</notification>
+
<notification
icon="notify.tga"
name="NoPlugin"
persist="true"
type="notify">
No Media Plugin was found to handle the "[MIME_TYPE]" mime type. Media of this type will be unavailable.
+ <tag>fail</tag>
<unique>
<context>MIME_TYPE</context>
</unique>
@@ -5104,6 +5536,7 @@ The following Media Plugin has failed:
[PLUGIN]
Please re-install the plugin or contact the vendor if you continue to experience problems.
+ <tag>fail</tag>
<form name="form">
<ignore name="ignore"
text="A Media Plugin fails to run"/>
@@ -5141,6 +5574,7 @@ The objects on the selected parcel of land owned by the Resident &apos;[NAME]&ap
The objects on the selected parcel of land shared with the group [GROUPNAME] have been returned back to their owner&apos;s inventory.
Transferable deeded objects have been returned to their previous owners.
Non-transferable objects that are deeded to the group have been deleted.
+ <tag>group</tag>
</notification>
<notification
@@ -5197,6 +5631,7 @@ This area does not allow pushing. You can&apos;t push others here unless you own
type="notify"
unique="true">
This area has voice chat disabled. You won&apos;t be able to hear anyone talking.
+ <tag>voice</tag>
</notification>
<notification
@@ -5241,6 +5676,7 @@ No scripts will work here except those belonging to the land owner.
persist="true"
type="notify">
You can only claim public land in the Region you&apos;re in.
+ <tag>fail</tag>
</notification>
<notification
@@ -5529,6 +5965,7 @@ An object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; owned by [NAME_SLU
name="JoinGroup"
persist="true"
type="notify">
+ <tag>group</tag>
[MESSAGE]
<form name="form">
<button
@@ -5553,6 +5990,7 @@ An object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; owned by [NAME_SLU
[NAME_SLURL] has offered to teleport you to their location:
[MESSAGE] - [MATURITY_STR] &lt;icon&gt;[MATURITY_ICON]&lt;/icon&gt;
+ <tag>confirm</tag>
<form name="form">
<button
index="0"
@@ -5596,6 +6034,8 @@ An object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; owned by [NAME_SLU
icon="notify.tga"
name="OfferFriendship"
type="offer">
+ <tag>friendship</tag>
+ <tag>confirm</tag>
[NAME_SLURL] is offering friendship.
[MESSAGE]
@@ -5617,6 +6057,7 @@ An object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; owned by [NAME_SLU
icon="notify.tga"
name="FriendshipOffered"
type="offer">
+ <tag>friendship</tag>
You have offered friendship to [TO_NAME]
</notification>
@@ -5625,6 +6066,7 @@ An object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; owned by [NAME_SLU
name="OfferFriendshipNoMessage"
persist="true"
type="notify">
+ <tag>friendship</tag>
[NAME_SLURL] is offering friendship.
(By default, you will be able to see each other&apos;s online status.)
@@ -5644,6 +6086,7 @@ An object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; owned by [NAME_SLU
icon="notify.tga"
name="FriendshipAccepted"
type="offer">
+ <tag>friendship</tag>
[NAME] accepted your friendship offer.
</notification>
@@ -5652,6 +6095,7 @@ An object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; owned by [NAME_SLU
name="FriendshipDeclined"
persist="true"
type="notify">
+ <tag>friendship</tag>
[NAME] declined your friendship offer.
</notification>
@@ -5659,6 +6103,7 @@ An object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; owned by [NAME_SLU
icon="notify.tga"
name="FriendshipAcceptedByMe"
type="offer">
+ <tag>friendship</tag>
Friendship offer accepted.
</notification>
@@ -5666,6 +6111,7 @@ Friendship offer accepted.
icon="notify.tga"
name="FriendshipDeclinedByMe"
type="offer">
+ <tag>friendship</tag>
Friendship offer declined.
</notification>
@@ -5719,6 +6165,7 @@ Load web page [URL]?
[MESSAGE]
From object: &lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;, owner: [NAME]?
+ <tag>confirm</tag>
<form name="form">
<button
index="0"
@@ -5737,6 +6184,7 @@ From object: &lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;, owner: [NAME]?
persist="true"
type="notify">
Failed to find [TYPE] in database.
+ <tag>fail</tag>
</notification>
<notification
@@ -5745,6 +6193,7 @@ Failed to find [TYPE] in database.
persist="true"
type="notify">
Failed to find [TYPE] named [DESC] in database.
+ <tag>fail</tag>
</notification>
<notification
@@ -5753,6 +6202,7 @@ Failed to find [TYPE] named [DESC] in database.
persist="true"
type="notify">
The item you are trying to wear uses a feature that your Viewer can&apos;t read. Please upgrade your version of [APP_NAME] to wear this item.
+ <tag>fail</tag>
</notification>
<notification
@@ -5764,6 +6214,7 @@ The item you are trying to wear uses a feature that your Viewer can&apos;t read.
[QUESTIONS]
Is this OK?
+ <tag>confirm</tag>
<form name="form">
<button
index="0"
@@ -5792,6 +6243,7 @@ An object named &apos;&lt;nolink&gt;[OBJECTNAME]&lt;/nolink&gt;&apos;, owned by
If you do not trust this object and its creator, you should deny the request.
Grant this request?
+ <tag>confirm</tag>
<form name="form">
<button
index="0"
@@ -5827,6 +6279,7 @@ Grant this request?
icon="notify.tga"
name="ScriptDialogGroup"
type="notify">
+ <tag>group</tag>
[GROUPNAME]&apos;s &apos;&lt;nolink&gt;[TITLE]&lt;/nolink&gt;&apos;
[MESSAGE]
<form name="form">
@@ -5863,6 +6316,7 @@ Your L$ balance is shown in the upper-right.
name="BuyLindenDollarSuccess"
persist="true"
type="notify">
+ <tag>funds</tag>
Thank you for your payment!
Your L$ balance will be updated when processing completes. If processing takes more than 20 mins, your transaction may be cancelled. In that case, the purchase amount will be credited to your US$ balance.
@@ -5870,57 +6324,6 @@ Your L$ balance will be updated when processing completes. If processing takes m
The status of your payment can be checked on your Transaction History page on your [http://secondlife.com/account/ Dashboard]
</notification>
-<!--
- <notification
- icon="notify.tga"
- name="FirstSit"
- persist="true"
- type="notify">
-You are sitting.
-Use your arrow keys (or AWSD) to look around.
-Click the &apos;Stand Up&apos; button to stand.
- </notification>
-
- <notification
- icon="notify.tga"
- name="FirstMap"
- persist="true"
- type="notify">
-Click and drag the map to look around.
-Double-click to teleport.
-Use the controls on the right to find things and display different backgrounds.
- </notification>
-
- <notification
- icon="notify.tga"
- name="FirstBuild"
- persist="true"
- type="notify">
-You have opened the Build Tools. Every object you see around you was created using these tools.
- </notification>
--->
-
-<!--
- <notification
- icon="notify.tga"
- name="FirstLeftClickNoHit"
- persist="true"
- type="notify">
- Left-clicking interacts with special objects.
- If the mouse pointer changes to a hand, you can interact with the object.
- Right-click always shows a menu of things you can do.
- </notification>
-
- <notification
- icon="notify.tga"
- name="FirstTeleport"
- persist="true"
- type="notify">
-You can only teleport to certain areas in this region. The arrow points to your specific destination. Click the arrow to dismiss it.
- </notification>
-
--->
-
<notification
icon="notify.tga"
name="FirstOverrideKeys"
@@ -5932,30 +6335,6 @@ Some objects (like guns) require you to go into mouselook to use them.
Press &apos;M&apos; to do this.
</notification>
-<!--
- <notification
- icon="notify.tga"
- name="FirstAppearance"
- persist="true"
- type="notify">
-You are editing your Appearance.
-Use the arrow keys to look around.
-When you are done, press &apos;Save All&apos;.
- </notification>
-
- <notification
- icon="notify.tga"
- name="FirstInventory"
- persist="true"
- type="notify">
-This is your Inventory, which contains items you own.
-
-* To wear something, drag it onto yourself.
-* To rez something inworld, drag it onto the ground.
-* To read a notecard, double-click it.
- </notification>
--->
-
<notification
icon="notify.tga"
name="FirstSandbox"
@@ -5966,47 +6345,6 @@ This is a sandbox area, and is meant to help Residents learn how to build.
Things you build here will be deleted after you leave, so don&apos;t forget to right-click and choose &apos;Take&apos; to move your creation to your Inventory.
</notification>
-<!--
- <notification
- icon="notify.tga"
- name="FirstFlexible"
- persist="true"
- type="notify">
-This object is flexible. Flexis must be phantom and not physical.
- </notification>
-
- <notification
- icon="notify.tga"
- name="FirstDebugMenus"
- persist="true"
- type="notify">
-You opened the Advanced menu.
-
-To toggle this menu,
- Windows: Ctrl+Alt+D
- Mac: &#8997;&#8984;D
-
- </notification>
-
- <notification
- icon="notify.tga"
- name="FirstSculptedPrim"
- persist="true"
- type="notify">
-You are editing a Sculpted prim. Sculpties require a special texture to define their shape.
- </notification>
--->
-
- <!--
- <notification
- icon="notify.tga"
- name="FirstMedia"
- persist="true"
- type="notify">
- You have begun playing media. Media can set to play automatically in the preferences window under Audio / Video. Note that this can be a security risk for media sites you do not trust.
- </notification>
- -->
-
<notification
icon="notifytip.tga"
name="MaxListSelectMessage"
@@ -6020,6 +6358,8 @@ You may only select up to [MAX_SELECT] items from this list.
type="notify">
[NAME] is inviting you to a Voice Chat call.
Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
+ <tag>confirm</tag>
+ <tag>voice</tag>
<unique>
<context>NAME</context>
</unique>
@@ -6069,6 +6409,9 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
type="notify">
[NAME] has joined a Voice Chat call with the group [GROUP].
Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
+ <tag>group</tag>
+ <tag>confirm</tag>
+ <tag>voice</tag>
<unique>
<context>NAME</context>
<context>GROUP</context>
@@ -6095,6 +6438,8 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
type="notify">
[NAME] has joined a voice chat call with a conference chat.
Click Accept to join the call or Decline to decline the invitation. Click Block to block this caller.
+ <tag>confirm</tag>
+ <tag>voice</tag>
<unique>
<context>NAME</context>
</unique>
@@ -6120,6 +6465,8 @@ Click Accept to join the call or Decline to decline the invitation. Click Block
type="notify">
[NAME] is inviting you to a conference chat.
Click Accept to join the chat or Decline to decline the invitation. Click Block to block this caller.
+ <tag>confirm</tag>
+ <tag>voice</tag>
<unique>
<context>NAME</context>
</unique>
@@ -6144,6 +6491,8 @@ Click Accept to join the chat or Decline to decline the invitation. Click Block
name="VoiceChannelFull"
type="notifytip">
The voice call you are trying to join, [VOICE_CHANNEL_NAME], has reached maximum capacity. Please try again later.
+ <tag>fail</tag>
+ <tag>voice</tag>
<unique>
<context>VOICE_CHANNEL_NAME</context>
</unique>
@@ -6154,7 +6503,9 @@ The voice call you are trying to join, [VOICE_CHANNEL_NAME], has reached maximum
name="ProximalVoiceChannelFull"
type="notifytip"
unique="true">
-We&apos;re sorry. This area has reached maximum capacity for voice conversations. Please try to use voice in another area.
+ We&apos;re sorry. This area has reached maximum capacity for voice conversations. Please try to use voice in another area.
+ <tag>fail</tag>
+ <tag>voice</tag>
</notification>
<notification
@@ -6162,6 +6513,7 @@ We&apos;re sorry. This area has reached maximum capacity for voice conversation
name="VoiceChannelDisconnected"
type="notifytip">
You have been disconnected from [VOICE_CHANNEL_NAME]. You will now be reconnected to Nearby Voice Chat.
+ <tag>voice</tag>
<unique>
<context>VOICE_CHANNEL_NAME</context>
</unique>
@@ -6172,6 +6524,7 @@ You have been disconnected from [VOICE_CHANNEL_NAME]. You will now be reconnect
name="VoiceChannelDisconnectedP2P"
type="notifytip">
[VOICE_CHANNEL_NAME] has ended the call. You will now be reconnected to Nearby Voice Chat.
+ <tag>voice</tag>
<unique>
<context>VOICE_CHANNEL_NAME</context>
</unique>
@@ -6182,6 +6535,8 @@ You have been disconnected from [VOICE_CHANNEL_NAME]. You will now be reconnect
name="P2PCallDeclined"
type="notifytip">
[VOICE_CHANNEL_NAME] has declined your call. You will now be reconnected to Nearby Voice Chat.
+ <tag>voice</tag>
+ <tag>fail</tag>
<unique>
<context>VOICE_CHANNEL_NAME</context>
</unique>
@@ -6192,6 +6547,8 @@ You have been disconnected from [VOICE_CHANNEL_NAME]. You will now be reconnect
name="P2PCallNoAnswer"
type="notifytip">
[VOICE_CHANNEL_NAME] is not available to take your call. You will now be reconnected to Nearby Voice Chat.
+ <tag>fail</tag>
+ <tag>voice</tag>
<unique>
<context>VOICE_CHANNEL_NAME</context>
</unique>
@@ -6202,6 +6559,8 @@ You have been disconnected from [VOICE_CHANNEL_NAME]. You will now be reconnect
name="VoiceChannelJoinFailed"
type="notifytip">
Failed to connect to [VOICE_CHANNEL_NAME], please try again later. You will now be reconnected to Nearby Voice Chat.
+ <tag>fail</tag>
+ <tag>voice</tag>
<unique>
<context>VOICE_CHANNEL_NAME</context>
</unique>
@@ -6214,6 +6573,8 @@ Failed to connect to [VOICE_CHANNEL_NAME], please try again later. You will now
type="notifytip"
unique="true">
We are creating a voice channel for you. This may take up to one minute.
+ <tag>status</tag>
+ <tag>voice</tag>
</notification>
<notification
@@ -6225,6 +6586,8 @@ We are creating a voice channel for you. This may take up to one minute.
unique="true">
One or more of your subscribed Voice Morphs has expired.
[[URL] Click here] to renew your subscription.
+ <tag>fail</tag>
+ <tag>voice</tag>
</notification>
<notification
@@ -6236,6 +6599,8 @@ One or more of your subscribed Voice Morphs has expired.
unique="true">
The active Voice Morph has expired, your normal voice settings have been applied.
[[URL] Click here] to renew your subscription.
+ <tag>fail</tag>
+ <tag>voice</tag>
</notification>
<notification
@@ -6247,6 +6612,8 @@ The active Voice Morph has expired, your normal voice settings have been applied
unique="true">
One or more of your Voice Morphs will expire in less than [INTERVAL] days.
[[URL] Click here] to renew your subscription.
+ <tag>fail</tag>
+ <tag>voice</tag>
</notification>
<notification
@@ -6257,6 +6624,7 @@ One or more of your Voice Morphs will expire in less than [INTERVAL] days.
type="notify"
unique="true">
New Voice Morphs are available!
+ <tag>voice</tag>
</notification>
<notification
@@ -6264,6 +6632,7 @@ New Voice Morphs are available!
name="Cannot enter parcel: not a group member"
type="notifytip">
<tag>fail</tag>
+ <tag>group</tag>
Only members of a certain group can visit this area.
</notification>
@@ -6288,6 +6657,8 @@ Cannot enter parcel, you are not on the access list.
name="VoiceNotAllowed"
type="notifytip">
You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].
+ <tag>fail</tag>
+ <tag>voice</tag>
<unique>
<context>VOICE_CHANNEL_NAME</context>
</unique>
@@ -6298,6 +6669,8 @@ You do not have permission to connect to voice chat for [VOICE_CHANNEL_NAME].
name="VoiceCallGenericError"
type="notifytip">
An error has occurred while trying to connect to voice chat for [VOICE_CHANNEL_NAME]. Please try again later.
+ <tag>fail</tag>
+ <tag>voice</tag>
<unique>
<context>VOICE_CHANNEL_NAME</context>
</unique>
@@ -6309,6 +6682,7 @@ An error has occurred while trying to connect to voice chat for [VOICE_CHANNEL_N
priority="high"
type="notifytip">
The SLurl you clicked on is not supported.
+ <tag>fail</tag>
</notification>
<notification
@@ -6316,7 +6690,7 @@ The SLurl you clicked on is not supported.
name="BlockedSLURL"
priority="high"
type="notifytip">
- <tag>win</tag>
+ <tag>security</tag>
A SLurl was received from an untrusted browser and has been blocked for your security.
</notification>
@@ -6325,6 +6699,7 @@ A SLurl was received from an untrusted browser and has been blocked for your sec
name="ThrottledSLURL"
priority="high"
type="notifytip">
+ <tag>security</tag>
Multiple SLurls were received from an untrusted browser within a short period.
They will be blocked for a few seconds for your security.
</notification>
@@ -6341,6 +6716,7 @@ They will be blocked for a few seconds for your security.
name="ConfirmCloseAll"
type="alertmodal">
Are you sure you want to close all IMs?
+ <tag>confirm</tag>
<usetemplate
name="okcancelignore"
notext="Cancel"
@@ -6358,6 +6734,7 @@ Attachment has been saved.
name="UnableToFindHelpTopic"
type="alertmodal">
Unable to find the help topic for this element.
+ <tag>fail</tag>
</notification>
<notification
@@ -6366,6 +6743,7 @@ Unable to find the help topic for this element.
type="alertmodal">
Server Error: Media update or get failed.
&apos;[ERROR]&apos;
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -6386,6 +6764,7 @@ Your text chat has been muted by moderator.
name="VoiceIsMutedByModerator"
type="alertmodal">
Your voice has been muted by moderator.
+ <tag>voice</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -6396,6 +6775,7 @@ Your voice has been muted by moderator.
name="ConfirmClearTeleportHistory"
type="alertmodal">
Are you sure you want to delete your teleport history?
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
@@ -6408,6 +6788,7 @@ Are you sure you want to delete your teleport history?
type="alert">
Selected button can not be shown right now.
The button will be shown when there is enough space for it.
+ <tag>fail</tag>
</notification>
<notification
@@ -6427,22 +6808,27 @@ Are you sure you want to share the following items:
With the following Residents:
[RESIDENTS]
+ <tag>confirm</tag>
<usetemplate
name="okcancelbuttons"
notext="Cancel"
yestext="Ok"/>
</notification>
+
<notification
icon="notifytip.tga"
name="ItemsShared"
type="notifytip">
Items successfully shared.
</notification>
+
<notification
icon="notifytip.tga"
name="DeedToGroupFail"
type="notifytip">
Deed to group failed.
+ <tag>group</tag>
+ <tag>fail</tag>
</notification>
<notification
@@ -6516,6 +6902,7 @@ Avatar '[NAME]' left appearance mode.
type="alertmodal">
We're having trouble connecting using [PROTOCOL] [HOSTID].
Please check your network and firewall setup.
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -6531,6 +6918,8 @@ We're having trouble connecting to your voice server:
Voice communications will not be available.
Please check your network and firewall setup.
+ <tag>voice</tag>
+ <tag>fail</tag>
<usetemplate
name="okbutton"
yestext="OK"/>
@@ -6565,6 +6954,8 @@ You locally updated a [RESOLUTION] baked texture for '[BODYREGION]' after [TIME]
name="ConfirmLeaveCall"
type="alert">
Are you sure you want to leave this call?
+ <tag>confirm</tag>
+ <tag>voice</tag>
<usetemplate
ignoretext="Confirm before I leave call"
name="okcancelignore"
@@ -6582,6 +6973,9 @@ This will also cause all residents that later join the call to be
muted, even after you have left the call.
Mute everyone?
+ <tag>group</tag>
+ <tag>confirm</tag>
+ <tag>voice</tag>
<usetemplate
ignoretext="Confirm before I mute all participants in a group call"
name="okcancelignore"
@@ -6600,6 +6994,7 @@ Mute everyone?
<notification
name="HintSit"
+
label="Stand"
type="hint"
unique="true">
@@ -6615,14 +7010,6 @@ Mute everyone?
</notification>
<notification
- name="HintAvatarPicker"
- label="Change your Look"
- type="hint"
- unique="true">
- Would you like to try a new look? Click the button below to see more Avatars.
- </notification>
-
- <notification
name="HintSidePanel"
label="Side Panel"
type="hint"
@@ -6678,6 +7065,7 @@ Mute everyone?
type="hint"
unique="true">
Here's your current balance of L$. Click Buy L$ to purchase more Linden Dollars.
+ <tag>funds</tag>
</notification>
<notification
@@ -6701,6 +7089,7 @@ Mute everyone?
name="AuthRequest"
type="browser">
The site at &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos; in realm &apos;[REALM]&apos; requires a user name and password.
+ <tag>confirm</tag>
<form name="form">
<input name="username" type="text" text="User Name"/>
<input name="password" type="password" text="Password "/>
@@ -6714,6 +7103,116 @@ The site at &apos;&lt;nolink&gt;[HOST_NAME]&lt;/nolink&gt;&apos; in realm &apos;
</form>
</notification>
+ <notification
+ name="ModeChange"
+ label=""
+ type="alertmodal"
+ unique="true">
+ Changing modes requires you to quit and restart.
+ <tag>confirm</tag>
+ <usetemplate
+ name="okcancelbuttons"
+ yestext="Quit"
+ notext="Don't Quit"/>
+ </notification>
+
+ <notification
+ name="NoClassifieds"
+ label=""
+ type="alertmodal"
+ unique="true">
+ <tag>fail</tag>
+ <tag>confirm</tag>
+ Creation and editing of Classifieds is only available in Advanced mode. Would you like to quit and change modes? The mode selector can be found on the login screen.
+ <usetemplate
+ name="okcancelbuttons"
+ yestext="Quit"
+ notext="Don't Quit"/>
+ </notification>
+
+ <notification
+ name="NoGroupInfo"
+ label=""
+ type="alertmodal"
+ unique="true">
+ <tag>fail</tag>
+ <tag>confirm</tag>
+ Creation and editing of Groups is only available in Advanced mode. Would you like to quit and change modes? The mode selector can be found on the login screen.
+ <usetemplate
+ name="okcancelbuttons"
+ yestext="Quit"
+ notext="Don't Quit"/>
+ </notification>
+
+ <notification
+ name="NoPicks"
+ label=""
+ type="alertmodal"
+ unique="true">
+ <tag>fail</tag>
+ <tag>confirm</tag>
+ Creation and editing of Picks is only available in Advanced mode. Would you like to quit and change modes? The mode selector can be found on the login screen.
+ <usetemplate
+ name="okcancelbuttons"
+ yestext="Quit"
+ notext="Don't Quit"/>
+ </notification>
+
+ <notification
+ name="NoWorldMap"
+ label=""
+ type="alertmodal"
+ unique="true">
+ <tag>fail</tag>
+ <tag>confirm</tag>
+ Viewing of the world map is only available in Advanced mode. Would you like to quit and change modes? The mode selector can be found on the login screen.
+ <usetemplate
+ name="okcancelbuttons"
+ yestext="Quit"
+ notext="Don't Quit"/>
+ </notification>
+
+ <notification
+ name="NoVoiceCall"
+ label=""
+ type="alertmodal"
+ unique="true">
+ <tag>fail</tag>
+ <tag>confirm</tag>
+ Voice calls are only available in Advanced mode. Would you like to logout and change modes?
+ <usetemplate
+ name="okcancelbuttons"
+ yestext="Quit"
+ notext="Don't Quit"/>
+ </notification>
+
+ <notification
+ name="NoAvatarShare"
+ label=""
+ type="alertmodal"
+ unique="true">
+ <tag>fail</tag>
+ <tag>confirm</tag>
+ Sharing is only available in Advanced mode. Would you like to logout and change modes?
+ <usetemplate
+ name="okcancelbuttons"
+ yestext="Quit"
+ notext="Don't Quit"/>
+ </notification>
+
+ <notification
+ name="NoAvatarPay"
+ label=""
+ type="alertmodal"
+ unique="true">
+ <tag>fail</tag>
+ <tag>confirm</tag>
+ Paying other residents is only available in Advanced mode. Would you like to logout and change modes?
+ <usetemplate
+ name="okcancelbuttons"
+ yestext="Quit"
+ notext="Don't Quit"/>
+ </notification>
<global name="UnsupportedCPU">
- Your CPU speed does not meet the minimum requirements.
diff --git a/indra/newview/skins/default/xui/en/panel_login.xml b/indra/newview/skins/default/xui/en/panel_login.xml
index 806182bcb4..4c2faddfe4 100644
--- a/indra/newview/skins/default/xui/en/panel_login.xml
+++ b/indra/newview/skins/default/xui/en/panel_login.xml
@@ -47,8 +47,8 @@ auto_resize="false"
follows="left|bottom"
name="login"
layout="topleft"
-width="695"
-min_width="695"
+width="705"
+min_width="705"
user_resize="false"
height="80">
<text
@@ -67,8 +67,7 @@ follows="left|bottom"
height="22"
left_delta="0"
max_chars="128"
-prevalidate_callback="ascii"
-select_on_focus="true"
+combo_editor.prevalidate_callback="ascii"
tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine"
top_pad="0"
name="username_combo"
@@ -118,13 +117,41 @@ label="Remember password"
name="connect_btn"
top="35"
width="90" />
+ <text
+ follows="left|bottom"
+ font="SansSerifSmall"
+ height="15"
+ left_pad="10"
+ name="mode_selection_text"
+ top="20"
+ width="130">
+ Mode:
+ </text>
+<combo_box
+ follows="left|bottom"
+ height="23"
+ max_chars="128"
+ tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features."
+ top_pad="0"
+ control_name="SessionSettingsFile"
+ name="mode_combo"
+ width="110">
+<combo_box.item
+ label="Basic"
+ name="Basic"
+ value="settings_minimal.xml" />
+<combo_box.item
+ label="Advanced"
+ name="Advanced"
+ value="" />
+</combo_box>
<text
follows="left|bottom"
font="SansSerifSmall"
height="15"
- left_pad="18"
+ left_pad="8"
name="start_location_text"
-top="20"
+ top="20"
width="130">
Start at:
</text>
@@ -136,7 +163,7 @@ control_name="NextLoginLocation"
max_chars="128"
top_pad="0"
name="start_location_combo"
- width="170">
+ width="165">
<combo_box.item
label="My last location"
name="MyLastLocation"
diff --git a/indra/newview/skins/minimal/colors.xml b/indra/newview/skins/minimal/colors.xml
new file mode 100644
index 0000000000..097a298ce5
--- /dev/null
+++ b/indra/newview/skins/minimal/colors.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<colors>
+ <color
+ name="MenuBarBgColor"
+ value="0 0 0 0" />
+</colors>
diff --git a/indra/newview/skins/minimal/textures/arrow_keys.png b/indra/newview/skins/minimal/textures/arrow_keys.png
new file mode 100644
index 0000000000..f19af59251
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/arrow_keys.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/bottomtray/button_separator.png b/indra/newview/skins/minimal/textures/bottomtray/button_separator.png
new file mode 100644
index 0000000000..71ed25f931
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/bottomtray/button_separator.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/bottomtray/close_off.png b/indra/newview/skins/minimal/textures/bottomtray/close_off.png
new file mode 100644
index 0000000000..241a24bde9
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/bottomtray/close_off.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/bottomtray/close_over.png b/indra/newview/skins/minimal/textures/bottomtray/close_over.png
new file mode 100644
index 0000000000..4630cb6dd6
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/bottomtray/close_over.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/bottomtray/close_press.png b/indra/newview/skins/minimal/textures/bottomtray/close_press.png
new file mode 100644
index 0000000000..3ed9c99a26
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/bottomtray/close_press.png
Binary files differ
diff --git a/indra/newview/skins/minimal/textures/textures.xml b/indra/newview/skins/minimal/textures/textures.xml
new file mode 100644
index 0000000000..3e2f5cd397
--- /dev/null
+++ b/indra/newview/skins/minimal/textures/textures.xml
@@ -0,0 +1,8 @@
+
+<textures version="101">
+ <texture name="Button_Separator" file_name="bottomtray/button_separator.png" preload="true" />
+ <texture name="arrow_keys.png"/>
+ <texture name="bottomtray_close_off" file_name="bottomtray/close_off.png" preload="true" />
+ <texture name="bottomtray_close_over" file_name="bottomtray/close_over.png" preload="true" />
+ <texture name="bottomtray_close_press" file_name="bottomtray/close_press.png" preload="true" />
+</textures>
diff --git a/indra/newview/skins/minimal/xui/de/floater_camera.xml b/indra/newview/skins/minimal/xui/de/floater_camera.xml
new file mode 100644
index 0000000000..d49c207f98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/floater_camera.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="camera_floater">
+ <floater.string name="rotate_tooltip">
+ Kamera um Fokus drehen
+ </floater.string>
+ <floater.string name="zoom_tooltip">
+ Kamera auf Fokus zoomen
+ </floater.string>
+ <floater.string name="move_tooltip">
+ Kamera nach oben, unten, links und rechts bewegen
+ </floater.string>
+ <floater.string name="camera_modes_title">
+ Kameramodi
+ </floater.string>
+ <floater.string name="pan_mode_title">
+ Kreisen - Zoomen - Schwenken
+ </floater.string>
+ <floater.string name="presets_mode_title">
+ Ansichten
+ </floater.string>
+ <floater.string name="free_mode_title">
+ Objekt ansehen
+ </floater.string>
+ <panel name="controls">
+ <panel name="preset_views_list">
+ <panel_camera_item name="front_view">
+ <panel_camera_item.text name="front_view_text">
+ Vorderansicht
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="group_view">
+ <panel_camera_item.text name="side_view_text">
+ Seitenansicht
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="rear_view">
+ <panel_camera_item.text name="rear_view_text">
+ Hinteransicht
+ </panel_camera_item.text>
+ </panel_camera_item>
+ </panel>
+ <panel name="camera_modes_list">
+ <panel_camera_item name="object_view">
+ <panel_camera_item.text name="object_view_text">
+ Objektansicht
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="mouselook_view">
+ <panel_camera_item.text name="mouselook_view_text">
+ Mouselook
+ </panel_camera_item.text>
+ </panel_camera_item>
+ </panel>
+ <panel name="zoom" tool_tip="Kamera auf Fokus zoomen">
+ <joystick_rotate name="cam_rotate_stick" tool_tip="Kamera um Fokus kreisen"/>
+ <slider_bar name="zoom_slider" tool_tip="Kamera auf Fokus zoomen"/>
+ <joystick_track name="cam_track_stick" tool_tip="Kamera nach oben, unten, links und rechts bewegen"/>
+ </panel>
+ </panel>
+ <panel name="buttons">
+ <button label="" name="presets_btn" tool_tip="Ansichten"/>
+ <button label="" name="pan_btn" tool_tip="Kreisen - Zoomen - Schwenken"/>
+ <button label="" name="avatarview_btn" tool_tip="Kameramodi"/>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/de/floater_help_browser.xml b/indra/newview/skins/minimal/xui/de/floater_help_browser.xml
new file mode 100644
index 0000000000..459dfb66c0
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/floater_help_browser.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_help_browser" title="ANWEISUNGEN">
+ <floater.string name="loading_text">
+ Wird geladen...
+ </floater.string>
+ <layout_stack name="stack1">
+ <layout_panel name="external_controls"/>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/de/floater_nearby_chat.xml b/indra/newview/skins/minimal/xui/de/floater_nearby_chat.xml
new file mode 100644
index 0000000000..bbb4114200
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/floater_nearby_chat.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="nearby_chat" title="CHAT IN DER NÄHE">
+ <check_box label="Chat übersetzen (Service von Google)" name="translate_chat_checkbox"/>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/de/inspect_avatar.xml b/indra/newview/skins/minimal/xui/de/inspect_avatar.xml
new file mode 100644
index 0000000000..4b8fd8a0ad
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/inspect_avatar.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater name="inspect_avatar">
+ <string name="Subtitle">
+ [AGE]
+ </string>
+ <string name="Details">
+ [SL_PROFILE]
+ </string>
+ <text name="user_subtitle" value="11 Monate und 3 Tage alt"/>
+ <text name="user_details">
+ Dies ist meine Second Life-Beschreibung und ich finde sie wirklich gut! Meine Beschreibung ist deshalb so lang, weil ich gerne rede.
+ </text>
+ <slider name="volume_slider" tool_tip="Lautstärke" value="0.5"/>
+ <button label="Freund hinzufügen" name="add_friend_btn" width="110"/>
+ <button label="IM" name="im_btn"/>
+ <button label="Profil" left_delta="120" name="view_profile_btn" width="44"/>
+ <panel name="moderator_panel">
+ <button label="Voice deaktivieren" name="disable_voice"/>
+ <button label="Voice aktivieren" name="enable_voice"/>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/de/inspect_object.xml b/indra/newview/skins/minimal/xui/de/inspect_object.xml
new file mode 100644
index 0000000000..72b8235828
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/inspect_object.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater name="inspect_object">
+ <string name="Creator">
+ Von [CREATOR]
+ </string>
+ <string name="CreatorAndOwner">
+ Von [CREATOR]
+Besitzer [OWNER]
+ </string>
+ <string name="Price">
+ [AMOUNT] L$
+ </string>
+ <string name="PriceFree">
+ Kostenlos!
+ </string>
+ <string name="Touch">
+ Berühren
+ </string>
+ <string name="Sit">
+ Sitzen
+ </string>
+ <text name="object_name" value="Test für ein Objektname der sehr lange ist und über zwei Zeilen geht."/>
+ <text name="object_creator">
+ von secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
+Besitzer secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
+ </text>
+ <text name="price_text">
+ 30.000 L$
+ </text>
+ <text name="object_description">
+ Dies ist eine wirklich lange Beschreibung für ein Objekt, mindestens 80 Zeichen lang oder jetzt schon mindestens 120 Zeichen lang und länger als der englische Originaltext. Niemand weiß es genau.
+ </text>
+ <text name="object_media_url">
+ http://www.superdupertest.com
+ </text>
+ <button label="Kaufen" name="buy_btn"/>
+ <button label="Bezahlen" name="pay_btn"/>
+ <button label="Kopie nehmen" name="take_free_copy_btn" width="100"/>
+ <button label="Berühren" name="touch_btn"/>
+ <button label="Sitzen" name="sit_btn"/>
+ <button label="Öffnen" name="open_btn"/>
+ <icon name="secure_browsing" tool_tip="Sicheres Browsen"/>
+ <button label="Mehr" name="more_info_btn"/>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/de/menu_add_wearable_gear.xml b/indra/newview/skins/minimal/xui/de/menu_add_wearable_gear.xml
new file mode 100644
index 0000000000..f3775a05ec
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_add_wearable_gear.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Add Wearable Gear Menu">
+ <menu_item_check label="Nach aktuellesten Objekten sortieren" name="sort_by_most_recent"/>
+ <menu_item_check label="Nach Name sortieren" name="sort_by_name"/>
+ <menu_item_check label="Nach Typ sortieren" name="sort_by_type"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_attachment_other.xml b/indra/newview/skins/minimal/xui/de/menu_attachment_other.xml
new file mode 100644
index 0000000000..237c92f7d2
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_attachment_other.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: See also menu_avatar_other.xml -->
+<context_menu name="Avatar Pie">
+ <menu_item_call label="Profil anzeigen" name="Profile..."/>
+ <menu_item_call label="Freund hinzufügen" name="Add Friend"/>
+ <menu_item_call label="IM" name="Send IM..."/>
+ <menu_item_call label="Anrufen" name="Call"/>
+ <menu_item_call label="In Gruppe einladen" name="Invite..."/>
+ <menu_item_call label="Ignorieren" name="Avatar Mute"/>
+ <menu_item_call label="Melden" name="abuse"/>
+ <menu_item_call label="Einfrieren" name="Freeze..."/>
+ <menu_item_call label="Hinauswerfen" name="Eject..."/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
+ <menu_item_call label="Hineinzoomen" name="Zoom In"/>
+ <menu_item_call label="Bezahlen" name="Pay..."/>
+ <menu_item_call label="Objektprofil" name="Object Inspect"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_attachment_self.xml b/indra/newview/skins/minimal/xui/de/menu_attachment_self.xml
new file mode 100644
index 0000000000..644fc68ba4
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_attachment_self.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Attachment Pie">
+ <menu_item_call label="Berühren" name="Attachment Object Touch"/>
+ <menu_item_call label="Bearbeiten" name="Edit..."/>
+ <menu_item_call label="Abnehmen" name="Detach"/>
+ <menu_item_call label="Hinsetzen" name="Sit Down Here"/>
+ <menu_item_call label="Aufstehen" name="Stand Up"/>
+ <menu_item_call label="Outfit ändern" name="Change Outfit"/>
+ <menu_item_call label="Mein Outfit bearbeiten" name="Edit Outfit"/>
+ <menu_item_call label="Meine Form bearbeiten" name="Edit My Shape"/>
+ <menu_item_call label="Meine Freunde" name="Friends..."/>
+ <menu_item_call label="Meine Gruppen" name="Groups..."/>
+ <menu_item_call label="Mein Profil" name="Profile..."/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
+ <menu_item_call label="Fallen lassen" name="Drop"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_avatar_icon.xml b/indra/newview/skins/minimal/xui/de/menu_avatar_icon.xml
new file mode 100644
index 0000000000..c036cf5515
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_avatar_icon.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Avatar Icon Menu">
+ <menu_item_call label="Profil anzeigen" name="Show Profile"/>
+ <menu_item_call label="IM senden..." name="Send IM"/>
+ <menu_item_call label="Freund hinzufügen..." name="Add Friend"/>
+ <menu_item_call label="Freund entfernen..." name="Remove Friend"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_avatar_other.xml b/indra/newview/skins/minimal/xui/de/menu_avatar_other.xml
new file mode 100644
index 0000000000..8aee0be3d2
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_avatar_other.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: See also menu_attachment_other.xml -->
+<context_menu name="Avatar Pie">
+ <menu_item_call label="Profil anzeigen" name="Profile..."/>
+ <menu_item_call label="Freund hinzufügen" name="Add Friend"/>
+ <menu_item_call label="IM" name="Send IM..."/>
+ <menu_item_call label="Anrufen" name="Call"/>
+ <menu_item_call label="In Gruppe einladen" name="Invite..."/>
+ <menu_item_call label="Ignorieren" name="Avatar Mute"/>
+ <menu_item_call label="Melden" name="abuse"/>
+ <menu_item_call label="Einfrieren" name="Freeze..."/>
+ <menu_item_call label="Hinauswerfen" name="Eject..."/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
+ <menu_item_call label="Hineinzoomen" name="Zoom In"/>
+ <menu_item_call label="Bezahlen" name="Pay..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_avatar_self.xml b/indra/newview/skins/minimal/xui/de/menu_avatar_self.xml
new file mode 100644
index 0000000000..582c76ac94
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_avatar_self.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Self Pie">
+ <menu_item_call label="Hinsetzen" name="Sit Down Here"/>
+ <menu_item_call label="Aufstehen" name="Stand Up"/>
+ <context_menu label="Ausziehen" name="Take Off &gt;">
+ <context_menu label="Kleidung" name="Clothes &gt;">
+ <menu_item_call label="Hemd" name="Shirt"/>
+ <menu_item_call label="Hose" name="Pants"/>
+ <menu_item_call label="Rock" name="Skirt"/>
+ <menu_item_call label="Schuhe" name="Shoes"/>
+ <menu_item_call label="Strümpfe" name="Socks"/>
+ <menu_item_call label="Jacke" name="Jacket"/>
+ <menu_item_call label="Handschuhe" name="Gloves"/>
+ <menu_item_call label="Unterhemd" name="Self Undershirt"/>
+ <menu_item_call label="Unterhose" name="Self Underpants"/>
+ <menu_item_call label="Tätowierung" name="Self Tattoo"/>
+ <menu_item_call label="Alpha" name="Self Alpha"/>
+ <menu_item_call label="Alle Kleider" name="All Clothes"/>
+ </context_menu>
+ <context_menu label="HUD" name="Object Detach HUD"/>
+ <context_menu label="Abnehmen" name="Object Detach"/>
+ <menu_item_call label="Alles abnehmen" name="Detach All"/>
+ </context_menu>
+ <menu_item_call label="Outfit ändern" name="Chenge Outfit"/>
+ <menu_item_call label="Mein Outfit bearbeiten" name="Edit Outfit"/>
+ <menu_item_call label="Meine Form bearbeiten" name="Edit My Shape"/>
+ <menu_item_call label="Meine Freunde" name="Friends..."/>
+ <menu_item_call label="Meine Gruppen" name="Groups..."/>
+ <menu_item_call label="Mein Profil" name="Profile..."/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_bottomtray.xml b/indra/newview/skins/minimal/xui/de/menu_bottomtray.xml
new file mode 100644
index 0000000000..6c4308286a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_bottomtray.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="hide_camera_move_controls_menu">
+ <menu_item_check label="Schaltfläche Gesten" name="ShowGestureButton"/>
+ <menu_item_check label="Schaltfläche Bewegungssteuerung" name="ShowMoveButton"/>
+ <menu_item_check label="Schaltfläche Ansicht" name="ShowCameraButton"/>
+ <menu_item_check label="Schaltfläche Foto" name="ShowSnapshotButton"/>
+ <menu_item_check label="Schaltfläche „Seitenleiste“" name="ShowSidebarButton"/>
+ <menu_item_check label="Schaltfläche „Bauen“" name="ShowBuildButton"/>
+ <menu_item_check label="Schaltfläche „Suchen“" name="ShowSearchButton"/>
+ <menu_item_check label="Schaltfläche „Karte“" name="ShowWorldMapButton"/>
+ <menu_item_check label="Schaltfläche „Minikarte“" name="ShowMiniMapButton"/>
+ <menu_item_call label="Ausschneiden" name="NearbyChatBar_Cut"/>
+ <menu_item_call label="Kopieren" name="NearbyChatBar_Copy"/>
+ <menu_item_call label="Einfügen" name="NearbyChatBar_Paste"/>
+ <menu_item_call label="Löschen" name="NearbyChatBar_Delete"/>
+ <menu_item_call label="Alle auswählen" name="NearbyChatBar_Select_All"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_cof_attachment.xml b/indra/newview/skins/minimal/xui/de/menu_cof_attachment.xml
new file mode 100644
index 0000000000..05d3dfca9d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_cof_attachment.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Attachment">
+ <menu_item_call label="Abnehmen" name="detach"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_cof_body_part.xml b/indra/newview/skins/minimal/xui/de/menu_cof_body_part.xml
new file mode 100644
index 0000000000..07960a525c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_cof_body_part.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Body">
+ <menu_item_call label="Ersetzen" name="replace"/>
+ <menu_item_call label="Bearbeiten" name="edit"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_cof_clothing.xml b/indra/newview/skins/minimal/xui/de/menu_cof_clothing.xml
new file mode 100644
index 0000000000..7fced273a7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_cof_clothing.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Clothing">
+ <menu_item_call label="Ausziehen" name="take_off"/>
+ <menu_item_call label="Ersetzen" name="replace"/>
+ <menu_item_call label="Eine Kategorie nach oben" name="move_up"/>
+ <menu_item_call label="Eine Kategorie nach unten" name="move_down"/>
+ <menu_item_call label="Bearbeiten" name="edit"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_cof_gear.xml b/indra/newview/skins/minimal/xui/de/menu_cof_gear.xml
new file mode 100644
index 0000000000..54b218d22f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_cof_gear.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear COF">
+ <menu label="Neue Kleider" name="COF.Gear.New_Clothes"/>
+ <menu label="Neue Körperteile" name="COF.Geear.New_Body_Parts"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_edit.xml b/indra/newview/skins/minimal/xui/de/menu_edit.xml
new file mode 100644
index 0000000000..37f68d68d5
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="Bearbeiten" name="Edit">
+ <menu_item_call label="Rückgängig" name="Undo"/>
+ <menu_item_call label="Wiederherstellen" name="Redo"/>
+ <menu_item_call label="Ausschneiden" name="Cut"/>
+ <menu_item_call label="Kopieren" name="Copy"/>
+ <menu_item_call label="Einfügen" name="Paste"/>
+ <menu_item_call label="Löschen" name="Delete"/>
+ <menu_item_call label="Duplizieren" name="Duplicate"/>
+ <menu_item_call label="Alle auswählen" name="Select All"/>
+ <menu_item_call label="Auswahl aufheben" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_favorites.xml b/indra/newview/skins/minimal/xui/de/menu_favorites.xml
new file mode 100644
index 0000000000..0d0491d2eb
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_favorites.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Teleportieren" name="Teleport To Landmark"/>
+ <menu_item_call label="Landmarken anzeigen/bearbeiten" name="Landmark Open"/>
+ <menu_item_call label="SLurl kopieren" name="Copy slurl"/>
+ <menu_item_call label="Auf Karte zeigen" name="Show On Map"/>
+ <menu_item_call label="Kopieren" name="Landmark Copy"/>
+ <menu_item_call label="Einfügen" name="Landmark Paste"/>
+ <menu_item_call label="Löschen" name="Delete"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_gesture_gear.xml b/indra/newview/skins/minimal/xui/de/menu_gesture_gear.xml
new file mode 100644
index 0000000000..953c0eeed5
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_gesture_gear.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_gesture_gear">
+ <menu_item_call label="Zu Favoriten hinzufügen/daraus entfernen" name="activate"/>
+ <menu_item_call label="Kopieren" name="copy_gesture"/>
+ <menu_item_call label="Einfügen" name="paste"/>
+ <menu_item_call label="UUID kopieren" name="copy_uuid"/>
+ <menu_item_call label="Aktuelles Outfit speichern" name="save_to_outfit"/>
+ <menu_item_call label="Bearbeiten" name="edit_gesture"/>
+ <menu_item_call label="Untersuchen" name="inspect"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_group_plus.xml b/indra/newview/skins/minimal/xui/de/menu_group_plus.xml
new file mode 100644
index 0000000000..583ee793be
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_group_plus.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_call label="Werden Sie Mitglied..." name="item_join"/>
+ <menu_item_call label="Neue Gruppe..." name="item_new"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_hide_navbar.xml b/indra/newview/skins/minimal/xui/de/menu_hide_navbar.xml
new file mode 100644
index 0000000000..9acf96dc6d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_hide_navbar.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="hide_navbar_menu">
+ <menu_item_check label="Navigationsleiste anzeigen" name="ShowNavbarNavigationPanel"/>
+ <menu_item_check label="Favoritenleiste anzeigen" name="ShowNavbarFavoritesPanel"/>
+ <menu_item_check label="Mini-Standortleiste anzeigen" name="ShowMiniLocationPanel"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_im_well_button.xml b/indra/newview/skins/minimal/xui/de/menu_im_well_button.xml
new file mode 100644
index 0000000000..f464b71f4a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_im_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="IM Well Button Context Menu">
+ <menu_item_call label="Alle schließen" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_imchiclet_adhoc.xml b/indra/newview/skins/minimal/xui/de/menu_imchiclet_adhoc.xml
new file mode 100644
index 0000000000..11f93f47b4
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_imchiclet_adhoc.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet AdHoc Menu">
+ <menu_item_call label="Sitzung beenden" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_imchiclet_group.xml b/indra/newview/skins/minimal/xui/de/menu_imchiclet_group.xml
new file mode 100644
index 0000000000..81ef3b6569
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_imchiclet_group.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet Group Menu">
+ <menu_item_call label="Gruppeninfo" name="Show Profile"/>
+ <menu_item_call label="Sitzung anzeigen" name="Chat"/>
+ <menu_item_call label="Sitzung beenden" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_imchiclet_p2p.xml b/indra/newview/skins/minimal/xui/de/menu_imchiclet_p2p.xml
new file mode 100644
index 0000000000..d123238246
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_imchiclet_p2p.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet P2P Menu">
+ <menu_item_call label="Profil anzeigen" name="Show Profile"/>
+ <menu_item_call label="Freund hinzufügen" name="Add Friend"/>
+ <menu_item_call label="Sitzung anzeigen" name="Send IM"/>
+ <menu_item_call label="Sitzung beenden" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_inspect_avatar_gear.xml b/indra/newview/skins/minimal/xui/de/menu_inspect_avatar_gear.xml
new file mode 100644
index 0000000000..fbc119c483
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_inspect_avatar_gear.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<toggleable_menu name="Gear Menu">
+ <menu_item_call label="Profil anzeigen" name="view_profile"/>
+ <menu_item_call label="Freund hinzufügen" name="add_friend"/>
+ <menu_item_call label="IM" name="im"/>
+ <menu_item_call label="Teleportieren" name="teleport"/>
+ <menu_item_call label="Ignorieren" name="block"/>
+ <menu_item_call label="Freischalten" name="unblock"/>
+ <menu_item_call label="Melden" name="report"/>
+ <menu_item_call label="Einfrieren" name="freeze"/>
+ <menu_item_call label="Hinauswerfen" name="eject"/>
+ <menu_item_call label="Hinauswerfen" name="kick"/>
+ <menu_item_call label="CSR" name="csr"/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="debug"/>
+ <menu_item_call label="Auf Karte anzeigen" name="find_on_map"/>
+ <menu_item_call label="Hineinzoomen" name="zoom_in"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_inspect_object_gear.xml b/indra/newview/skins/minimal/xui/de/menu_inspect_object_gear.xml
new file mode 100644
index 0000000000..7c47913e30
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_inspect_object_gear.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu name="Gear Menu">
+ <menu_item_call label="Berühren" name="touch"/>
+ <menu_item_call label="Sitzen" name="sit"/>
+ <menu_item_call label="Bezahlen" name="pay"/>
+ <menu_item_call label="Kaufen" name="buy"/>
+ <menu_item_call label="Nehmen" name="take"/>
+ <menu_item_call label="Kopie nehmen" name="take_copy"/>
+ <menu_item_call label="Öffnen" name="open"/>
+ <menu_item_call label="Bearbeiten" name="edit"/>
+ <menu_item_call label="Anziehen" name="wear"/>
+ <menu_item_call label="Hinzufügen" name="add"/>
+ <menu_item_call label="Melden" name="report"/>
+ <menu_item_call label="Ignorieren" name="block"/>
+ <menu_item_call label="Hineinzoomen" name="zoom_in"/>
+ <menu_item_call label="Entfernen" name="remove"/>
+ <menu_item_call label="Weitere Infos" name="more_info"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml
new file mode 100644
index 0000000000..851a96cc09
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_inspect_self_gear.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu name="Gear Menu">
+ <menu_item_call label="Hinsetzen" name="sit_down_here"/>
+ <menu_item_call label="Aufstehen" name="stand_up"/>
+ <menu_item_call label="Outfit ändern" name="change_outfit"/>
+ <menu_item_call label="Mein Profil" name="my_profile"/>
+ <menu_item_call label="Meine Freunde" name="my_friends"/>
+ <menu_item_call label="Meine Gruppen" name="my_groups"/>
+ <menu_item_call label="Fehler in Texturen beseitigen" name="Debug..."/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_inv_offer_chiclet.xml b/indra/newview/skins/minimal/xui/de/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..71cff7136b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="Schließen" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_inventory.xml b/indra/newview/skins/minimal/xui/de/menu_inventory.xml
new file mode 100644
index 0000000000..43722e0dcf
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_inventory.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Teilen" name="Share"/>
+ <menu_item_call label="Kaufen" name="Task Buy"/>
+ <menu_item_call label="Öffnen" name="Task Open"/>
+ <menu_item_call label="Abspielen" name="Task Play"/>
+ <menu_item_call label="Eigenschaften" name="Task Properties"/>
+ <menu_item_call label="Umbenennen" name="Task Rename"/>
+ <menu_item_call label="Löschen" name="Task Remove"/>
+ <menu_item_call label="Papierkorb ausleeren" name="Empty Trash"/>
+ <menu_item_call label="Fundstücke ausleeren" name="Empty Lost And Found"/>
+ <menu_item_call label="Neuer Ordner" name="New Folder"/>
+ <menu_item_call label="Neues Skript" name="New Script"/>
+ <menu_item_call label="Neue Notizkarte" name="New Note"/>
+ <menu_item_call label="Neue Geste" name="New Gesture"/>
+ <menu label="Neue Kleider" name="New Clothes">
+ <menu_item_call label="Neues Hemd" name="New Shirt"/>
+ <menu_item_call label="Neue Hose" name="New Pants"/>
+ <menu_item_call label="Neue Schuhe" name="New Shoes"/>
+ <menu_item_call label="Neue Socken" name="New Socks"/>
+ <menu_item_call label="Neue Jacke" name="New Jacket"/>
+ <menu_item_call label="Neuer Rock" name="New Skirt"/>
+ <menu_item_call label="Neue Handschuhe" name="New Gloves"/>
+ <menu_item_call label="Neues Unterhemd" name="New Undershirt"/>
+ <menu_item_call label="Neue Unterhose" name="New Underpants"/>
+ <menu_item_call label="Neue Alpha-Maske" name="New Alpha Mask"/>
+ <menu_item_call label="Neue Tätowierung" name="New Tattoo"/>
+ </menu>
+ <menu label="Neue Körperteile" name="New Body Parts">
+ <menu_item_call label="Neue Form/Gestalt" name="New Shape"/>
+ <menu_item_call label="Neue Haut" name="New Skin"/>
+ <menu_item_call label="Neues Haar" name="New Hair"/>
+ <menu_item_call label="Neue Augen" name="New Eyes"/>
+ </menu>
+ <menu label="Typ ändern" name="Change Type">
+ <menu_item_call label="Standard" name="Default"/>
+ <menu_item_call label="Handschuhe" name="Gloves"/>
+ <menu_item_call label="Jacke" name="Jacket"/>
+ <menu_item_call label="Hose" name="Pants"/>
+ <menu_item_call label="Form" name="Shape"/>
+ <menu_item_call label="Schuhe" name="Shoes"/>
+ <menu_item_call label="Hemd" name="Shirt"/>
+ <menu_item_call label="Rock" name="Skirt"/>
+ <menu_item_call label="Unterhose" name="Underpants"/>
+ <menu_item_call label="Unterhemd" name="Undershirt"/>
+ </menu>
+ <menu_item_call label="Teleportieren" name="Landmark Open"/>
+ <menu_item_call label="Öffnen" name="Animation Open"/>
+ <menu_item_call label="Öffnen" name="Sound Open"/>
+ <menu_item_call label="Aktuelles Outfit ersetzen" name="Replace Outfit"/>
+ <menu_item_call label="Zum aktuellen Outfit hinzufügen" name="Add To Outfit"/>
+ <menu_item_call label="Vom aktuellen Outfit entfernen" name="Remove From Outfit"/>
+ <menu_item_call label="Original suchen" name="Find Original"/>
+ <menu_item_call label="Objekt löschen" name="Purge Item"/>
+ <menu_item_call label="Objekt wiederherstellen" name="Restore Item"/>
+ <menu_item_call label="Öffnen" name="Open"/>
+ <menu_item_call label="Original öffnen" name="Open Original"/>
+ <menu_item_call label="Eigenschaften" name="Properties"/>
+ <menu_item_call label="Umbenennen" name="Rename"/>
+ <menu_item_call label="Asset-UUID kopieren" name="Copy Asset UUID"/>
+ <menu_item_call label="Kopieren" name="Copy"/>
+ <menu_item_call label="Einfügen" name="Paste"/>
+ <menu_item_call label="Als Link einfügen" name="Paste As Link"/>
+ <menu_item_call label="Löschen" name="Remove Link"/>
+ <menu_item_call label="Löschen" name="Delete"/>
+ <menu_item_call label="Systemordner löschen" name="Delete System Folder"/>
+ <menu_item_call label="Konferenz-Chat starten" name="Conference Chat Folder"/>
+ <menu_item_call label="Wiedergeben/Abspielen" name="Sound Play"/>
+ <menu_item_call label="Landmarken-Info" name="About Landmark"/>
+ <menu_item_call label="Inworld abspielen" name="Animation Play"/>
+ <menu_item_call label="Lokal abspielen" name="Animation Audition"/>
+ <menu_item_call label="Instant Message senden" name="Send Instant Message"/>
+ <menu_item_call label="Teleport anbieten..." name="Offer Teleport..."/>
+ <menu_item_call label="Konferenz-Chat starten" name="Conference Chat"/>
+ <menu_item_call label="Aktivieren" name="Activate"/>
+ <menu_item_call label="Deaktivieren" name="Deactivate"/>
+ <menu_item_call label="Speichern unter" name="Save As"/>
+ <menu_item_call label="Von Körper abnehmen" name="Detach From Yourself"/>
+ <menu_item_call label="Anziehen" name="Wearable And Object Wear"/>
+ <menu label="Anhängen an" name="Attach To"/>
+ <menu label="An HUD hängen" name="Attach To HUD"/>
+ <menu_item_call label="Bearbeiten" name="Wearable Edit"/>
+ <menu_item_call label="Hinzufügen" name="Wearable Add"/>
+ <menu_item_call label="Ausziehen" name="Take Off"/>
+ <menu_item_call label="--keine Optionen--" name="--no options--"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_inventory_add.xml b/indra/newview/skins/minimal/xui/de/menu_inventory_add.xml
new file mode 100644
index 0000000000..dccee6712d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_inventory_add.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_inventory_add">
+ <menu label="Hochladen" name="upload">
+ <menu_item_call label="Bild ([COST] L$)..." name="Upload Image"/>
+ <menu_item_call label="Sound ([COST] L$)..." name="Upload Sound"/>
+ <menu_item_call label="Animation ([COST] L$)..." name="Upload Animation"/>
+ <menu_item_call label="Mehrfach-Upload ([COST] L$ pro Datei)..." name="Bulk Upload"/>
+ <menu_item_call label="Hochlade-Berechtigungen (Standard) festlegen" name="perm prefs"/>
+ </menu>
+ <menu_item_call label="Neuer Ordner" name="New Folder"/>
+ <menu_item_call label="Neues Skript" name="New Script"/>
+ <menu_item_call label="Neue Notizkarte" name="New Note"/>
+ <menu_item_call label="Neue Geste" name="New Gesture"/>
+ <menu label="Neue Kleider" name="New Clothes">
+ <menu_item_call label="Neues Hemd" name="New Shirt"/>
+ <menu_item_call label="Neue Hose" name="New Pants"/>
+ <menu_item_call label="Neue Schuhe" name="New Shoes"/>
+ <menu_item_call label="Neue Socken" name="New Socks"/>
+ <menu_item_call label="Neue Jacke" name="New Jacket"/>
+ <menu_item_call label="Neuer Rock" name="New Skirt"/>
+ <menu_item_call label="Neue Handschuhe" name="New Gloves"/>
+ <menu_item_call label="Neues Unterhemd" name="New Undershirt"/>
+ <menu_item_call label="Neue Unterhose" name="New Underpants"/>
+ <menu_item_call label="Neues Alpha" name="New Alpha"/>
+ <menu_item_call label="Neue Tätowierung" name="New Tattoo"/>
+ </menu>
+ <menu label="Neue Körperteile" name="New Body Parts">
+ <menu_item_call label="Neue Form/Gestalt" name="New Shape"/>
+ <menu_item_call label="Neue Haut" name="New Skin"/>
+ <menu_item_call label="Neues Haar" name="New Hair"/>
+ <menu_item_call label="Neue Augen" name="New Eyes"/>
+ </menu>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_inventory_gear_default.xml b/indra/newview/skins/minimal/xui/de/menu_inventory_gear_default.xml
new file mode 100644
index 0000000000..df86a5cf71
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_inventory_gear_default.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="menu_gear_default">
+ <menu_item_call label="Neues Inventar-Fenster" name="new_window"/>
+ <menu_item_check label="Nach Name sortieren" name="sort_by_name"/>
+ <menu_item_check label="Nach aktuellesten Objekten sortieren" name="sort_by_recent"/>
+ <menu_item_check label="Systemordner nach oben" name="sort_system_folders_to_top"/>
+ <menu_item_call label="Filter anzeigen" name="show_filters"/>
+ <menu_item_call label="Filter zurücksetzen" name="reset_filters"/>
+ <menu_item_call label="Alle Ordner schließen" name="close_folders"/>
+ <menu_item_call label="Fundbüro ausleeren" name="empty_lostnfound"/>
+ <menu_item_call label="Textur speichern als" name="Save Texture As"/>
+ <menu_item_call label="Teilen" name="Share"/>
+ <menu_item_call label="Original suchen" name="Find Original"/>
+ <menu_item_call label="Alle Links suchen" name="Find All Links"/>
+ <menu_item_call label="Papierkorb ausleeren" name="empty_trash"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_land.xml b/indra/newview/skins/minimal/xui/de/menu_land.xml
new file mode 100644
index 0000000000..de679da3d8
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_land.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Land Pie">
+ <menu_item_call label="Land-Info" name="Place Information..."/>
+ <menu_item_call label="Hier sitzen" name="Sit Here"/>
+ <menu_item_call label="Dieses Land kaufen" name="Land Buy"/>
+ <menu_item_call label="Pass kaufen" name="Land Buy Pass"/>
+ <menu_item_call label="Bauen" name="Create"/>
+ <menu_item_call label="Land bearbeiten" name="Edit Terrain"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_landmark.xml b/indra/newview/skins/minimal/xui/de/menu_landmark.xml
new file mode 100644
index 0000000000..2aff0eec95
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_landmark.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="landmark_overflow_menu">
+ <menu_item_call label="SLurl kopieren" name="copy"/>
+ <menu_item_call label="Löschen" name="delete"/>
+ <menu_item_call label="Auswahl erstellen" name="pick"/>
+ <menu_item_call label="Zu Favoritenleiste hinzufügen" name="add_to_favbar"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_login.xml b/indra/newview/skins/minimal/xui/de/menu_login.xml
new file mode 100644
index 0000000000..a373e15338
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_login.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu_bar name="Login Menu">
+ <menu label="Ich" name="File">
+ <menu_item_call label="Einstellungen" name="Preferences..."/>
+ <menu_item_call label="[APP_NAME] schließen" name="Quit"/>
+ </menu>
+ <menu label="Hilfe" name="Help">
+ <menu_item_call label="[SECOND_LIFE]-Hilfe" name="Second Life Help"/>
+ <menu_item_call label="INFO ÃœBER [APP_NAME]" name="About Second Life"/>
+ </menu>
+ <menu_item_check label="Debug-Menü anzeigen" name="Show Debug Menu"/>
+ <menu label="Debug" name="Debug">
+ <menu_item_call label="Debug-Einstellungen anzeigen" name="Debug Settings"/>
+ <menu_item_call label="UI/Farb-Einstellungen" name="UI/Color Settings"/>
+ <menu_item_call label="XUI-Editor" name="UI Preview Tool"/>
+ <menu label="UI-Tests" name="UI Tests"/>
+ <menu_item_call label="Fenstergröße einstellen..." name="Set Window Size..."/>
+ <menu_item_call label="Servicebedingungen anzeigen" name="TOS"/>
+ <menu_item_call label="Wichtige Meldung anzeigen" name="Critical"/>
+ <menu_item_call label="Test Medienbrowser" name="Web Browser Test"/>
+ <menu_item_call label="Test Webinhalt-Floater" name="Web Content Floater Test"/>
+ <menu_item_check label="Grid-Auswahl anzeigen" name="Show Grid Picker"/>
+ <menu_item_call label="Benachrichtigungs-Konsole anzeigen" name="Show Notifications Console"/>
+ </menu>
+</menu_bar>
diff --git a/indra/newview/skins/minimal/xui/de/menu_mini_map.xml b/indra/newview/skins/minimal/xui/de/menu_mini_map.xml
new file mode 100644
index 0000000000..2e0d72c40c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_mini_map.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Zoom Nah" name="Zoom Close"/>
+ <menu_item_call label="Zoom Mittel" name="Zoom Medium"/>
+ <menu_item_call label="Zoom Weit" name="Zoom Far"/>
+ <menu_item_call label="Zoom-Standard" name="Zoom Default"/>
+ <menu_item_check label="Karte drehen" name="Rotate Map"/>
+ <menu_item_check label="Automatisch zentrieren" name="Auto Center"/>
+ <menu_item_call label="Verfolgung abschalten" name="Stop Tracking"/>
+ <menu_item_call label="Weltkarte" name="World Map"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_navbar.xml b/indra/newview/skins/minimal/xui/de/menu_navbar.xml
new file mode 100644
index 0000000000..5175f34b41
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_navbar.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Navbar Menu">
+ <menu_item_check label="Koordinaten anzeigen" name="Show Coordinates"/>
+ <menu_item_check label="Parzelleneigenschaften anzeigen" name="Show Parcel Properties"/>
+ <menu_item_call label="Landmarke" name="Landmark"/>
+ <menu_item_call label="Ausschneiden" name="Cut"/>
+ <menu_item_call label="Kopieren" name="Copy"/>
+ <menu_item_call label="Einfügen" name="Paste"/>
+ <menu_item_call label="Löschen" name="Delete"/>
+ <menu_item_call label="Alle auswählen" name="Select All"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_nearby_chat.xml b/indra/newview/skins/minimal/xui/de/menu_nearby_chat.xml
new file mode 100644
index 0000000000..99d6428c3f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_nearby_chat.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="NearBy Chat Menu">
+ <menu_item_call label="Leute in der Nähe anzeigen..." name="nearby_people"/>
+ <menu_item_check label="Ignorierten Text anzeigen" name="muted_text"/>
+ <menu_item_check label="Bilder von Freunden anzeigen" name="show_buddy_icons"/>
+ <menu_item_check label="Namen anzeigen" name="show_names"/>
+ <menu_item_check label="Namen und Symbole anzeigen" name="show_icons_and_names"/>
+ <menu_item_call label="Schriftgröße" name="font_size"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_notification_well_button.xml b/indra/newview/skins/minimal/xui/de/menu_notification_well_button.xml
new file mode 100644
index 0000000000..0f2784f160
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Alle schließen" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_object.xml b/indra/newview/skins/minimal/xui/de/menu_object.xml
new file mode 100644
index 0000000000..19057d4228
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_object.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Object Pie">
+ <menu_item_call label="Berühren" name="Object Touch">
+ <menu_item_call.on_enable name="EnableTouch" parameter="Berühren"/>
+ </menu_item_call>
+ <menu_item_call label="Bearbeiten" name="Edit..."/>
+ <menu_item_call label="Bauen" name="Build"/>
+ <menu_item_call label="Öffnen" name="Open"/>
+ <menu_item_call label="Hier sitzen" name="Object Sit"/>
+ <menu_item_call label="Aufstehen" name="Object Stand Up"/>
+ <menu_item_call label="Objektprofil" name="Object Inspect"/>
+ <menu_item_call label="Hineinzoomen" name="Zoom In"/>
+ <context_menu label="Anziehen" name="Put On">
+ <menu_item_call label="Anziehen" name="Wear"/>
+ <menu_item_call label="Hinzufügen" name="Add"/>
+ <context_menu label="Anhängen" name="Object Attach"/>
+ <context_menu label="HUD anhängen" name="Object Attach HUD"/>
+ </context_menu>
+ <context_menu label="Entfernen" name="Remove">
+ <menu_item_call label="Missbrauch melden" name="Report Abuse..."/>
+ <menu_item_call label="Ignorieren" name="Object Mute"/>
+ <menu_item_call label="Zurückgeben" name="Return..."/>
+ <menu_item_call label="Löschen" name="Delete"/>
+ </context_menu>
+ <menu_item_call label="Nehmen" name="Pie Object Take"/>
+ <menu_item_call label="Kopie nehmen" name="Take Copy"/>
+ <menu_item_call label="Bezahlen" name="Pay..."/>
+ <menu_item_call label="Kaufen" name="Buy..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_object_icon.xml b/indra/newview/skins/minimal/xui/de/menu_object_icon.xml
new file mode 100644
index 0000000000..8b6c558416
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_object_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Object Icon Menu">
+ <menu_item_call label="Objektprofil..." name="Object Profile"/>
+ <menu_item_call label="Ignorieren..." name="Block"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_outfit_gear.xml b/indra/newview/skins/minimal/xui/de/menu_outfit_gear.xml
new file mode 100644
index 0000000000..897154ec56
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_outfit_gear.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear Outfit">
+ <menu_item_call label="Anziehen - Aktuelles Outfit ersetzen" name="wear"/>
+ <menu_item_call label="Anziehen - Aktuelles Outfit hinzufügen" name="wear_add"/>
+ <menu_item_call label="Ausziehen - Aus aktuellem Outfit entfernen" name="take_off"/>
+ <menu label="Neue Kleider" name="New Clothes">
+ <menu_item_call label="Neues Hemd" name="New Shirt"/>
+ <menu_item_call label="Neue Hose" name="New Pants"/>
+ <menu_item_call label="Neue Schuhe" name="New Shoes"/>
+ <menu_item_call label="Neue Socken" name="New Socks"/>
+ <menu_item_call label="Neue Jacke" name="New Jacket"/>
+ <menu_item_call label="Neuer Rock" name="New Skirt"/>
+ <menu_item_call label="Neue Handschuhe" name="New Gloves"/>
+ <menu_item_call label="Neues Unterhemd" name="New Undershirt"/>
+ <menu_item_call label="Neue Unterhose" name="New Underpants"/>
+ <menu_item_call label="Neues Alpha" name="New Alpha"/>
+ <menu_item_call label="Neue Tätowierung" name="New Tattoo"/>
+ </menu>
+ <menu label="Neue Körperteile" name="New Body Parts">
+ <menu_item_call label="Neue Form" name="New Shape"/>
+ <menu_item_call label="Neue Haut" name="New Skin"/>
+ <menu_item_call label="Neues Haar" name="New Hair"/>
+ <menu_item_call label="Neue Augen" name="New Eyes"/>
+ </menu>
+ <menu_item_call label="Outfit neu benennen" name="rename"/>
+ <menu_item_call label="Outfit löschen" name="delete_outfit"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_outfit_tab.xml b/indra/newview/skins/minimal/xui/de/menu_outfit_tab.xml
new file mode 100644
index 0000000000..32a65c96fc
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_outfit_tab.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Outfit">
+ <menu_item_call label="Anziehen - Aktuelles Outfit ersetzen" name="wear_replace"/>
+ <menu_item_call label="Anziehen - Aktuelles Outfit hinzufügen" name="wear_add"/>
+ <menu_item_call label="Ausziehen - Aus aktuellem Outfit entfernen" name="take_off"/>
+ <menu_item_call label="Outfit bearbeiten" name="edit"/>
+ <menu_item_call label="Outfit neu benennen" name="rename"/>
+ <menu_item_call label="Outfit löschen" name="delete"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_participant_list.xml b/indra/newview/skins/minimal/xui/de/menu_participant_list.xml
new file mode 100644
index 0000000000..160f2f97be
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_participant_list.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Participant List Context Menu">
+ <menu_item_check label="Nach Name sortieren" name="SortByName"/>
+ <menu_item_check label="Nach letzten Sprechern sortieren" name="SortByRecentSpeakers"/>
+ <menu_item_call label="Profil anzeigen" name="View Profile"/>
+ <menu_item_call label="Freund hinzufügen" name="Add Friend"/>
+ <menu_item_call label="IM" name="IM"/>
+ <menu_item_call label="Anrufen" name="Call"/>
+ <menu_item_call label="Teilen" name="Share"/>
+ <menu_item_call label="Bezahlen" name="Pay"/>
+ <menu_item_check label="Symbole für Personen anzeigen" name="View Icons"/>
+ <menu_item_check label="Voice ignorieren" name="Block/Unblock"/>
+ <menu_item_check label="Text ignorieren" name="MuteText"/>
+ <context_menu label="Moderator-Optionen" name="Moderator Options">
+ <menu_item_check label="Text-Chat zulassen" name="AllowTextChat"/>
+ <menu_item_call label="Diesen Teilnehmer stummschalten" name="ModerateVoiceMuteSelected"/>
+ <menu_item_call label="Stummschaltung für diesen Teilnehmer aufheben" name="ModerateVoiceUnMuteSelected"/>
+ <menu_item_call label="Alle stummschalten" name="ModerateVoiceMute"/>
+ <menu_item_call label="Alle freischalten" name="ModerateVoiceUnmute"/>
+ </context_menu>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_people_friends_view_sort.xml b/indra/newview/skins/minimal/xui/de/menu_people_friends_view_sort.xml
new file mode 100644
index 0000000000..84d9d8938c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_people_friends_view_sort.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Nach Name sortieren" name="sort_name"/>
+ <menu_item_check label="Nach Status sortieren" name="sort_status"/>
+ <menu_item_check label="Symbole für Personen anzeigen" name="view_icons"/>
+ <menu_item_check label="Erteilte Genehmigungen anzeigen" name="view_permissions"/>
+ <menu_item_call label="Ignorierte Einwohner &amp; Objekte anzeigen" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_people_groups.xml b/indra/newview/skins/minimal/xui/de/menu_people_groups.xml
new file mode 100644
index 0000000000..76225ba241
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_people_groups.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_call label="Info anzeigen" name="View Info"/>
+ <menu_item_call label="Chat" name="Chat"/>
+ <menu_item_call label="Anrufen" name="Call"/>
+ <menu_item_call label="Aktivieren" name="Activate"/>
+ <menu_item_call label="Verlassen" name="Leave"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_people_groups_view_sort.xml b/indra/newview/skins/minimal/xui/de/menu_people_groups_view_sort.xml
new file mode 100644
index 0000000000..b68597d8aa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_people_groups_view_sort.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Gruppensymbole anzeigen" name="Display Group Icons"/>
+ <menu_item_call label="Ausgewählte Gruppe verlassen" name="Leave Selected Group"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_people_nearby.xml b/indra/newview/skins/minimal/xui/de/menu_people_nearby.xml
new file mode 100644
index 0000000000..1db964357f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_people_nearby.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Avatar Context Menu">
+ <menu_item_call label="Profil anzeigen" name="View Profile"/>
+ <menu_item_call label="Freund hinzufügen" name="Add Friend"/>
+ <menu_item_call label="Freund entfernen" name="Remove Friend"/>
+ <menu_item_call label="IM" name="IM"/>
+ <menu_item_call label="Anrufen" name="Call"/>
+ <menu_item_call label="Karte" name="Map"/>
+ <menu_item_call label="Teilen" name="Share"/>
+ <menu_item_call label="Bezahlen" name="Pay"/>
+ <menu_item_check label="Ignorieren/Freischalten" name="Block/Unblock"/>
+ <menu_item_call label="Teleport anbieten" name="teleport"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_people_nearby_multiselect.xml b/indra/newview/skins/minimal/xui/de/menu_people_nearby_multiselect.xml
new file mode 100644
index 0000000000..b6e99edfe1
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_people_nearby_multiselect.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Multi-Selected People Context Menu">
+ <menu_item_call label="Freunde hinzufügen" name="Add Friends"/>
+ <menu_item_call label="Freunde entfernen" name="Remove Friend"/>
+ <menu_item_call label="IM" name="IM"/>
+ <menu_item_call label="Anrufen" name="Call"/>
+ <menu_item_call label="Teilen" name="Share"/>
+ <menu_item_call label="Bezahlen" name="Pay"/>
+ <menu_item_call label="Teleport anbieten" name="teleport"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_people_nearby_view_sort.xml b/indra/newview/skins/minimal/xui/de/menu_people_nearby_view_sort.xml
new file mode 100644
index 0000000000..0f252ab46d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_people_nearby_view_sort.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Nach letzten Sprechern sortieren" name="sort_by_recent_speakers"/>
+ <menu_item_check label="Nach Name sortieren" name="sort_name"/>
+ <menu_item_check label="Nach Entfernung sortieren" name="sort_distance"/>
+ <menu_item_check label="Symbole für Personen anzeigen" name="view_icons"/>
+ <menu_item_call label="Ignorierte Einwohner &amp; Objekte anzeigen" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_people_recent_view_sort.xml b/indra/newview/skins/minimal/xui/de/menu_people_recent_view_sort.xml
new file mode 100644
index 0000000000..1ef020f5e1
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_people_recent_view_sort.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Nach aktuellesten Sprechern sortieren" name="sort_most"/>
+ <menu_item_check label="Nach Name sortieren" name="sort_name"/>
+ <menu_item_check label="Symbole für Personen anzeigen" name="view_icons"/>
+ <menu_item_call label="Ignorierte Einwohner &amp; Objekte anzeigen" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_picks.xml b/indra/newview/skins/minimal/xui/de/menu_picks.xml
new file mode 100644
index 0000000000..9aec4c83b0
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_picks.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Picks">
+ <menu_item_call label="Info" name="pick_info"/>
+ <menu_item_call label="Bearbeiten" name="pick_edit"/>
+ <menu_item_call label="Teleportieren" name="pick_teleport"/>
+ <menu_item_call label="Karte" name="pick_map"/>
+ <menu_item_call label="Löschen" name="pick_delete"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_picks_plus.xml b/indra/newview/skins/minimal/xui/de/menu_picks_plus.xml
new file mode 100644
index 0000000000..385ff25b95
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_picks_plus.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="picks_plus_menu">
+ <menu_item_call label="Neue Auswahl" name="create_pick"/>
+ <menu_item_call label="Neue Anzeige" name="create_classified"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_place.xml b/indra/newview/skins/minimal/xui/de/menu_place.xml
new file mode 100644
index 0000000000..d9c85f5b92
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_place.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="place_overflow_menu">
+ <menu_item_call label="Eine Landmarke setzen" name="landmark"/>
+ <menu_item_call label="Auswahl erstellen" name="pick"/>
+ <menu_item_call label="Pass kaufen" name="pass"/>
+ <menu_item_call label="Bearbeiten" name="edit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_place_add_button.xml b/indra/newview/skins/minimal/xui/de/menu_place_add_button.xml
new file mode 100644
index 0000000000..7c0ff4a46a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_place_add_button.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_folder_gear">
+ <menu_item_call label="Ordner hinzufügen" name="add_folder"/>
+ <menu_item_call label="Landmarke hinzufügen" name="add_landmark"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_places_gear_folder.xml b/indra/newview/skins/minimal/xui/de/menu_places_gear_folder.xml
new file mode 100644
index 0000000000..132d3f6466
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_places_gear_folder.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_folder_gear">
+ <menu_item_call label="Landmarke hinzufügen" name="add_landmark"/>
+ <menu_item_call label="Ordner hinzufügen" name="add_folder"/>
+ <menu_item_call label="Ausschneiden" name="cut"/>
+ <menu_item_call label="Kopieren" name="copy_folder"/>
+ <menu_item_call label="Einfügen" name="paste"/>
+ <menu_item_call label="Umbenennen" name="rename"/>
+ <menu_item_call label="Löschen" name="delete"/>
+ <menu_item_call label="Erweitern Sie sich" name="expand"/>
+ <menu_item_call label="Zuklappen" name="collapse"/>
+ <menu_item_call label="Alle Ordner aufklappen" name="expand_all"/>
+ <menu_item_call label="Alle Ordner schließen" name="collapse_all"/>
+ <menu_item_check label="Nach Datum sortieren" name="sort_by_date"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_places_gear_landmark.xml b/indra/newview/skins/minimal/xui/de/menu_places_gear_landmark.xml
new file mode 100644
index 0000000000..6af4d644af
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_places_gear_landmark.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_ladmark_gear">
+ <menu_item_call label="Teleportieren" name="teleport"/>
+ <menu_item_call label="Weitere Informationen" name="more_info"/>
+ <menu_item_call label="Auf Karte zeigen" name="show_on_map"/>
+ <menu_item_call label="Landmarke hinzufügen" name="add_landmark"/>
+ <menu_item_call label="Ordner hinzufügen" name="add_folder"/>
+ <menu_item_call label="Ausschneiden" name="cut"/>
+ <menu_item_call label="Landmarke kopieren" name="copy_landmark"/>
+ <menu_item_call label="SLurl kopieren" name="copy_slurl"/>
+ <menu_item_call label="Einfügen" name="paste"/>
+ <menu_item_call label="Umbenennen" name="rename"/>
+ <menu_item_call label="Löschen" name="delete"/>
+ <menu_item_call label="Alle Ordner aufklappen" name="expand_all"/>
+ <menu_item_call label="Alle Ordner schließen" name="collapse_all"/>
+ <menu_item_check label="Nach Datum sortieren" name="sort_by_date"/>
+ <menu_item_call label="Auswahl erstellen" name="create_pick"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_profile_overflow.xml b/indra/newview/skins/minimal/xui/de/menu_profile_overflow.xml
new file mode 100644
index 0000000000..9f3fcbca1d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_profile_overflow.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="profile_overflow_menu">
+ <menu_item_call label="Karte" name="show_on_map"/>
+ <menu_item_call label="Bezahlen" name="pay"/>
+ <menu_item_call label="Teilen" name="share"/>
+ <menu_item_call label="Ignorieren" name="block"/>
+ <menu_item_call label="Freischalten" name="unblock"/>
+ <menu_item_call label="Hinauswerfen" name="kick"/>
+ <menu_item_call label="Einfrieren" name="freeze"/>
+ <menu_item_call label="Auftauen" name="unfreeze"/>
+ <menu_item_call label="CSR" name="csr"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_save_outfit.xml b/indra/newview/skins/minimal/xui/de/menu_save_outfit.xml
new file mode 100644
index 0000000000..986c78b318
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="Speichern" name="save_outfit"/>
+ <menu_item_call label="Speichern unter" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_script_chiclet.xml b/indra/newview/skins/minimal/xui/de/menu_script_chiclet.xml
new file mode 100644
index 0000000000..3256aa1a87
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="Schließen" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_slurl.xml b/indra/newview/skins/minimal/xui/de/menu_slurl.xml
new file mode 100644
index 0000000000..b2ec017f9f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_slurl.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="URL-Info" name="about_url"/>
+ <menu_item_call label="Zu URL teleportieren" name="teleport_to_url"/>
+ <menu_item_call label="Karte" name="show_on_map"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_teleport_history_gear.xml b/indra/newview/skins/minimal/xui/de/menu_teleport_history_gear.xml
new file mode 100644
index 0000000000..68b8e21802
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_teleport_history_gear.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Teleport History Gear Context Menu">
+ <menu_item_call label="Alle Ordner aufklappen" name="Expand all folders"/>
+ <menu_item_call label="Alle Ordner schließen" name="Collapse all folders"/>
+ <menu_item_call label="Teleport-Liste löschen" name="Clear Teleport History"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_teleport_history_item.xml b/indra/newview/skins/minimal/xui/de/menu_teleport_history_item.xml
new file mode 100644
index 0000000000..ff8fb0b181
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_teleport_history_item.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Teleport History Item Context Menu">
+ <menu_item_call label="Teleportieren" name="Teleport"/>
+ <menu_item_call label="Weitere Informationen" name="More Information"/>
+ <menu_item_call label="In Zwischenablage kopieren" name="CopyToClipboard"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_teleport_history_tab.xml b/indra/newview/skins/minimal/xui/de/menu_teleport_history_tab.xml
new file mode 100644
index 0000000000..194dd16fd1
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_teleport_history_tab.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Teleport History Item Context Menu">
+ <menu_item_call label="Öffnen" name="TabOpen"/>
+ <menu_item_call label="Schließen" name="TabClose"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_text_editor.xml b/indra/newview/skins/minimal/xui/de/menu_text_editor.xml
new file mode 100644
index 0000000000..c00186c13e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_text_editor.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Text editor context menu">
+ <menu_item_call label="Ausschneiden" name="Cut"/>
+ <menu_item_call label="Kopieren" name="Copy"/>
+ <menu_item_call label="Einfügen" name="Paste"/>
+ <menu_item_call label="Löschen" name="Delete"/>
+ <menu_item_call label="Alle auswählen" name="Select All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_topinfobar.xml b/indra/newview/skins/minimal/xui/de/menu_topinfobar.xml
new file mode 100644
index 0000000000..5b0a724244
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_topinfobar.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_topinfobar">
+ <menu_item_check label="Koordinaten anzeigen" name="Show Coordinates"/>
+ <menu_item_check label="Parzellen-Eigenschaften anzeigen" name="Show Parcel Properties"/>
+ <menu_item_call label="Landmarke" name="Landmark"/>
+ <menu_item_call label="Kopieren" name="Copy"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_url_agent.xml b/indra/newview/skins/minimal/xui/de/menu_url_agent.xml
new file mode 100644
index 0000000000..9a808088fb
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_url_agent.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Einwohnerprofil anzeigen" name="show_agent"/>
+ <menu_item_call label="Name in Zwischenablage kopieren" name="url_copy_label"/>
+ <menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_url_group.xml b/indra/newview/skins/minimal/xui/de/menu_url_group.xml
new file mode 100644
index 0000000000..6bd86414bc
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_url_group.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Gruppeninformation anzeigen" name="show_group"/>
+ <menu_item_call label="Gruppe in Zwischenablage kopieren" name="url_copy_label"/>
+ <menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_url_http.xml b/indra/newview/skins/minimal/xui/de/menu_url_http.xml
new file mode 100644
index 0000000000..30eb1668a5
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_url_http.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Webseite öffnen" name="url_open"/>
+ <menu_item_call label="Im internen Browser öffnen" name="url_open_internal"/>
+ <menu_item_call label="Im externen Browser öffnen" name="url_open_external"/>
+ <menu_item_call label="URL in Zwischenablage kopieren" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_url_inventory.xml b/indra/newview/skins/minimal/xui/de/menu_url_inventory.xml
new file mode 100644
index 0000000000..dc069df02b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_url_inventory.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Inventarobjekte anzeigen" name="show_item"/>
+ <menu_item_call label="Name in Zwischenablage kopieren" name="url_copy_label"/>
+ <menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_url_map.xml b/indra/newview/skins/minimal/xui/de/menu_url_map.xml
new file mode 100644
index 0000000000..2f6ffcd450
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_url_map.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Auf Karte zeigen" name="show_on_map"/>
+ <menu_item_call label="Zu Position teleportieren" name="teleport_to_location"/>
+ <menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_url_objectim.xml b/indra/newview/skins/minimal/xui/de/menu_url_objectim.xml
new file mode 100644
index 0000000000..90d3763d9c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_url_objectim.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Objektinformationen anzeigen" name="show_object"/>
+ <menu_item_call label="Auf Karte zeigen" name="show_on_map"/>
+ <menu_item_call label="Zu Objekt-Position teleportieren" name="teleport_to_object"/>
+ <menu_item_call label="Objektname in Zwischenablage kopieren" name="url_copy_label"/>
+ <menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_url_parcel.xml b/indra/newview/skins/minimal/xui/de/menu_url_parcel.xml
new file mode 100644
index 0000000000..9169bca24f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_url_parcel.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Parzelleninformationen anzeigen" name="show_parcel"/>
+ <menu_item_call label="Auf Karte zeigen" name="show_on_map"/>
+ <menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_url_slapp.xml b/indra/newview/skins/minimal/xui/de/menu_url_slapp.xml
new file mode 100644
index 0000000000..72e916b902
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_url_slapp.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Diesen Befehl ausführen" name="run_slapp"/>
+ <menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_url_slurl.xml b/indra/newview/skins/minimal/xui/de/menu_url_slurl.xml
new file mode 100644
index 0000000000..5d48230ebf
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_url_slurl.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Ortsinformationen anzeigen" name="show_place"/>
+ <menu_item_call label="Auf Karte zeigen" name="show_on_map"/>
+ <menu_item_call label="Zu Position teleportieren" name="teleport_to_location"/>
+ <menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_url_teleport.xml b/indra/newview/skins/minimal/xui/de/menu_url_teleport.xml
new file mode 100644
index 0000000000..4cc1ecc70e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_url_teleport.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="An diesen Standort teleportieren" name="teleport"/>
+ <menu_item_call label="Auf Karte zeigen" name="show_on_map"/>
+ <menu_item_call label="SLurl in die Zwischenablage kopieren" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_viewer.xml b/indra/newview/skins/minimal/xui/de/menu_viewer.xml
new file mode 100644
index 0000000000..67dc618eb0
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_viewer.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu_bar name="Main Menu">
+ <menu label="Hilfe" name="Help">
+ <menu_item_call label="[SECOND_LIFE]-Hilfe" name="Second Life Help"/>
+ </menu>
+ <menu label="Erweitert" name="Advanced">
+ <menu label="Tastaturkürzel" name="Shortcuts">
+ <menu_item_check label="Fliegen" name="Fly"/>
+ <menu_item_call label="Fenster schließen" name="Close Window"/>
+ <menu_item_call label="Alle Fenster schließen" name="Close All Windows"/>
+ <menu_item_call label="Ansicht zurücksetzen" name="Reset View"/>
+ </menu>
+ </menu>
+</menu_bar>
diff --git a/indra/newview/skins/minimal/xui/de/menu_wearable_list_item.xml b/indra/newview/skins/minimal/xui/de/menu_wearable_list_item.xml
new file mode 100644
index 0000000000..283e454a06
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_wearable_list_item.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Outfit Wearable Context Menu">
+ <menu_item_call label="Ersetzen" name="wear_replace"/>
+ <menu_item_call label="Anziehen" name="wear_wear"/>
+ <menu_item_call label="Hinzufügen" name="wear_add"/>
+ <menu_item_call label="Ausziehen / Abnehmen" name="take_off_or_detach"/>
+ <menu_item_call label="Abnehmen" name="detach"/>
+ <context_menu label="Anhängen an" name="wearable_attach_to"/>
+ <context_menu label="An HUD hängen" name="wearable_attach_to_hud"/>
+ <menu_item_call label="Ausziehen" name="take_off"/>
+ <menu_item_call label="Bearbeiten" name="edit"/>
+ <menu_item_call label="Objektprofil" name="object_profile"/>
+ <menu_item_call label="Original anzeigen" name="show_original"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_wearing_gear.xml b/indra/newview/skins/minimal/xui/de/menu_wearing_gear.xml
new file mode 100644
index 0000000000..80d4ff4d9f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_wearing_gear.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear Wearing">
+ <menu_item_call label="Outfit bearbeiten" name="edit"/>
+ <menu_item_call label="Ausziehen" name="takeoff"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/de/menu_wearing_tab.xml b/indra/newview/skins/minimal/xui/de/menu_wearing_tab.xml
new file mode 100644
index 0000000000..695451a105
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/menu_wearing_tab.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Wearing">
+ <menu_item_call label="Ausziehen" name="take_off"/>
+ <menu_item_call label="Abnehmen" name="detach"/>
+ <menu_item_call label="Outfit bearbeiten" name="edit"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/de/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/de/panel_bottomtray.xml
new file mode 100644
index 0000000000..ea7cccbdf8
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/panel_bottomtray.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="bottom_tray">
+ <string name="DragIndicationImageName" value="Accordion_ArrowOpened_Off"/>
+ <string name="SpeakBtnToolTip" value="Schaltet Mikrofon ein/aus"/>
+ <string name="VoiceControlBtnToolTip" value="Voice-Chat-Steuerung anzeigen/ausblenden"/>
+ <layout_stack name="toolbar_stack">
+ <layout_panel name="gesture_panel">
+ <gesture_combo_list label="Gesten" name="Gesture" tool_tip="Gesten anzeigen/ausblenden"/>
+ </layout_panel>
+ <layout_panel name="cam_panel">
+ <bottomtray_button label="Ansicht" name="camera_btn" tool_tip="Kamerasteuerung anzeigen/ausblenden"/>
+ </layout_panel>
+ <layout_panel name="avatar_and_destinations_panel">
+ <radio_group name="avatar_and_destination_btns">
+ <radio_item name="destination_btn" value="0"/>
+ <radio_item name="avatar_btn" value="1"/>
+ </radio_group>
+ </layout_panel>
+ <layout_panel name="people_panel">
+ <bottomtray_button label="Leute" name="show_people_button" tool_tip="Zeigt Leutefenster an"/>
+ </layout_panel>
+ <layout_panel name="profile_panel">
+ <bottomtray_button label="Profil" name="show_profile_btn" tool_tip="Zeigt Profilfenster an"/>
+ </layout_panel>
+ <layout_panel name="howto_panel">
+ <bottomtray_button label="Anweisungen" name="show_help_btn" tool_tip="Second Life-Anweisungsthemen öffnen"/>
+ </layout_panel>
+ <layout_panel name="im_well_panel">
+ <chiclet_im_well name="im_well">
+ <button name="Unread IM messages" tool_tip="IMs"/>
+ </chiclet_im_well>
+ </layout_panel>
+ <layout_panel name="notification_well_panel">
+ <chiclet_notification name="notification_well">
+ <button name="Unread" tool_tip="Benachrichtigungen"/>
+ </chiclet_notification>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/de/panel_im_control_panel.xml b/indra/newview/skins/minimal/xui/de/panel_im_control_panel.xml
new file mode 100644
index 0000000000..abf8011d9d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/panel_im_control_panel.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_im_control_panel">
+ <text name="avatar_name" value="Unbekannt"/>
+ <layout_stack name="button_stack">
+ <layout_panel name="view_profile_btn_panel">
+ <button label="Profil" name="view_profile_btn"/>
+ </layout_panel>
+ <layout_panel name="add_friend_btn_panel">
+ <button label="Freund hinzufügen" name="add_friend_btn"/>
+ </layout_panel>
+ <layout_panel name="teleport_btn_panel">
+ <button label="Teleportieren" name="teleport_btn" tool_tip="Dieser Person einen Teleport anbieten."/>
+ </layout_panel>
+ <layout_panel name="share_btn_panel">
+ <button label="Teilen" name="share_btn"/>
+ </layout_panel>
+ <layout_panel name="pay_btn_panel">
+ <button label="Bezahlen" name="pay_btn"/>
+ </layout_panel>
+ <layout_panel name="call_btn_panel">
+ <button label="Anrufen" name="call_btn"/>
+ </layout_panel>
+ <layout_panel name="end_call_btn_panel">
+ <button label="Anruf beenden" name="end_call_btn"/>
+ </layout_panel>
+ <layout_panel name="voice_ctrls_btn_panel">
+ <button label="Voice-Steuerung" name="voice_ctrls_btn"/>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/de/panel_login.xml b/indra/newview/skins/minimal/xui/de/panel_login.xml
new file mode 100644
index 0000000000..dff70d6994
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/panel_login.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_login">
+ <panel.string name="create_account_url">
+ http://de.secondlife.com/registration/
+ </panel.string>
+ <panel.string name="forgot_password_url">
+ http://secondlife.com/account/request.php?lang=de
+ </panel.string>
+ <layout_stack name="login_widgets">
+ <layout_panel name="login">
+ <text name="username_text">
+ Benutzername:
+ </text>
+ <combo_box name="username_combo" tool_tip="Bei der Registrierung gewählter Benutzername wie „berndschmidt12“ oder „Liebe Sonne“"/>
+ <text name="password_text">
+ Kennwort:
+ </text>
+ <check_box label="Kennwort merken" name="remember_check"/>
+ <button label="Anmelden" name="connect_btn"/>
+ <text name="mode_selection_text">
+ Modus:
+ </text>
+ <combo_box name="mode_combo">
+ <combo_box.item label="Einfach (Standard)" name="Basic"/>
+ <combo_box.item label="Erweitert" name="Advanced"/>
+ </combo_box>
+ </layout_panel>
+ <layout_panel name="links">
+ <text name="create_new_account_text">
+ Registrieren
+ </text>
+ <text name="forgot_password_text">
+ Benutzernamen oder Kennwort vergessen?
+ </text>
+ <text name="login_help">
+ Sie brauchen Hilfe?
+ </text>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/de/panel_navigation_bar.xml b/indra/newview/skins/minimal/xui/de/panel_navigation_bar.xml
new file mode 100644
index 0000000000..ee1a543aac
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/panel_navigation_bar.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="navigation_bar">
+ <panel name="navigation_panel">
+ <pull_button name="back_btn" tool_tip="Zurück zum vorherigen Standort teleportieren"/>
+ <pull_button name="forward_btn" tool_tip="Um einen Standort weiter teleportieren"/>
+ <button name="home_btn" tool_tip="Zu meinem Zuhause teleportieren"/>
+ <location_input label="Standort" name="location_combo"/>
+ <search_combo_box label="Suche" name="search_combo_box" tool_tip="Suche">
+ <combo_editor label="[SECOND_LIFE] durchsuchen" name="search_combo_editor"/>
+ </search_combo_box>
+ </panel>
+ <favorites_bar name="favorite" tool_tip="Ziehen Sie Landmarken hier hin, damit Sie schnell zu Ihren Lieblingsplätzen in Second Life gelangen können!">
+ <label name="favorites_bar_label" tool_tip="Ziehen Sie Landmarken hier hin, damit Sie schnell zu Ihren Lieblingsplätzen in Second Life gelangen können!">
+ Favoritenleiste
+ </label>
+ <chevron_button name="&gt;&gt;" tool_tip="Mehr meiner Favoriten anzeigen"/>
+ </favorites_bar>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/de/panel_people.xml b/indra/newview/skins/minimal/xui/de/panel_people.xml
new file mode 100644
index 0000000000..c6253e17de
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/panel_people.xml
@@ -0,0 +1,70 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray panel -->
+<panel label="Leute" name="people_panel">
+ <string name="no_recent_people" value="Sie haben in letzter Zeit mit niemandem interagiert. Suchen Sie nach Leuten, mit denen Sie sich unterhalten können? Klicken Sie unten auf die Schaltfläche „Ziele“."/>
+ <string name="no_filtered_recent_people" value="Es gibt keine Leute mit diesem Namen, mit denen Sie in letzter Zeit interagiert haben."/>
+ <string name="no_one_near" value="Es ist niemand in der Nähe. Suchen Sie nach Leuten, mit denen Sie sich unterhalten können? Klicken Sie unten auf die Schaltfläche „Ziele“."/>
+ <string name="no_one_filtered_near" value="Es ist niemand mit diesem Namen in der Nähe."/>
+ <string name="no_friends_online" value="Keine Freunde online"/>
+ <string name="no_friends" value="Keine Freunde"/>
+ <string name="no_friends_msg">
+ Klicken Sie mit der rechten Maustaste auf einen Einwohner, um ihn als Freund hinzuzufügen. Suchen Sie nach Leuten, mit denen Sie sich unterhalten können? Klicken Sie unten auf die Schaltfläche „Ziele“.
+ </string>
+ <string name="no_filtered_friends_msg">
+ Sie haben nicht das Richtige gefunden? Klicken Sie unten auf die Schaltfläche „Ziele“.
+ </string>
+ <string name="people_filter_label" value="Nach Leuten filtern"/>
+ <string name="groups_filter_label" value="Nach Gruppen filtern"/>
+ <string name="no_filtered_groups_msg" value="Sie haben nicht das Richtige gefunden? Versuchen Sie es mit der [secondlife:///app/search/groups/[SEARCH_TERM] Suche]."/>
+ <string name="no_groups_msg" value="Suchen Sie nach Gruppen? Versuchen Sie es mit der [secondlife:///app/search/groups Suche]."/>
+ <string name="MiniMapToolTipMsg" value="[REGION](Doppelklicken, um Karte zu öffnen; Umschalttaste gedrückt halten und ziehen, um zu schwenken)"/>
+ <string name="AltMiniMapToolTipMsg" value="[REGION](Doppelklicken, um zu teleportieren; Umschalttaste gedrückt halten und ziehen, um zu schwenken)"/>
+ <filter_editor label="Filter" name="filter_input"/>
+ <tab_container name="tabs">
+ <panel label="IN DER NÄHE" name="nearby_panel">
+ <panel label="bottom_panel" name="bottom_panel"/>
+ </panel>
+ <panel label="MEINE FREUNDE" name="friends_panel">
+ <accordion name="friends_accordion">
+ <accordion_tab name="tab_online" title="Online"/>
+ <accordion_tab name="tab_all" title="Alle"/>
+ </accordion>
+ <panel label="bottom_panel" name="bottom_panel">
+ <layout_stack name="bottom_panel">
+ <layout_panel name="trash_btn_panel">
+ <dnd_button name="del_btn" tool_tip="Ausgewählte Person aus Ihrer Freundesliste entfernen"/>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </panel>
+ <panel label="AKTUELL" name="recent_panel">
+ <panel label="bottom_panel" name="bottom_panel">
+ <button name="add_friend_btn" tool_tip="Ausgewählten Einwohner zur Freundeliste hinzufügen"/>
+ </panel>
+ </panel>
+ </tab_container>
+ <panel name="button_bar">
+ <layout_stack name="bottom_bar_ls">
+ <layout_panel name="view_profile_btn_lp">
+ <button label="Profil" name="view_profile_btn" tool_tip="Bilder, Gruppen und andere Einwohner-Informationen anzeigen"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="IM" name="im_btn" tool_tip="Instant Messenger öffnen"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="Teleportieren" name="teleport_btn" tool_tip="Teleport anbieten"/>
+ </layout_panel>
+ </layout_stack>
+ <layout_stack name="bottom_bar_ls1">
+ <layout_panel name="group_info_btn_lp">
+ <button label="Gruppenprofil" name="group_info_btn" tool_tip="Gruppeninformationen anzeigen"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="Gruppen-Chat" name="chat_btn" tool_tip="Chat öffnen"/>
+ </layout_panel>
+ <layout_panel name="group_call_btn_lp">
+ <button label="Gruppe anrufen" name="group_call_btn" tool_tip="Diese Gruppe anrufen"/>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/de/panel_side_tray_tab_caption.xml b/indra/newview/skins/minimal/xui/de/panel_side_tray_tab_caption.xml
new file mode 100644
index 0000000000..652fb7c836
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/panel_side_tray_tab_caption.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="sidetray_tab_panel">
+ <text name="sidetray_tab_title" value="Klappmenü??"/>
+ <button name="undock" tool_tip="Abkoppeln"/>
+ <button name="dock" tool_tip="Andocken"/>
+ <button name="show_help" tool_tip="Hilfe anzeigen"/>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/de/panel_status_bar.xml b/indra/newview/skins/minimal/xui/de/panel_status_bar.xml
new file mode 100644
index 0000000000..04ed58f944
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/de/panel_status_bar.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="status">
+ <panel.string name="StatBarDaysOfWeek">
+ Sonntag:Montag:Dienstag:Mittwoch:Donnerstag:Freitag:Samstag
+ </panel.string>
+ <panel.string name="StatBarMonthsOfYear">
+ Januar:Februar:März:April:Mai:Juni:Juli:August:September:Oktober:November:Dezember
+ </panel.string>
+ <panel.string name="packet_loss_tooltip">
+ Paketverlust
+ </panel.string>
+ <panel.string name="bandwidth_tooltip">
+ Bandbreite
+ </panel.string>
+ <panel.string name="time">
+ [hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]
+ </panel.string>
+ <panel.string name="timeTooltip">
+ [weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]
+ </panel.string>
+ <panel.string name="buycurrencylabel">
+ [AMT] L$
+ </panel.string>
+ <panel name="balance_bg">
+ <text name="balance" tool_tip="Klicken, um L$-Guthaben zu aktualisieren" value="20 L$"/>
+ <button label="L$ kaufen" name="buyL" tool_tip="Hier klicken, um mehr L$ zu kaufen"/>
+ </panel>
+ <text name="TimeText" tool_tip="Aktuelle Zeit (Pazifik)">
+ 24:00 H PST
+ </text>
+ <button name="media_toggle_btn" tool_tip="Alle Medien starten/stoppen (Musik, Video, Webseiten)"/>
+ <button name="volume_btn" tool_tip="Steuerung der Gesamtlautstärke"/>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/floater_camera.xml b/indra/newview/skins/minimal/xui/en/floater_camera.xml
new file mode 100644
index 0000000000..4cf792444f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/floater_camera.xml
@@ -0,0 +1,284 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_dock="true"
+ can_minimize="true"
+ can_close="false"
+ follows="bottom"
+ height="164"
+ layout="topleft"
+ name="camera_floater"
+ save_rect="true"
+ save_visibility="true"
+ save_dock_state="true"
+ single_instance="true"
+ width="228">
+ <floater.string
+ name="rotate_tooltip">
+ Rotate Camera Around Focus
+ </floater.string>
+ <floater.string
+ name="zoom_tooltip">
+ Zoom Camera Towards Focus
+ </floater.string>
+ <floater.string
+ name="move_tooltip">
+ Move Camera Up and Down, Left and Right
+ </floater.string>
+ <floater.string
+ name="camera_modes_title">
+ Camera modes
+ </floater.string>
+ <floater.string
+ name="pan_mode_title">
+ Orbit Zoom Pan
+ </floater.string>
+ <floater.string
+ name="presets_mode_title">
+ Preset Views
+ </floater.string>
+ <floater.string
+ name="free_mode_title">
+ View Object
+ </floater.string>
+ <panel
+ border="false"
+ height="123"
+ layout="topleft"
+ left="2"
+ top="0"
+ mouse_opaque="false"
+ name="controls"
+ width="226">
+ <panel
+ color="Transparent"
+ follows="all"
+ height="102"
+ layout="topleft"
+ left="8"
+ name="preset_views_list"
+ opaque="true"
+ top="24"
+ width="212"
+ visible="false">
+ <panel_camera_item
+ name="front_view">
+ <panel_camera_item.mousedown_callback
+ function="CameraPresets.ChangeView"
+ parameter="front_view" />
+ <panel_camera_item.picture
+ image_name="Cam_Preset_Front_Off" />
+ <panel_camera_item.selected_picture
+ image_name="Cam_Preset_Front_On" />
+ <panel_camera_item.text
+ name="front_view_text">
+ Front View
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item
+ name="group_view"
+ top_pad="4">
+ <panel_camera_item.mousedown_callback
+ function="CameraPresets.ChangeView"
+ parameter="group_view" />
+ <panel_camera_item.picture
+ image_name="Cam_Preset_Side_Off" />
+ <panel_camera_item.selected_picture
+ image_name="Cam_Preset_Side_On" />
+ <panel_camera_item.text
+ name="side_view_text">
+ Side View
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item
+ name="rear_view"
+ layout="topleft"
+ top_pad="4">
+ <panel_camera_item.mousedown_callback
+ function="CameraPresets.ChangeView"
+ parameter="rear_view" />
+ <panel_camera_item.picture
+ image_name="Cam_Preset_Back_Off" />
+ <panel_camera_item.selected_picture
+ image_name="Cam_Preset_Back_On" />
+ <panel_camera_item.text
+ name="rear_view_text">
+ Rear View
+ </panel_camera_item.text>
+ </panel_camera_item>
+ </panel>
+ <panel
+ color="Transparent"
+ follows="all"
+ height="68"
+ item_pad="4"
+ layout="topleft"
+ left="8"
+ name="camera_modes_list"
+ opaque="true"
+ top="24"
+ width="212"
+ visible="false">
+ <panel_camera_item
+ name="object_view">
+ <panel_camera_item.mousedown_callback
+ function="CameraPresets.ChangeView"
+ parameter="object_view" />
+ <panel_camera_item.text
+ name="object_view_text">
+ Object View
+ </panel_camera_item.text>
+ <panel_camera_item.picture
+ image_name="Object_View_Off" />
+ <panel_camera_item.selected_picture
+ image_name="Object_View_On" />
+ </panel_camera_item>
+ <panel_camera_item
+ name="mouselook_view"
+ layout="topleft">
+ <panel_camera_item.mousedown_callback
+ function="CameraPresets.ChangeView"
+ parameter="mouselook_view" />
+ <panel_camera_item.text
+ name="mouselook_view_text">
+ Mouselook View
+ </panel_camera_item.text>
+ <panel_camera_item.picture
+ image_name="MouseLook_View_Off" />
+ <panel_camera_item.selected_picture
+ image_name="MouseLook_View_On" />
+ </panel_camera_item>
+ </panel>
+ <!--TODO: replace + - images -->
+ <panel
+ border="false"
+ class="camera_zoom_panel"
+ height="114"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="zoom"
+ top="20"
+ width="226">
+ <joystick_rotate
+ follows="top|left"
+ height="78"
+ image_selected="Cam_Rotate_In"
+ image_unselected="Cam_Rotate_Out"
+ layout="topleft"
+ left="7"
+ mouse_opaque="false"
+ name="cam_rotate_stick"
+ quadrant="left"
+ scale_image="false"
+ sound_flags="3"
+ visible="true"
+ tool_tip="Orbit camera around focus"
+ top="20"
+ width="78">
+ <commit_callback
+ function="Camera.rotate" />
+ <mouse_held_callback
+ function="Camera.rotate" />
+ </joystick_rotate>
+ <button
+ follows="top|left"
+ height="18"
+ image_disabled="AddItem_Disabled"
+ image_selected="AddItem_Press"
+ image_unselected="AddItem_Off"
+ layout="topleft"
+ left_pad="14"
+ name="zoom_plus_btn"
+ width="18"
+ top="18">
+ <commit_callback
+ function="Zoom.plus" />
+ <mouse_held_callback
+ function="Zoom.plus" />
+ </button>
+ <slider_bar
+ height="50"
+ layout="topleft"
+ name="zoom_slider"
+ orientation="vertical"
+ tool_tip="Zoom camera toward focus"
+ top_pad="0"
+ min_val="0"
+ max_val="1"
+ width="18">
+ <commit_callback function="Slider.value_changed"/>
+ </slider_bar>
+ <button
+ follows="top|left"
+ height="18"
+ image_disabled="MinusItem_Disabled"
+ image_selected="MinusItem_Press"
+ image_unselected="MinusItem_Off"
+ layout="topleft"
+ name="zoom_minus_btn"
+ top_pad="0"
+ width="18">
+ <commit_callback
+ function="Zoom.minus" />
+ <mouse_held_callback
+ function="Zoom.minus" />
+ </button>
+ <joystick_track
+ follows="top|left"
+ height="78"
+ image_selected="Cam_Tracking_In"
+ image_unselected="Cam_Tracking_Out"
+ layout="topleft"
+ left="133"
+ name="cam_track_stick"
+ quadrant="left"
+ scale_image="false"
+ sound_flags="3"
+ tool_tip="Move camera up and down, left and right"
+ top="20"
+ width="78">
+ <commit_callback
+ function="Camera.track" />
+ <mouse_held_callback
+ function="Camera.track" />
+ </joystick_track>
+ </panel>
+ </panel>
+ <panel
+ border="false"
+ height="42"
+ layout="topleft"
+ left="2"
+ top_pad="0"
+ name="buttons"
+ width="226">
+ <button
+ height="23"
+ label=""
+ layout="topleft"
+ left="83"
+ is_toggle="true"
+ image_overlay="Cam_Avatar_Off"
+ image_selected="PushButton_Selected_Press"
+ name="presets_btn"
+ tab_stop="false"
+ tool_tip="Preset Views"
+ top="13"
+ width="25">
+ </button>
+ <button
+ height="23"
+ label=""
+ layout="topleft"
+ left_pad="1"
+ is_toggle="true"
+ image_overlay="PanOrbit_Off"
+ image_selected="PushButton_Selected_Press"
+ name="pan_btn"
+ tab_stop="false"
+ tool_tip="Orbit Zoom Pan"
+ width="25">
+ </button>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/en/floater_help_browser.xml b/indra/newview/skins/minimal/xui/en/floater_help_browser.xml
new file mode 100644
index 0000000000..eddfe41c25
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/floater_help_browser.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_resize="true"
+ can_minimize="false"
+ height="360"
+ layout="topleft"
+ min_height="360"
+ left="645"
+ top="10"
+ min_width="300"
+ name="floater_help_browser"
+ save_rect="true"
+ single_instance="true"
+ title="HOW TO"
+ width="300">
+ <floater.string
+ name="loading_text">
+ Loading...
+ </floater.string>
+ <floater.string
+ name="done_text">
+ </floater.string>
+ <layout_stack
+ bottom="360"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ left="5"
+ orientation="vertical"
+ name="stack1"
+ top="20"
+ width="290">
+ <layout_panel
+ layout="topleft"
+ left_delta="0"
+ top_delta="0"
+ name="external_controls"
+ user_resize="false"
+ width="280">
+ <web_browser
+ trusted_content="true"
+ bottom="-5"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ left="0"
+ name="browser"
+ top="0"
+ height="300"
+ width="280" />
+ </layout_panel>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/en/floater_media_browser.xml b/indra/newview/skins/minimal/xui/en/floater_media_browser.xml
new file mode 100644
index 0000000000..4862146c94
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/floater_media_browser.xml
@@ -0,0 +1,242 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_resize="true"
+ height="440"
+ layout="topleft"
+ min_height="140"
+ min_width="467"
+ name="floater_about"
+ save_rect="true"
+ auto_tile="true"
+ title="MEDIA BROWSER"
+ width="820">
+ <floater.string
+ name="home_page_url">
+ http://www.secondlife.com
+ </floater.string>
+ <floater.string
+ name="support_page_url">
+ http://support.secondlife.com
+ </floater.string>
+ <layout_stack
+ bottom="440"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ left="10"
+ name="stack1"
+ orientation="vertical"
+ top="20"
+ width="800">
+ <layout_panel
+ auto_resize="false"
+ default_tab_group="1"
+ height="20"
+ layout="topleft"
+ left="0"
+ min_height="20"
+ name="nav_controls"
+ top="400"
+ user_resize="false"
+ width="800">
+ <button
+ follows="left|top"
+ height="20"
+ label="Back"
+ layout="topleft"
+ left="0"
+ name="back"
+ top="0"
+ width="55">
+ <button.commit_callback
+ function="MediaBrowser.Back" />
+ </button>
+ <button
+ follows="left|top"
+ height="20"
+ label="Forward"
+ layout="topleft"
+ left_pad="3"
+ name="forward"
+ top_delta="0"
+ width="68">
+ <button.commit_callback
+ function="MediaBrowser.Forward" />
+ </button>
+ <button
+ enabled="false"
+ follows="left|top"
+ height="20"
+ label="Reload"
+ layout="topleft"
+ left_pad="2"
+ name="reload"
+ top_delta="0"
+ width="70">
+ <button.commit_callback
+ function="MediaBrowser.Refresh" />
+ </button>
+ <combo_box
+ allow_text_entry="true"
+ follows="left|top|right"
+ tab_group="1"
+ height="20"
+ layout="topleft"
+ left_pad="5"
+ max_chars="1024"
+ name="address"
+ combo_editor.select_on_focus="true"
+ top_delta="0"
+ width="540">
+ <combo_box.commit_callback
+ function="MediaBrowser.EnterAddress" />
+ </combo_box>
+ <button
+ enabled="false"
+ follows="right|top"
+ height="20"
+ label="Go"
+ layout="topleft"
+ left_pad="5"
+ name="go"
+ top_delta="0"
+ width="50">
+ <button.commit_callback
+ function="MediaBrowser.Go" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ height="20"
+ layout="topleft"
+ left_delta="0"
+ min_height="20"
+ name="time_controls"
+ top_delta="0"
+ user_resize="false"
+ width="800">
+ <button
+ follows="left|top"
+ height="20"
+ label="rewind"
+ layout="topleft"
+ left="0"
+ name="rewind"
+ top="0"
+ width="55" />
+ <button
+ follows="left|top"
+ height="20"
+ image_selected="button_anim_play_selected.tga"
+ image_unselected="button_anim_play.tga"
+ layout="topleft"
+ left_delta="55"
+ name="play"
+ top_delta="0"
+ width="55" />
+ <button
+ follows="left|top"
+ height="20"
+ image_selected="button_anim_pause_selected.tga"
+ image_unselected="button_anim_pause.tga"
+ layout="topleft"
+ left_delta="0"
+ name="pause"
+ top_delta="0"
+ width="55" />
+ <button
+ follows="left|top"
+ height="20"
+ label="stop"
+ layout="topleft"
+ left_pad="10"
+ name="stop"
+ top_delta="0"
+ width="55" />
+ <button
+ follows="left|top"
+ height="20"
+ label="forward"
+ layout="topleft"
+ left_pad="20"
+ name="seek"
+ top_delta="0"
+ width="55" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ height="20"
+ layout="topleft"
+ left_delta="0"
+ min_height="20"
+ name="parcel_owner_controls"
+ top_delta="0"
+ user_resize="false"
+ width="540">
+ <button
+ enabled="false"
+ follows="left|top"
+ height="20"
+ label="Send Current Page to Parcel"
+ layout="topleft"
+ left="0"
+ name="assign"
+ top="0"
+ width="200">
+ <button.commit_callback
+ function="MediaBrowser.Assign" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ height="40"
+ layout="topleft"
+ left_delta="0"
+ name="external_controls"
+ top_delta="0"
+ user_resize="false"
+ width="540">
+ <web_browser
+ bottom="-30"
+ follows="all"
+ layout="topleft"
+ left="0"
+ name="browser"
+ top="0"
+ width="540" />
+ <button
+ follows="bottom|left"
+ height="20"
+ label="Open in My Web Browser"
+ layout="topleft"
+ left_delta="0"
+ name="open_browser"
+ top_pad="5"
+ width="185">
+ <button.commit_callback
+ function="MediaBrowser.OpenWebBrowser" />
+ </button>
+ <check_box
+ control_name="UseExternalBrowser"
+ follows="bottom|left"
+ height="20"
+ label="Always open in my web browser"
+ layout="topleft"
+ left_pad="5"
+ name="open_always"
+ top_delta="0"
+ width="200" />
+ <button
+ follows="bottom|right"
+ height="20"
+ label="Close"
+ layout="topleft"
+ left_pad="80"
+ name="close"
+ top_delta="0"
+ width="70">
+ <button.commit_callback
+ function="MediaBrowser.Close" />
+ </button>
+ </layout_panel>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/en/floater_nearby_chat.xml b/indra/newview/skins/minimal/xui/en/floater_nearby_chat.xml
new file mode 100644
index 0000000000..74ac885202
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/floater_nearby_chat.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater
+ border_visible="false"
+ border="false"
+ bg_opaque_image="Window_Foreground"
+ bg_alpha_image="Window_Background"
+ bg_alpha_image_overlay="DkGray_66"
+ legacy_header_height="18"
+ can_minimize="true"
+ can_tear_off="false"
+ can_resize="true"
+ can_drag_on_left="false"
+ can_close="false"
+ can_dock="true"
+ bevel_style="in"
+ height="300"
+ min_width="235"
+ layout="topleft"
+ name="nearby_chat"
+ save_rect="true"
+ title="NEARBY CHAT"
+ save_dock_state="true"
+ save_visibility="true"
+ single_instance="true"
+ width="320">
+ <check_box
+ bottom_delta="36"
+ control_name="TranslateChat"
+ enabled="true"
+ height="16"
+ label="Translate chat (powered by Google)"
+ layout="topleft"
+ left="5"
+ name="translate_chat_checkbox"
+ width="230" />
+ <chat_history
+ parse_urls="true"
+ bg_readonly_color="ChatHistoryBgColor"
+ bg_writeable_color="ChatHistoryBgColor"
+ follows="all"
+ left="5"
+ top_delta="17"
+ layout="topleft"
+ height="260"
+ name="chat_history"
+ parse_highlights="true"
+ text_color="ChatHistoryTextColor"
+ text_readonly_color="ChatHistoryTextColor"
+ right_widget_pad="5"
+ left_widget_pad="0"
+ width="315" />
+</floater>
diff --git a/indra/newview/skins/minimal/xui/en/floater_side_bar_tab.xml b/indra/newview/skins/minimal/xui/en/floater_side_bar_tab.xml
new file mode 100644
index 0000000000..83b1260620
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/floater_side_bar_tab.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<floater
+ can_close="true"
+ can_resize="true"
+ min_width="333"
+ min_height="440"
+ save_rect="true"
+ save_visibility="true"
+ >
+</floater>
diff --git a/indra/newview/skins/minimal/xui/en/floater_web_content.xml b/indra/newview/skins/minimal/xui/en/floater_web_content.xml
new file mode 100644
index 0000000000..50cb5b14ce
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/floater_web_content.xml
@@ -0,0 +1,189 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<floater
+ legacy_header_height="18"
+ can_resize="true"
+ height="775"
+ layout="topleft"
+ min_height="400"
+ min_width="500"
+ name="floater_web_content"
+ save_rect="true"
+ auto_tile="true"
+ title=""
+ initial_mime_type="text/html"
+ width="780">
+ <layout_stack
+ bottom="775"
+ follows="left|right|top|bottom"
+ layout="topleft"
+ left="5"
+ name="stack1"
+ orientation="vertical"
+ top="20"
+ width="770">
+ <layout_panel
+ auto_resize="false"
+ default_tab_group="1"
+ height="22"
+ layout="topleft"
+ left="0"
+ min_height="20"
+ name="nav_controls"
+ top="400"
+ user_resize="false"
+ width="770">
+ <button
+ image_overlay="Arrow_Left_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ hover_glow_amount="0.15"
+ tool_tip="Navigate back"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="1"
+ name="back"
+ top="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Back" />
+ </button>
+ <button
+ image_overlay="Arrow_Right_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ tool_tip="Navigate forward"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="27"
+ name="forward"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Forward" />
+ </button>
+ <button
+ image_overlay="Stop_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ tool_tip="Stop navigation"
+ enabled="true"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="51"
+ name="stop"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Stop" />
+ </button>
+ <button
+ image_overlay="Refresh_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ tool_tip="Reload page"
+ follows="left|top"
+ height="22"
+ layout="topleft"
+ left="51"
+ name="reload"
+ top_delta="0"
+ width="22">
+ <button.commit_callback
+ function="WebContent.Reload" />
+ </button>
+ <combo_box
+ allow_text_entry="true"
+ follows="left|top|right"
+ tab_group="1"
+ height="22"
+ layout="topleft"
+ left_pad="4"
+ max_chars="1024"
+ name="address"
+ combo_editor.select_on_focus="true"
+ tool_tip="Enter URL here"
+ top_delta="0"
+ width="672">
+ <combo_box.commit_callback
+ function="WebContent.EnterAddress" />
+ </combo_box>
+ <icon
+ name="media_secure_lock_flag"
+ height="16"
+ follows="top|right"
+ image_name="Lock2"
+ layout="topleft"
+ left_delta="620"
+ top_delta="2"
+ visible="false"
+ tool_tip="Secured Browsing"
+ width="16" />
+ <button
+ image_overlay="ExternalBrowser_Off"
+ image_disabled="PushButton_Disabled"
+ image_disabled_selected="PushButton_Disabled"
+ image_selected="PushButton_Selected"
+ image_unselected="PushButton_Off"
+ tool_tip="Open current URL in your desktop browser"
+ follows="right|top"
+ enabled="true"
+ height="22"
+ layout="topleft"
+ name="popexternal"
+ right="770"
+ top_delta="-2"
+ width="22">
+ <button.commit_callback
+ function="WebContent.PopExternal" />
+ </button>
+ </layout_panel>
+ <layout_panel
+ height="40"
+ layout="topleft"
+ left_delta="0"
+ name="external_controls"
+ top_delta="0"
+ user_resize="false"
+ width="585">
+ <web_browser
+ bottom="-22"
+ follows="all"
+ layout="topleft"
+ left="0"
+ name="webbrowser"
+ top="0"/>
+ <text
+ type="string"
+ length="200"
+ follows="bottom|left"
+ height="20"
+ layout="topleft"
+ left_delta="0"
+ name="statusbartext"
+ parse_urls="false"
+ text_color="0.4 0.4 0.4 1"
+ top_pad="5"
+ width="495"/>
+ <progress_bar
+ color_bar="0.3 1.0 0.3 1"
+ follows="bottom|right"
+ height="16"
+ top_delta="-1"
+ left_pad="24"
+ layout="topleft"
+ name="statusbarprogress"
+ width="64"/>
+ </layout_panel>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/en/inspect_avatar.xml b/indra/newview/skins/minimal/xui/en/inspect_avatar.xml
new file mode 100644
index 0000000000..853d5f8735
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/inspect_avatar.xml
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater
+ legacy_header_height="25"
+ bevel_style="in"
+ bg_opaque_image="Inspector_Background"
+ can_close="false"
+ can_minimize="false"
+ height="164"
+ layout="topleft"
+ name="inspect_avatar"
+ single_instance="true"
+ sound_flags="0"
+ visible="true"
+ width="245">
+ <!-- Allowed fields include:
+ [BORN_ON] ("12/3/2008")
+ [SL_PROFILE] (Second Life profile),
+ [RW_PROFILE] (real world profile),
+ [ACCTTYPE] ("Resident"),
+ [PAYMENTINFO] ("Payment Info on File"),
+ [AGE] ("1 year 2 months")
+ -->
+ <string
+ name="Subtitle">
+[AGE]
+ </string>
+ <string
+ name="Details">
+[SL_PROFILE]
+ </string>
+ <text
+ follows="top|left"
+ font="SansSerif"
+ height="20"
+ left="8"
+ name="user_name_small"
+ top="7"
+ text_color="White"
+ use_ellipses="true"
+ word_wrap="true"
+ visible="false"
+ value="Grumpity ProductEngine with a long name"
+ width="185" />
+ <text
+ follows="top|left"
+ font="SansSerifBigLarge"
+ height="21"
+ left="8"
+ name="user_name"
+ top="10"
+ text_color="White"
+ use_ellipses="true"
+ value="Grumpity ProductEngine"
+ width="190" />
+ <text
+ follows="top|left"
+ height="16"
+ left="8"
+ name="user_slid"
+ font="SansSerifSmallBold"
+ text_color="EmphasisColor"
+ value="james.linden"
+ width="185"
+ use_ellipses="true" />
+ <text
+ follows="top|left"
+ height="16"
+ left="8"
+ name="user_subtitle"
+ font="SansSerifSmall"
+ text_color="White"
+ top_pad="0"
+ value="11 Months, 3 days old"
+ width="175"
+ use_ellipses="true" />
+ <text
+ follows="left|top|right"
+ height="35"
+ left="8"
+ name="user_details"
+ right="-10"
+ word_wrap="true"
+ top_pad="4"
+ use_ellipses="true"
+ width="220">This is my second life description and I really think it is great. But for some reason my description is super extra long because I like to talk a whole lot
+ </text>
+ <slider
+ follows="top|left"
+ height="23"
+ increment="0.01"
+ left="1"
+ max_val="0.95"
+ min_val="0.05"
+ name="volume_slider"
+ show_text="false"
+ tool_tip="Voice volume"
+ top_pad="0"
+ value="0.5"
+ width="200" />
+ <button
+ follows="top|left"
+ height="16"
+ image_disabled="Audio_Off"
+ image_disabled_selected="AudioMute_Off"
+ image_hover_selected="AudioMute_Over"
+ image_selected="AudioMute_Off"
+ image_unselected="Audio_Off"
+ is_toggle="true"
+ left_pad="0"
+ top_delta="4"
+ name="mute_btn"
+ width="16" />
+ <avatar_icon
+ follows="top|left"
+ height="38"
+ right="-10"
+ bevel_style="in"
+ border_style="line"
+ mouse_opaque="true"
+ name="avatar_icon"
+ top="10"
+ width="38" />
+<!-- Overlapping buttons for default actions
+ llinspectavatar.cpp makes visible the most likely default action
+-->
+ <button
+ follows="top|left"
+ height="20"
+ label="Add Friend"
+ left="8"
+ top="135"
+ name="add_friend_btn"
+ width="90" />
+ <button
+ follows="top|left"
+ height="20"
+ label="IM"
+ left_delta="0"
+ top_delta="0"
+ name="im_btn"
+ width="80"
+ commit_callback.function="InspectAvatar.IM"/>
+ <button
+ follows="top|left"
+ height="20"
+ label="Profile"
+ layout="topleft"
+ name="view_profile_btn"
+ left_delta="96"
+ top_delta="0"
+ tab_stop="false"
+ width="80" />
+ <!-- gear buttons here -->
+ <menu_button
+ follows="top|left"
+ height="20"
+ layout="topleft"
+ image_overlay="OptionsMenu_Off"
+ menu_filename="menu_inspect_avatar_gear.xml"
+ name="gear_btn"
+ right="-5"
+ top_delta="0"
+ width="35" />
+ <menu_button
+ follows="top|left"
+ height="20"
+ image_overlay="OptionsMenu_Off"
+ menu_filename="menu_inspect_self_gear.xml"
+ name="gear_self_btn"
+ right="-5"
+ top_delta="0"
+ width="35" />
+ <panel
+ follows="top|left"
+ top="164"
+ left="0"
+ height="60"
+ width="228"
+ visible="false"
+ background_visible="true"
+ name="moderator_panel"
+ background_opaque="true"
+ bg_opaque_color="MouseGray">
+ <button
+ name="disable_voice"
+ label="Disable Voice"
+ top="20"
+ width="95"
+ height="20"
+ left="10"
+ commit_callback.function="InspectAvatar.DisableVoice"/>
+ <button
+ name="enable_voice"
+ label="Enable Voice"
+ top="20"
+ width="95"
+ height="20"
+ left="10"
+ visible="false"
+ commit_callback.function="InspectAvatar.EnableVoice"/>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/en/inspect_object.xml b/indra/newview/skins/minimal/xui/en/inspect_object.xml
new file mode 100644
index 0000000000..f424069ec6
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/inspect_object.xml
@@ -0,0 +1,144 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater
+ legacy_header_height="25"
+ bevel_style="in"
+ bg_opaque_image="Inspector_Background"
+ can_close="false"
+ can_minimize="false"
+ height="150"
+ layout="topleft"
+ name="inspect_object"
+ single_instance="true"
+ sound_flags="0"
+ visible="true"
+ width="228">
+ <string name="Creator">By [CREATOR]</string>
+ <string name="CreatorAndOwner">
+By [CREATOR]
+Owner [OWNER]
+ </string>
+ <string name="Price">L$[AMOUNT]</string>
+ <string name="PriceFree">Free!</string>
+ <string name="Touch">Touch</string>
+ <string name="Sit">Sit</string>
+ <text
+ parse_urls="false"
+ follows="all"
+ font="SansSerifLarge"
+ height="30"
+ left="8"
+ name="object_name"
+ text_color="White"
+ top="6"
+ use_ellipses="true"
+ word_wrap="true"
+ width="220" />
+ <text
+ follows="all"
+ height="50"
+ left="8"
+ name="object_creator"
+ top_pad="6"
+ use_ellipses="true"
+ width="220">
+ by secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
+owner secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
+ </text>
+ <text
+ follows="all"
+ font="SansSerifSmall"
+ font.style="BOLD"
+ height="14"
+ halign="right"
+ right="-5"
+ name="price_text"
+ text_color="white"
+ top="60"
+ font_shadow="none"
+ width="60">
+L$30,000
+ </text>
+ <text
+ clip_partial="true"
+ follows="all"
+ font="SansSerifSmall"
+ height="25"
+ left="8"
+ name="object_description"
+ top="76"
+ use_ellipses="true"
+ width="220"
+ word_wrap="true">
+ </text>
+ <!-- Overlapping buttons for all default actions. Show "Buy" if
+ for sale, "Sit" if can sit, etc. -->
+ <icon
+ name="secure_browsing"
+ image_name="Lock"
+ left="0"
+ visible="false"
+ width="18"
+ height="18"
+ top="103"
+ tool_tip="Secure Browsing"
+ follows="left|top" />
+ <text
+ follows="all"
+ font="SansSerifSmall"
+ height="13"
+ name="object_media_url"
+ width="207"
+ left_pad="2"
+ top_delta="0"
+ max_length = "50"
+ use_ellipses="true">
+ http://www.superdupertest.com
+</text>
+ <button
+ follows="top|left"
+ height="20"
+ label="Take Copy"
+ left_delta="0"
+ name="take_free_copy_btn"
+ top_delta="0"
+ width="80" />
+ <button
+ follows="top|left"
+ height="20"
+ label="Touch"
+ left_delta="0"
+ name="touch_btn"
+ top_delta="0"
+ width="80" />
+ <button
+ follows="top|left"
+ height="20"
+ label="Sit"
+ left_delta="0"
+ name="sit_btn"
+ top_delta="0"
+ width="80" />
+ <button
+ follows="top|left"
+ height="20"
+ label="Open"
+ left_delta="0"
+ name="open_btn"
+ top_delta="0"
+ width="80" />
+
+ <!-- non-overlapping buttons here -->
+ <menu_button
+ follows="top|left"
+ height="20"
+ image_overlay="OptionsMenu_Off"
+ menu_filename="menu_inspect_object_gear.xml"
+ name="gear_btn"
+ right="-5"
+ top_delta="0"
+ width="35" />
+</floater>
diff --git a/indra/newview/skins/minimal/xui/en/main_view.xml b/indra/newview/skins/minimal/xui/en/main_view.xml
new file mode 100644
index 0000000000..45ba785c1f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/main_view.xml
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ follows="left|right|top|bottom"
+ height="768"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ tab_stop="false"
+ name="main_view"
+ width="1024">
+ <panel top="0"
+ follows="all"
+ height="768"
+ mouse_opaque="false"
+ name="login_panel_holder"
+ width="1024"/>
+
+ <layout_stack border_size="0"
+ follows="all"
+ mouse_opaque="false"
+ height="768"
+ name="menu_stack"
+ orientation="vertical"
+ top="0">
+ <layout_panel auto_resize="false"
+ height="30"
+ mouse_opaque="false"
+ name="nav_bar_container"
+ tab_stop="false"
+ min_height="0"
+ width="1024"
+ user_resize="false"
+ visible="true">
+ </layout_panel>
+ <layout_panel auto_resize="true"
+ follows="all"
+ height="500"
+ layout="topleft"
+ mouse_opaque="false"
+ tab_stop="false"
+ name="hud"
+ width="1024">
+ <panel auto_resize="false"
+ follows="all"
+ height="500"
+ top="0"
+ layout="topleft"
+ mouse_opaque="false"
+ tab_stop="false"
+ name="non_side_tray_view"
+ user_resize="false"
+ width="1024">
+
+ <layout_stack border_size="0"
+ bottom="500"
+ follows="all"
+ height="500"
+ left="0"
+ top="0"
+ mouse_opaque="false"
+ name="world_stack"
+ open_time_constant="0.03"
+ close_time_constant="0.03"
+ orientation="vertical">
+ <layout_panel auto_resize="true"
+ follows="all"
+ height="500"
+ layout="topleft"
+ tab_stop="false"
+ mouse_opaque="false"
+ user_resize="false"
+ name="hud container"
+ width="500">
+ <view top="0"
+ follows="all"
+ height="500"
+ left="0"
+ mouse_opaque="false"
+ name="floater_snap_region"
+ width="500"/>
+ <panel follows="left|top"
+ height="0"
+ left="0"
+ mouse_opaque="false"
+ name="topinfo_bar_container"
+ tab_stop="false"
+ top="0"
+ visible="false"
+ width="1024"/>
+ <panel bottom="500"
+ follows="left|right|bottom"
+ height="25"
+ left="0"
+ mouse_opaque="false"
+ tab_stop="false"
+ name="stand_stop_flying_container"
+ visible="false"
+ width="500"/>
+ <panel follows="all"
+ height="500"
+ left="0"
+ mouse_opaque="false"
+ name="floater_view_holder"
+ tab_group="-1"
+ tab_stop="false"
+ top="0"
+ width="500">
+ <floater_view follows="all"
+ height="500"
+ left="0"
+ mouse_opaque="false"
+ name="Floater View"
+ tab_group="-1"
+ tab_stop="false"
+ top="0"
+ width="500"/>
+ </panel>
+ <panel bottom="500"
+ follows="all"
+ height="500"
+ left="0"
+ mouse_opaque="false"
+ name="world_view_rect"
+ top="0"
+ width="500"/>
+ </layout_panel>
+ <layout_panel auto_resize="false"
+ min_height="33"
+ height="33"
+ mouse_opaque="false"
+ name="bottom_tray_container"
+ visible="false"/>
+ <layout_panel auto_resize="false"
+ height="215"
+ mouse_opaque="false"
+ user_resize="false"
+ name="avatar_picker_and_destination_guide_container"
+ visible="false">
+ <panel top="0"
+ height="215"
+ left="0"
+ background_visible="true"
+ width="500"
+ follows="all">
+ <web_browser
+ top="0"
+ height="200"
+ follows="all"
+ name="destination_guide_contents"
+ trusted_content="true"
+ visible="false"/>
+ <web_browser
+ top="0"
+ height="200"
+ follows="all"
+ name="avatar_picker_contents"
+ visible="false"
+ trusted_content="true"/>
+ <button
+ name="close"
+ width="22"
+ height="23"
+ right="-10"
+ top="2"
+ follows="top|right"
+ chrome="true"
+ tab_stop="false"
+ image_unselected="bottomtray_close_off"
+ image_selected="bottomtray_close_press"
+ />
+ </panel>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ <debug_view follows="all"
+ left="0"
+ top="0"
+ mouse_opaque="false"
+ height="500"
+ name="DebugView"
+ width="1024"/>
+ </layout_panel>
+ </layout_stack>
+ <panel mouse_opaque="false"
+ follows="right|top"
+ name="status_bar_container"
+ tab_stop="false"
+ height="30"
+ left="-70"
+ top="0"
+ width="70"
+ visible="false"/>
+ <panel follows="top|bottom"
+ height="500"
+ mouse_opaque="false"
+ tab_stop="false"
+ name="hidden_side_tray"
+ visible="false"
+ width="333">
+ <panel
+ name="side_tray_container"
+ width="333"
+ height="500"/>
+ </panel>
+
+ <panel top="0"
+ follows="all"
+ mouse_opaque="false"
+ left="0"
+ name="snapshot_floater_view_holder"
+ width="1024"
+ height="798">
+ <snapshot_floater_view enabled="false"
+ follows="all"
+ height="768"
+ left="0"
+ mouse_opaque="false"
+ name="Snapshot Floater View"
+ tab_stop="false"
+ top="0"
+ visible="false"
+ width="1024"/>
+ </panel>
+ <panel top="0"
+ follows="all"
+ height="768"
+ mouse_opaque="false"
+ name="popup_holder"
+ class="popup_holder"
+ width="1024">
+ <icon follows="right|bottom"
+ image_name="Resize_Corner"
+ right="-1"
+ name="resize_corner"
+ width="11"
+ bottom="-1"
+ height="11" />
+ </panel>
+ <view top="0"
+ left="0"
+ width="1024"
+ height="768"
+ name="hint_holder"
+ mouse_opaque="false"
+ follows="all"/>
+ <panel top="0"
+ follows="all"
+ height="768"
+ mouse_opaque="true"
+ name="progress_view"
+ filename="panel_progress.xml"
+ class="progress_view"
+ width="1024"
+ visible="false"/>
+ <menu_holder top="0"
+ follows="all"
+ height="768"
+ mouse_opaque="false"
+ name="Menu Holder"
+ width="1024"/>
+ <tooltip_view top="0"
+ follows="all"
+ height="768"
+ mouse_opaque="false"
+ name="tooltip view"
+ tab_group="-2"
+ width="1024"/>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/menu_add_wearable_gear.xml b/indra/newview/skins/minimal/xui/en/menu_add_wearable_gear.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_add_wearable_gear.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_attachment_other.xml b/indra/newview/skins/minimal/xui/en/menu_attachment_other.xml
new file mode 100644
index 0000000000..b55e677276
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_attachment_other.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!-- *NOTE: See also menu_avatar_other.xml -->
+<context_menu
+ layout="topleft"
+ name="Avatar Pie">
+ <menu_item_call
+ label="View Profile"
+ name="Profile...">
+ <menu_item_call.on_click
+ function="ShowAgentProfile"
+ parameter="hit object" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Add Friend"
+ name="Add Friend">
+ <menu_item_call.on_click
+ function="Avatar.AddFriend" />
+ <menu_item_call.on_enable
+ function="Avatar.EnableAddFriend" />
+ </menu_item_call>
+ <menu_item_call
+ label="IM"
+ name="Send IM...">
+ <menu_item_call.on_click
+ function="Avatar.SendIM" />
+ </menu_item_call>
+ <menu_item_separator />
+ <menu_item_call
+ enabled="false"
+ label="Block"
+ name="Avatar Mute">
+ <menu_item_call.on_click
+ function="Avatar.Mute" />
+ <menu_item_call.on_enable
+ function="Avatar.EnableMute" />
+ </menu_item_call>
+ <menu_item_call
+ label="Report"
+ name="abuse">
+ <menu_item_call.on_click
+ function="Avatar.ReportAbuse" />
+ </menu_item_call>
+ <menu_item_call
+ label="Freeze"
+ name="Freeze...">
+ <menu_item_call.on_click
+ function="Avatar.Freeze" />
+ <menu_item_call.on_visible
+ function="Avatar.EnableFreezeEject"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Eject"
+ name="Eject...">
+ <menu_item_call.on_click
+ function="Avatar.Eject" />
+ <menu_item_call.on_visible
+ function="Avatar.EnableFreezeEject"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Debug Textures"
+ name="Debug...">
+ <menu_item_call.on_click
+ function="Avatar.Debug" />
+ <menu_item_call.on_visible
+ function="IsGodCustomerService"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Zoom In"
+ name="Zoom In">
+ <menu_item_call.on_click
+ function="Tools.LookAtSelection"
+ parameter="zoom" />
+ </menu_item_call>
+ <menu_item_separator />
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/en/menu_attachment_self.xml b/indra/newview/skins/minimal/xui/en/menu_attachment_self.xml
new file mode 100644
index 0000000000..542a7dc7dc
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_attachment_self.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Attachment Pie">
+ <menu_item_call
+ enabled="false"
+ label="Touch"
+ layout="topleft"
+ name="Attachment Object Touch">
+ <menu_item_call.on_click
+ function="Object.Touch" />
+ <menu_item_call.on_enable
+ function="Object.EnableTouch"
+ name="EnableTouch"/>
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Detach"
+ layout="topleft"
+ name="Detach">
+ <menu_item_call.on_click
+ function="Attachment.Detach" />
+ <menu_item_call.on_enable
+ function="Attachment.EnableDetach" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/en/menu_avatar_icon.xml b/indra/newview/skins/minimal/xui/en/menu_avatar_icon.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_avatar_icon.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_avatar_other.xml b/indra/newview/skins/minimal/xui/en/menu_avatar_other.xml
new file mode 100644
index 0000000000..b76629f401
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_avatar_other.xml
@@ -0,0 +1,75 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!-- *NOTE: See also menu_attachment_other.xml -->
+<context_menu
+ layout="topleft"
+ name="Avatar Pie">
+ <menu_item_call
+ label="View Profile"
+ name="Profile...">
+ <menu_item_call.on_click
+ function="ShowAgentProfile"
+ parameter="hit object" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Add Friend"
+ name="Add Friend">
+ <menu_item_call.on_click
+ function="Avatar.AddFriend" />
+ <menu_item_call.on_enable
+ function="Avatar.EnableAddFriend" />
+ </menu_item_call>
+ <menu_item_call
+ label="IM"
+ name="Send IM...">
+ <menu_item_call.on_click
+ function="Avatar.SendIM" />
+ </menu_item_call>
+ <menu_item_separator />
+ <menu_item_call
+ enabled="false"
+ label="Block"
+ name="Avatar Mute">
+ <menu_item_call.on_click
+ function="Avatar.Mute" />
+ <menu_item_call.on_enable
+ function="Avatar.EnableMute" />
+ </menu_item_call>
+ <menu_item_call
+ label="Report"
+ name="abuse">
+ <menu_item_call.on_click
+ function="Avatar.ReportAbuse" />
+ </menu_item_call>
+ <menu_item_call
+ label="Freeze"
+ name="Freeze...">
+ <menu_item_call.on_click
+ function="Avatar.Freeze" />
+ <menu_item_call.on_visible
+ function="Avatar.EnableFreezeEject"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Eject"
+ name="Eject...">
+ <menu_item_call.on_click
+ function="Avatar.Eject" />
+ <menu_item_call.on_visible
+ function="Avatar.EnableFreezeEject"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Debug Textures"
+ name="Debug...">
+ <menu_item_call.on_click
+ function="Avatar.Debug" />
+ <menu_item_call.on_visible
+ function="IsGodCustomerService"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Zoom In"
+ name="Zoom In">
+ <menu_item_call.on_click
+ function="Tools.LookAtSelection"
+ parameter="zoom" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/en/menu_avatar_self.xml b/indra/newview/skins/minimal/xui/en/menu_avatar_self.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_avatar_self.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_bottomtray.xml b/indra/newview/skins/minimal/xui/en/menu_bottomtray.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_bottomtray.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_cof_attachment.xml b/indra/newview/skins/minimal/xui/en/menu_cof_attachment.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_cof_attachment.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_cof_body_part.xml b/indra/newview/skins/minimal/xui/en/menu_cof_body_part.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_cof_body_part.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_cof_clothing.xml b/indra/newview/skins/minimal/xui/en/menu_cof_clothing.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_cof_clothing.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_cof_gear.xml b/indra/newview/skins/minimal/xui/en/menu_cof_gear.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_cof_gear.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_edit.xml b/indra/newview/skins/minimal/xui/en/menu_edit.xml
new file mode 100644
index 0000000000..747eb3fc6a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_edit.xml
@@ -0,0 +1,90 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu create_jump_keys="true"
+ label="Edit"
+ name="Edit"
+ visible="false">
+ <menu_item_call
+ label="Undo"
+ name="Undo"
+ shortcut="control|Z">
+ <menu_item_call.on_click
+ function="Edit.Undo" />
+ <menu_item_call.on_enable
+ function="Edit.EnableUndo" />
+ </menu_item_call>
+ <menu_item_call
+ label="Redo"
+ name="Redo"
+ shortcut="control|Y">
+ <menu_item_call.on_click
+ function="Edit.Redo" />
+ <menu_item_call.on_enable
+ function="Edit.EnableRedo" />
+ </menu_item_call>
+ <menu_item_separator/>
+ <menu_item_call
+ label="Cut"
+ name="Cut"
+ shortcut="control|X">
+ <menu_item_call.on_click
+ function="Edit.Cut" />
+ <menu_item_call.on_enable
+ function="Edit.EnableCut" />
+ </menu_item_call>
+ <menu_item_call
+ label="Copy"
+ name="Copy"
+ shortcut="control|C">
+ <menu_item_call.on_click
+ function="Edit.Copy" />
+ <menu_item_call.on_enable
+ function="Edit.EnableCopy" />
+ </menu_item_call>
+ <menu_item_call
+ label="Paste"
+ name="Paste"
+ shortcut="control|V">
+ <menu_item_call.on_click
+ function="Edit.Paste" />
+ <menu_item_call.on_enable
+ function="Edit.EnablePaste" />
+ </menu_item_call>
+ <menu_item_call
+ label="Delete"
+ name="Delete"
+ allow_key_repeat="true"
+ shortcut="Del">
+ <menu_item_call.on_click
+ function="Edit.Delete" />
+ <menu_item_call.on_enable
+ function="Edit.EnableDelete" />
+ </menu_item_call>
+ <menu_item_call
+ label="Duplicate"
+ name="Duplicate"
+ shortcut="control|D">
+ <menu_item_call.on_click
+ function="Edit.Duplicate" />
+ <menu_item_call.on_enable
+ function="Edit.EnableDuplicate" />
+ </menu_item_call>
+ <menu_item_separator/>
+ <menu_item_call
+ label="Select All"
+ name="Select All"
+ shortcut="control|A">
+ <menu_item_call.on_click
+ function="Edit.SelectAll" />
+ <menu_item_call.on_enable
+ function="Edit.EnableSelectAll" />
+ </menu_item_call>
+ <menu_item_call
+ label="Deselect"
+ name="Deselect"
+ shortcut="control|E">
+ <menu_item_call.on_click
+ function="Edit.Deselect" />
+ <menu_item_call.on_enable
+ function="Edit.EnableDeselect" />
+ </menu_item_call>
+</menu> \ No newline at end of file
diff --git a/indra/newview/skins/minimal/xui/en/menu_favorites.xml b/indra/newview/skins/minimal/xui/en/menu_favorites.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_favorites.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_gesture_gear.xml b/indra/newview/skins/minimal/xui/en/menu_gesture_gear.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_gesture_gear.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_group_plus.xml b/indra/newview/skins/minimal/xui/en/menu_group_plus.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_group_plus.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_hide_navbar.xml b/indra/newview/skins/minimal/xui/en/menu_hide_navbar.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_hide_navbar.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_im_well_button.xml b/indra/newview/skins/minimal/xui/en/menu_im_well_button.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_im_well_button.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_imchiclet_adhoc.xml b/indra/newview/skins/minimal/xui/en/menu_imchiclet_adhoc.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_imchiclet_adhoc.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_imchiclet_group.xml b/indra/newview/skins/minimal/xui/en/menu_imchiclet_group.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_imchiclet_group.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_imchiclet_p2p.xml b/indra/newview/skins/minimal/xui/en/menu_imchiclet_p2p.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_imchiclet_p2p.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_inspect_avatar_gear.xml b/indra/newview/skins/minimal/xui/en/menu_inspect_avatar_gear.xml
new file mode 100644
index 0000000000..5a4a059781
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_inspect_avatar_gear.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="utf-8"?>
+<toggleable_menu
+ create_jump_keys="true"
+ layout="topleft"
+ mouse_opaque="false"
+ visible="false"
+ name="Gear Menu">
+ <menu_item_call
+ label="View Profile"
+ enabled="true"
+ name="view_profile">
+ <menu_item_call.on_click
+ function="InspectAvatar.ViewProfile"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Add Friend"
+ name="add_friend">
+ <menu_item_call.on_click
+ function="InspectAvatar.AddFriend"/>
+ <menu_item_call.on_enable
+ function="InspectAvatar.Gear.Enable"/>
+ </menu_item_call>
+ <menu_item_call
+ label="IM"
+ name="im">
+ <menu_item_call.on_click
+ function="InspectAvatar.IM"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Teleport"
+ name="teleport">
+ <menu_item_call.on_click
+ function="InspectAvatar.Teleport"/>
+ <menu_item_call.on_enable
+ function="InspectAvatar.Gear.EnableTeleportOffer"/>
+ </menu_item_call>
+ <menu_item_separator />
+ <menu_item_call
+ label="Block"
+ name="block">
+ <menu_item_call.on_click
+ function="InspectAvatar.ToggleMute"/>
+ <menu_item_call.on_visible
+ function="InspectAvatar.EnableMute" />
+ </menu_item_call>
+ <menu_item_call
+ label="Unblock"
+ name="unblock">
+ <menu_item_call.on_click
+ function="InspectAvatar.ToggleMute"/>
+ <menu_item_call.on_visible
+ function="InspectAvatar.EnableUnmute" />
+ </menu_item_call>
+ <menu_item_call
+ label="Report"
+ name="report">
+ <menu_item_call.on_click
+ function="InspectAvatar.Report"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Freeze"
+ name="freeze">
+ <menu_item_call.on_click
+ function="InspectAvatar.Freeze"/>
+ <menu_item_call.on_visible
+ function="InspectAvatar.VisibleFreeze"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Eject"
+ name="eject">
+ <menu_item_call.on_click
+ function="InspectAvatar.Eject"/>
+ <menu_item_call.on_visible
+ function="InspectAvatar.VisibleEject"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Kick"
+ name="kick">
+ <menu_item_call.on_click
+ function="InspectAvatar.Kick"/>
+ <menu_item_call.on_visible
+ function="InspectAvatar.EnableGod"/>
+ </menu_item_call>
+ <menu_item_call
+ label="CSR"
+ name="csr">
+ <menu_item_call.on_click
+ function="InspectAvatar.CSR" />
+ <menu_item_call.on_visible
+ function="InspectAvatar.EnableGod" />
+ </menu_item_call>
+ <menu_item_call
+ label="Debug Textures"
+ name="debug">
+ <menu_item_call.on_click
+ function="Avatar.Debug"/>
+ <menu_item_call.on_visible
+ function="IsGodCustomerService"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Find On Map"
+ name="find_on_map">
+ <menu_item_call.on_click
+ function="InspectAvatar.FindOnMap"/>
+ <menu_item_call.on_visible
+ function="InspectAvatar.VisibleFindOnMap"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Zoom In"
+ name="zoom_in">
+ <menu_item_call.on_click
+ function="InspectAvatar.ZoomIn"/>
+ <menu_item_call.on_visible
+ function="InspectAvatar.VisibleZoomIn"/>
+ </menu_item_call>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/en/menu_inspect_object_gear.xml b/indra/newview/skins/minimal/xui/en/menu_inspect_object_gear.xml
new file mode 100644
index 0000000000..8ec360a604
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_inspect_object_gear.xml
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="utf-8"?>
+<toggleable_menu
+ create_jump_keys="true"
+ layout="topleft"
+ mouse_opaque="false"
+ visible="false"
+ name="Gear Menu">
+ <menu_item_call
+ label="Touch"
+ layout="topleft"
+ enabled="true"
+ name="touch">
+ <menu_item_call.on_click
+ function="InspectObject.Touch"/>
+ <menu_item_call.on_visible
+ function="Object.EnableTouch" />
+ </menu_item_call>
+ <menu_item_call
+ label="Sit"
+ layout="topleft"
+ name="sit">
+ <menu_item_call.on_click
+ function="InspectObject.Sit"/>
+ <menu_item_call.on_visible
+ function="Object.EnableSit"/>
+ </menu_item_call>
+ <menu_item_call
+ label="Report"
+ layout="topleft"
+ name="report">
+ <menu_item_call.on_click
+ function="Object.ReportAbuse" />
+ </menu_item_call>
+ <menu_item_call
+ label="Block"
+ layout="topleft"
+ name="block">
+ <menu_item_call.on_click
+ function="Object.Mute" />
+ <menu_item_call.on_visible
+ function="Object.EnableMute" />
+ </menu_item_call>
+ <menu_item_call
+ label="Zoom In"
+ layout="topleft"
+ name="zoom_in">
+ <menu_item_call.on_click
+ function="InspectObject.ZoomIn" />
+ </menu_item_call>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/en/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/en/menu_inspect_self_gear.xml
new file mode 100644
index 0000000000..ae8b640d26
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_inspect_self_gear.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu
+ layout="topleft"
+ name="Self Pie">
+ <menu_item_call
+ label="Sit Down"
+ layout="topleft"
+ name="Sit Down Here">
+ <menu_item_call.on_click
+ function="Self.SitDown"
+ parameter="" />
+ <menu_item_call.on_enable
+ function="Self.EnableSitDown" />
+ </menu_item_call>
+ <menu_item_call
+ label="Stand Up"
+ layout="topleft"
+ name="Stand Up">
+ <menu_item_call.on_click
+ function="Self.StandUp"
+ parameter="" />
+ <menu_item_call.on_enable
+ function="Self.EnableStandUp" />
+ </menu_item_call>
+ <menu_item_call
+ label="My Friends"
+ layout="topleft"
+ name="Friends...">
+ <menu_item_call.on_click
+ function="SideTray.PanelPeopleTab"
+ parameter="friends_panel" />
+ </menu_item_call>
+ <menu_item_call
+ label="My Profile"
+ layout="topleft"
+ name="Profile...">
+ <menu_item_call.on_click
+ function="ShowAgentProfile"
+ parameter="agent" />
+ </menu_item_call>
+ <menu_item_call
+ label="Debug Textures"
+ name="Debug...">
+ <menu_item_call.on_click
+ function="Avatar.Debug" />
+ <menu_item_call.on_visible
+ function="IsGodCustomerService"/>
+ </menu_item_call>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/en/menu_inv_offer_chiclet.xml b/indra/newview/skins/minimal/xui/en/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_inv_offer_chiclet.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_inventory.xml b/indra/newview/skins/minimal/xui/en/menu_inventory.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_inventory.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_inventory_add.xml b/indra/newview/skins/minimal/xui/en/menu_inventory_add.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_inventory_add.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_inventory_gear_default.xml b/indra/newview/skins/minimal/xui/en/menu_inventory_gear_default.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_inventory_gear_default.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_land.xml b/indra/newview/skins/minimal/xui/en/menu_land.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_land.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_landmark.xml b/indra/newview/skins/minimal/xui/en/menu_landmark.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_landmark.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_login.xml b/indra/newview/skins/minimal/xui/en/menu_login.xml
new file mode 100644
index 0000000000..62dbce3f56
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_login.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu_bar/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_mini_map.xml b/indra/newview/skins/minimal/xui/en/menu_mini_map.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_mini_map.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_navbar.xml b/indra/newview/skins/minimal/xui/en/menu_navbar.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_navbar.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_nearby_chat.xml b/indra/newview/skins/minimal/xui/en/menu_nearby_chat.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_nearby_chat.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_notification_well_button.xml b/indra/newview/skins/minimal/xui/en/menu_notification_well_button.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_notification_well_button.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_object.xml b/indra/newview/skins/minimal/xui/en/menu_object.xml
new file mode 100644
index 0000000000..888ce42cf1
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_object.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Object Pie">
+ <menu_item_call
+ enabled="false"
+ label="Sit Here"
+ name="Object Sit">
+ <menu_item_call.on_click
+ function="Object.SitOrStand" />
+ <menu_item_call.on_enable
+ function="Object.EnableSit" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Stand Up"
+ name="Object Stand Up">
+ <menu_item_call.on_click
+ function="Object.SitOrStand" />
+ <menu_item_call.on_enable
+ function="Object.EnableStandUp" />
+ </menu_item_call>
+ <menu_item_call
+ label="Zoom In"
+ name="Zoom In">
+ <menu_item_call.on_click
+ function="Object.ZoomIn" />
+ </menu_item_call>
+ <menu_item_call
+ enabled="false"
+ label="Touch"
+ name="Object Touch">
+ <menu_item_call.on_click
+ function="Object.Touch" />
+ <menu_item_call.on_enable
+ function="Object.EnableTouch"
+ name="EnableTouch"
+ parameter="Touch" />
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/en/menu_object_icon.xml b/indra/newview/skins/minimal/xui/en/menu_object_icon.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_object_icon.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_outfit_gear.xml b/indra/newview/skins/minimal/xui/en/menu_outfit_gear.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_outfit_gear.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_outfit_tab.xml b/indra/newview/skins/minimal/xui/en/menu_outfit_tab.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_outfit_tab.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_participant_list.xml b/indra/newview/skins/minimal/xui/en/menu_participant_list.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_participant_list.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_people_friends_view_sort.xml b/indra/newview/skins/minimal/xui/en/menu_people_friends_view_sort.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_people_friends_view_sort.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_people_groups.xml b/indra/newview/skins/minimal/xui/en/menu_people_groups.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_people_groups.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_people_groups_view_sort.xml b/indra/newview/skins/minimal/xui/en/menu_people_groups_view_sort.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_people_groups_view_sort.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_people_nearby.xml b/indra/newview/skins/minimal/xui/en/menu_people_nearby.xml
new file mode 100644
index 0000000000..3d64133f54
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_people_nearby.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu
+ layout="topleft"
+ name="Avatar Context Menu">
+ <menu_item_call
+ label="View Profile"
+ layout="topleft"
+ name="View Profile">
+ <menu_item_call.on_click
+ function="Avatar.Profile" />
+ </menu_item_call>
+ <menu_item_call
+ label="Add Friend"
+ layout="topleft"
+ name="Add Friend">
+ <menu_item_call.on_click
+ function="Avatar.AddFriend" />
+ <menu_item_call.on_enable
+ function="Avatar.EnableItem"
+ parameter="can_add" />
+ </menu_item_call>
+ <menu_item_call
+ label="Remove Friend"
+ layout="topleft"
+ name="Remove Friend">
+ <menu_item_call.on_click
+ function="Avatar.RemoveFriend" />
+ <menu_item_call.on_enable
+ function="Avatar.EnableItem"
+ parameter="can_delete" />
+ </menu_item_call>
+ <menu_item_call
+ label="IM"
+ layout="topleft"
+ name="IM">
+ <menu_item_call.on_click
+ function="Avatar.IM" />
+ </menu_item_call>
+ <menu_item_check
+ label="Block/Unblock"
+ layout="topleft"
+ name="Block/Unblock">
+ <menu_item_check.on_click
+ function="Avatar.BlockUnblock" />
+ <menu_item_check.on_check
+ function="Avatar.CheckItem"
+ parameter="is_blocked" />
+ <menu_item_check.on_enable
+ function="Avatar.EnableItem"
+ parameter="can_block" />
+ </menu_item_check>
+ <menu_item_call
+ label="Offer Teleport"
+ name="teleport">
+ <menu_item_call.on_click
+ function="Avatar.OfferTeleport"/>
+ <menu_item_call.on_enable
+ function="Avatar.EnableItem"
+ parameter="can_offer_teleport"/>
+ </menu_item_call>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/en/menu_people_nearby_multiselect.xml b/indra/newview/skins/minimal/xui/en/menu_people_nearby_multiselect.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_people_nearby_multiselect.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_people_nearby_view_sort.xml b/indra/newview/skins/minimal/xui/en/menu_people_nearby_view_sort.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_people_nearby_view_sort.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_people_recent_view_sort.xml b/indra/newview/skins/minimal/xui/en/menu_people_recent_view_sort.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_people_recent_view_sort.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_picks.xml b/indra/newview/skins/minimal/xui/en/menu_picks.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_picks.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_picks_plus.xml b/indra/newview/skins/minimal/xui/en/menu_picks_plus.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_picks_plus.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_place.xml b/indra/newview/skins/minimal/xui/en/menu_place.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_place.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_place_add_button.xml b/indra/newview/skins/minimal/xui/en/menu_place_add_button.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_place_add_button.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_places_gear_folder.xml b/indra/newview/skins/minimal/xui/en/menu_places_gear_folder.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_places_gear_folder.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_places_gear_landmark.xml b/indra/newview/skins/minimal/xui/en/menu_places_gear_landmark.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_places_gear_landmark.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_profile_overflow.xml b/indra/newview/skins/minimal/xui/en/menu_profile_overflow.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_profile_overflow.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_save_outfit.xml b/indra/newview/skins/minimal/xui/en/menu_save_outfit.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_save_outfit.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_script_chiclet.xml b/indra/newview/skins/minimal/xui/en/menu_script_chiclet.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_script_chiclet.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_slurl.xml b/indra/newview/skins/minimal/xui/en/menu_slurl.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_slurl.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_teleport_history_gear.xml b/indra/newview/skins/minimal/xui/en/menu_teleport_history_gear.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_teleport_history_gear.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_teleport_history_item.xml b/indra/newview/skins/minimal/xui/en/menu_teleport_history_item.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_teleport_history_item.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_teleport_history_tab.xml b/indra/newview/skins/minimal/xui/en/menu_teleport_history_tab.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_teleport_history_tab.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_text_editor.xml b/indra/newview/skins/minimal/xui/en/menu_text_editor.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_text_editor.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_topinfobar.xml b/indra/newview/skins/minimal/xui/en/menu_topinfobar.xml
new file mode 100644
index 0000000000..9ebab9ef98
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_topinfobar.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_url_agent.xml b/indra/newview/skins/minimal/xui/en/menu_url_agent.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_url_agent.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_url_group.xml b/indra/newview/skins/minimal/xui/en/menu_url_group.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_url_group.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_url_http.xml b/indra/newview/skins/minimal/xui/en/menu_url_http.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_url_http.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_url_inventory.xml b/indra/newview/skins/minimal/xui/en/menu_url_inventory.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_url_inventory.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_url_map.xml b/indra/newview/skins/minimal/xui/en/menu_url_map.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_url_map.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_url_objectim.xml b/indra/newview/skins/minimal/xui/en/menu_url_objectim.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_url_objectim.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_url_parcel.xml b/indra/newview/skins/minimal/xui/en/menu_url_parcel.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_url_parcel.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_url_slapp.xml b/indra/newview/skins/minimal/xui/en/menu_url_slapp.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_url_slapp.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_url_slurl.xml b/indra/newview/skins/minimal/xui/en/menu_url_slurl.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_url_slurl.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_url_teleport.xml b/indra/newview/skins/minimal/xui/en/menu_url_teleport.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_url_teleport.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_viewer.xml b/indra/newview/skins/minimal/xui/en/menu_viewer.xml
new file mode 100644
index 0000000000..cd83ea4e99
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_viewer.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<menu_bar
+ bg_visible="false"
+ follows="left|top|right"
+ name="Main Menu">
+ <menu
+ create_jump_keys="true"
+ label="Help"
+ name="Help"
+ tear_off="true">
+ <menu_item_call
+ label="[SECOND_LIFE] Help"
+ name="Second Life Help"
+ shortcut="F1">
+ <menu_item_call.on_click
+ function="ShowHelp"
+ parameter="f1_help" />
+ </menu_item_call>
+ </menu>
+ <menu
+ create_jump_keys="true"
+ label="Advanced"
+ name="Advanced"
+ tear_off="true"
+ visible="false">
+ <menu
+ create_jump_keys="true"
+ label="Shortcuts"
+ name="Shortcuts"
+ tear_off="true"
+ visible="false">
+ <menu_item_check
+ label="Fly"
+ name="Fly"
+ shortcut="Home">
+ <menu_item_check.on_check
+ function="Agent.getFlying" />
+ <menu_item_check.on_click
+ function="Agent.toggleFlying" />
+ <menu_item_check.on_enable
+ function="Agent.enableFlying" />
+ </menu_item_check>
+ <menu_item_call
+ label="Close Window"
+ name="Close Window"
+ shortcut="control|W">
+ <menu_item_call.on_click
+ function="File.CloseWindow" />
+ <menu_item_call.on_enable
+ function="File.EnableCloseWindow" />
+ </menu_item_call>
+ <menu_item_call
+ label="Close All Windows"
+ name="Close All Windows"
+ shortcut="control|shift|W">
+ <menu_item_call.on_click
+ function="File.CloseAllWindows" />
+ <menu_item_call.on_enable
+ function="File.EnableCloseAllWindows" />
+ </menu_item_call>
+
+ <menu_item_call
+ label="Reset View"
+ name="Reset View"
+ shortcut="Esc">
+ <menu_item_call.on_click
+ function="View.ResetView" />
+ </menu_item_call>
+ </menu> <!--Shortcuts-->
+ </menu>
+</menu_bar>
diff --git a/indra/newview/skins/minimal/xui/en/menu_wearable_list_item.xml b/indra/newview/skins/minimal/xui/en/menu_wearable_list_item.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_wearable_list_item.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_wearing_gear.xml b/indra/newview/skins/minimal/xui/en/menu_wearing_gear.xml
new file mode 100644
index 0000000000..28c4762eaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_wearing_gear.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<toggleable_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/menu_wearing_tab.xml b/indra/newview/skins/minimal/xui/en/menu_wearing_tab.xml
new file mode 100644
index 0000000000..fb19c5eb2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/menu_wearing_tab.xml
@@ -0,0 +1,2 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<context_menu/>
diff --git a/indra/newview/skins/minimal/xui/en/notification_visibility.xml b/indra/newview/skins/minimal/xui/en/notification_visibility.xml
new file mode 100644
index 0000000000..616b544847
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/notification_visibility.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" ?>
+<notification_visibility>
+ <respond name="VoiceInviteP2P" response="Decline"/>
+ <respond name="VoiceInviteAdHoc" response="Decline"/>
+ <respond name="VoiceInviteGroup" response="Decline"/>
+
+ <!-- group and voice are disabled features -->
+ <hide tag="group"/>
+ <hide tag="voice"/>
+
+ <!-- no spammy scripts -->
+ <!-- <hide name="ScriptDialog"/> -->
+
+ <!-- hints pertaining to UI we don't show -->
+ <hide name="FirstBalanceIncrease"/>
+ <hide name="FirstInventory"/>
+ <hide name="HintSidePanel"/>
+ <hide name="HintMove"/>
+ <hide name="HintDisplayName"/>
+ <hide name="HintInventory"/>
+ <hide name="HintLindenDollar"/>
+
+ <!-- spam from servers, such as "Autopilot cancelled" -->
+ <hide name="SystemMessageTip"/>
+
+ <!-- show everything else -->
+ <show/>
+</notification_visibility>
+
diff --git a/indra/newview/skins/minimal/xui/en/notifications.xml b/indra/newview/skins/minimal/xui/en/notifications.xml
new file mode 100644
index 0000000000..84da9472cc
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/notifications.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" ?>
+<notifications>
+ <notification
+ icon="notify.tga"
+ name="UserGiveItem"
+ type="offer">
+ [NAME_SLURL] is offering you [ITEM_SLURL]. Using this item requires you to switch to Advanced mode where you will find the item in your Inventory. To switch to Advanced mode, quit and restart this application and change the mode setting on the login screen.
+ <form name="form">
+ <button
+ index="4"
+ name="Show"
+ text="Keep Item"/>
+ <button
+ index="1"
+ name="Discard"
+ text="Reject Item"/>
+ <button
+ index="2"
+ name="Mute"
+ text="Block User"/>
+ </form>
+ </notification>
+ <notification
+ icon="notify.tga"
+ name="ObjectGiveItem"
+ type="offer">
+ An object named &lt;nolink&gt;[OBJECTFROMNAME]&lt;/nolink&gt; owned by [NAME_SLURL] is offering you [ITEM_SLURL]. Using this item requires you to switch to Advanced mode where you will find the item in your Inventory. To switch to Advanced mode, quit and restart this application and change the mode setting on the login screen.
+ <form name="form">
+ <button
+ index="0"
+ name="Keep"
+ text="Keep Item"/>
+ <button
+ index="1"
+ name="Discard"
+ text="Reject Item"/>
+ <button
+ index="2"
+ name="Mute"
+ text="Block Object"/>
+ </form>
+ </notification>
+
+</notifications>
diff --git a/indra/newview/skins/minimal/xui/en/panel_adhoc_control_panel.xml b/indra/newview/skins/minimal/xui/en/panel_adhoc_control_panel.xml
new file mode 100644
index 0000000000..5730adab8a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/panel_adhoc_control_panel.xml
@@ -0,0 +1,46 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ border="false"
+ follows="all"
+ height="215"
+ name="panel_im_control_panel"
+ width="150">
+ <layout_stack
+ mouse_opaque="false"
+ border_size="0"
+ clip="false"
+ follows="all"
+ height="215"
+ layout="topleft"
+ left="3"
+ name="vertical_stack"
+ orientation="vertical"
+ top="0"
+ width="147">
+ <layout_panel
+ auto_resize="true"
+ follows="top|left"
+ height="130"
+ layout="topleft"
+ left="0"
+ min_height="0"
+ mouse_opaque="false"
+ width="147"
+ top="0"
+ name="speakers_list_panel"
+ user_resize="false">
+ <avatar_list
+ color="DkGray2"
+ follows="all"
+ height="130"
+ ignore_online_status="true"
+ layout="topleft"
+ name="speakers_list"
+ opaque="false"
+ show_info_btn="true"
+ show_profile_btn="false"
+ show_speaking_indicator="false"
+ width="147" />
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml
new file mode 100644
index 0000000000..0145de8be9
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/panel_bottomtray.xml
@@ -0,0 +1,483 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ bg_opaque_color="DkGray"
+ chrome="true"
+ follows="left|bottom|right"
+ height="33"
+ layout="topleft"
+ left="0"
+ name="bottom_tray"
+ focus_root="true"
+ top="28"
+ width="1310">
+ <string
+ name="DragIndicationImageName"
+ value="Accordion_ArrowOpened_Off" />
+ <string
+ name="SpeakBtnToolTip"
+ value="Turns microphone on/off" />
+ <string
+ name="VoiceControlBtnToolTip"
+ value="Shows/hides voice control panel" />
+ <layout_stack
+ border_size="0"
+ clip="false"
+ follows="all"
+ height="28"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="toolbar_stack"
+ orientation="horizontal"
+ top="0"
+ width="1310">
+ <layout_panel
+ auto_resize="false"
+ user_resize="false"
+ min_width="2"
+ width="2" />
+ <layout_panel
+ auto_resize="false"
+ layout="topleft"
+ max_width="320"
+ min_width="214"
+ height="28"
+ mouse_opaque="false"
+ name="chat_bar_layout_panel"
+ user_resize="true"
+ width="308" >
+ <panel
+ name="chat_bar"
+ filename="panel_nearby_chat_bar.xml"
+ left="0"
+ height="28"
+ width="306"
+ top="0"
+ mouse_opaque="false"
+ follows="left|right"
+ />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="65"
+ mouse_opaque="false"
+ name="gesture_panel"
+ top_delta="0"
+ user_resize="false"
+ width="85">
+ <gesture_combo_list
+ follows="left|right"
+ height="23"
+ label="Gesture"
+ layout="topleft"
+ get_more="false"
+ view_all="false"
+ left="0"
+ name="Gesture"
+ tool_tip="Shows/hides gestures"
+ top="5"
+ width="82">
+ <combo_button
+ pad_right="10"
+ can_drag="false"
+ use_ellipses="true" />
+ <combo_list
+ page_lines="17" />
+ </gesture_combo_list>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="52"
+ mouse_opaque="false"
+ name="cam_panel"
+ user_resize="false"
+ width="83">
+ <bottomtray_button
+ can_drag="false"
+ follows="left|right"
+ height="23"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
+ is_toggle="true"
+ label="View"
+ layout="topleft"
+ left="0"
+ name="camera_btn"
+ tool_tip="Shows/hides camera controls"
+ top="5"
+ use_ellipses="true"
+ width="80">
+ <init_callback
+ function="Button.SetDockableFloaterToggle"
+ parameter="camera" />
+ </bottomtray_button>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_width="17"
+ name="splitter_panel"
+ user_resize="false"
+ width="17">
+ <icon
+ follows="left|bottom"
+ height="18"
+ width="2"
+ left="6"
+ image_name="Button_Separator"
+ name="separator"
+ top="7"/>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="83"
+ mouse_opaque="false"
+ name="avatar_and_destinations_panel"
+ user_resize="false"
+ width="103">
+ <bottomtray_button
+ can_drag="false"
+ follows="left|right"
+ height="23"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
+ label="Destinations"
+ layout="topleft"
+ left="0"
+ name="destination_btn"
+ tool_tip="Shows people window"
+ top="5"
+ is_toggle="true"
+ use_ellipses="true"
+ width="100">
+ <bottomtray_button.commit_callback
+ function="Destination.show" />
+ </bottomtray_button>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="73"
+ mouse_opaque="false"
+ name="avatar_and_destinations_panel"
+ user_resize="false"
+ width="103">
+ <bottomtray_button
+ can_drag="false"
+ follows="left|right"
+ height="23"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
+ label="My Avatar"
+ layout="topleft"
+ left="0"
+ name="avatar_btn"
+ top="5"
+ is_toggle="true"
+ use_ellipses="true"
+ width="100">
+ <bottomtray_button.commit_callback
+ function="Avatar.show" />
+ </bottomtray_button>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="left|right"
+ height="28"
+ layout="topleft"
+ min_width="17"
+ name="splitter_panel"
+ user_resize="false"
+ width="17">
+ <icon
+ follows="left|bottom"
+ height="18"
+ width="2"
+ left="6"
+ image_name="Button_Separator"
+ name="separator"
+ top="7"/>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="65"
+ mouse_opaque="false"
+ name="people_panel"
+ top_delta="0"
+ user_resize="false"
+ width="105">
+ <bottomtray_button
+ can_drag="false"
+ follows="left|right"
+ height="23"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
+ label="People"
+ layout="topleft"
+ left="0"
+ name="show_people_button"
+ tool_tip="Shows people window"
+ top="5"
+ is_toggle="true"
+ use_ellipses="true"
+ width="100">
+ <bottomtray_button.commit_callback
+ function="ShowSidetrayPanel"
+ parameter="panel_people" />
+ </bottomtray_button>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="65"
+ mouse_opaque="false"
+ name="profile_panel"
+ top_delta="0"
+ user_resize="false"
+ width="105">
+ <bottomtray_button
+ can_drag="false"
+ follows="left|right"
+ height="23"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
+ label="Profile"
+ layout="topleft"
+ left="0"
+ name="show_profile_btn"
+ tool_tip="Shows profile window"
+ is_toggle="true"
+ top="5"
+ use_ellipses="true"
+ width="100">
+ <bottomtray_button.commit_callback
+ function="ToggleAgentProfile"
+ parameter="agent"/>
+ </bottomtray_button>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="65"
+ mouse_opaque="false"
+ name="howto_panel"
+ top_delta="0"
+ user_resize="false"
+ width="105">
+ <bottomtray_button
+ can_drag="false"
+ follows="left|right"
+ height="23"
+ image_pressed="PushButton_Press"
+ image_pressed_selected="PushButton_Selected_Press"
+ image_selected="PushButton_Selected_Press"
+ label="How To"
+ layout="topleft"
+ left="0"
+ name="show_help_btn"
+ tool_tip="Open Second Life How To topics"
+ is_toggle="true"
+ top="5"
+ use_ellipses="true"
+ width="100">
+ <bottomtray_button.commit_callback
+ function="ToggleHelp"
+ parameter="f1_help" />
+ </bottomtray_button>
+ </layout_panel>
+ <layout_panel
+ follows="left|right"
+ height="30"
+ layout="topleft"
+ min_width="95"
+ mouse_opaque="false"
+ name="chiclet_list_panel"
+ top="0"
+ user_resize="false"
+ width="189">
+ <!--*NOTE: min_width of the chiclet_panel (chiclet_list) must be the same
+as for parent layout_panel (chiclet_list_panel) to resize bottom tray properly. EXT-991-->
+ <chiclet_panel
+ chiclet_padding="4"
+ follows="left|right"
+ height="24"
+ layout="topleft"
+ left="1"
+ min_width="95"
+ mouse_opaque="false"
+ name="chiclet_list"
+ top="7"
+ width="189">
+ <button
+ auto_resize="true"
+ follows="right"
+ height="29"
+ image_hover_selected="SegmentedBtn_Left_Over"
+ image_hover_unselected="SegmentedBtn_Left_Over"
+ image_overlay="Arrow_Small_Left"
+ image_pressed="SegmentedBtn_Left_Press"
+ image_pressed_selected="SegmentedBtn_Left_Press"
+ image_selected="SegmentedBtn_Left_Off"
+ image_unselected="SegmentedBtn_Left_Off"
+ layout="topleft"
+ name="chicklet_left_scroll_button"
+ tab_stop="false"
+ top="-28"
+ visible="false"
+ width="7" />
+ <button
+ auto_resize="true"
+ follows="right"
+ height="29"
+ image_hover_selected="SegmentedBtn_Right_Over"
+ image_hover_unselected="SegmentedBtn_Right_Over"
+ image_overlay="Arrow_Small_Right"
+ image_pressed="SegmentedBtn_Right_Press"
+ image_pressed_selected="SegmentedBtn_Right_Press"
+ image_selected="SegmentedBtn_Right_Off"
+ image_unselected="SegmentedBtn_Right_Off"
+ layout="topleft"
+ name="chicklet_right_scroll_button"
+ tab_stop="false"
+ top="-28"
+ visible="false"
+ width="7" />
+ </chiclet_panel>
+ </layout_panel>
+ <layout_panel auto_resize="false"
+ user_resize="false"
+ width="4"
+ min_width="4"/>
+ <layout_panel
+ auto_resize="false"
+ follows="right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="37"
+ name="im_well_panel"
+ top="0"
+ user_resize="false"
+ width="37">
+ <chiclet_im_well
+ follows="right"
+ height="28"
+ layout="topleft"
+ left="0"
+ max_displayed_count="99"
+ name="im_well"
+ top="0"
+ width="35">
+ <!--
+Emulate 4 states of button by background images, see details in EXT-3147. The same should be for notification_well button
+xml attribute Description
+image_unselected "Unlit" - there are no new messages
+image_selected "Unlit" + "Selected" - there are no new messages and the Well is open
+image_pressed "Lit" - there are new messages
+image_pressed_selected "Lit" + "Selected" - there are new messages and the Well is open
+ -->
+ <button
+ auto_resize="true"
+ follows="right"
+ halign="center"
+ height="23"
+ image_overlay="Unread_IM"
+ image_overlay_alignment="center"
+ image_pressed="WellButton_Lit"
+ image_pressed_selected="WellButton_Lit_Selected"
+ image_selected="PushButton_Press"
+ label_color="Black"
+ left="0"
+ name="Unread IM messages"
+ tool_tip="Conversations"
+ width="34">
+ <init_callback
+ function="Button.SetDockableFloaterToggle"
+ parameter="im_well_window" />
+ </button>
+ </chiclet_im_well>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ min_width="37"
+ name="notification_well_panel"
+ top="0"
+ user_resize="false"
+ width="37">
+ <chiclet_notification
+ follows="right"
+ height="23"
+ layout="topleft"
+ left="0"
+ max_displayed_count="99"
+ name="notification_well"
+ top="5"
+ width="35">
+ <button
+ auto_resize="true"
+ bottom_pad="3"
+ follows="right"
+ halign="center"
+ height="23"
+ image_overlay="Notices_Unread"
+ image_overlay_alignment="center"
+ image_pressed="WellButton_Lit"
+ image_pressed_selected="WellButton_Lit_Selected"
+ image_selected="PushButton_Press"
+ label_color="Black"
+ left="0"
+ name="Unread"
+ tool_tip="Notifications"
+ width="34">
+ <init_callback
+ function="Button.SetDockableFloaterToggle"
+ parameter="notification_well_window" />
+ </button>
+ </chiclet_notification>
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ user_resize="false"
+ min_width="4"
+ name="DUMMY2"
+ width="8" />
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/panel_group_control_panel.xml b/indra/newview/skins/minimal/xui/en/panel_group_control_panel.xml
new file mode 100644
index 0000000000..abddc59296
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/panel_group_control_panel.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ border="false"
+ follows="all"
+ height="238"
+ name="panel_im_control_panel"
+ width="150">
+ <layout_stack
+ mouse_opaque="false"
+ border_size="0"
+ clip="false"
+ follows="all"
+ height="238"
+ layout="topleft"
+ left="5"
+ name="vertical_stack"
+ orientation="vertical"
+ top="0"
+ width="145">
+ <layout_panel
+ auto_resize="true"
+ follows="top|left"
+ height="100"
+ layout="topleft"
+ min_height="0"
+ mouse_opaque="false"
+ width="145"
+ top="0"
+ name="speakers_list_panel"
+ user_resize="false">
+ <avatar_list
+ color="DkGray2"
+ follows="all"
+ height="100"
+ ignore_online_status="true"
+ layout="topleft"
+ name="speakers_list"
+ opaque="false"
+ show_info_btn="true"
+ show_profile_btn="false"
+ show_speaking_indicator="false"
+ width="145" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="top|left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ width="130"
+ name="end_call_btn_panel"
+ user_resize="false"
+ visible="false">
+ <button
+ follows="all"
+ height="23"
+ label="Leave Call"
+ name="end_call_btn"
+ use_ellipses="true" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ follows="top|left|right"
+ height="28"
+ layout="topleft"
+ min_height="28"
+ width="130"
+ name="voice_ctrls_btn_panel"
+ user_resize="false"
+ visible="false">
+ <button
+ follows="all"
+ height="23"
+ label="Open Voice Controls"
+ name="voice_ctrls_btn"
+ use_ellipses="true" />
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/panel_im_control_panel.xml b/indra/newview/skins/minimal/xui/en/panel_im_control_panel.xml
new file mode 100644
index 0000000000..53def54aca
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/panel_im_control_panel.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ border="false"
+ height="300"
+ name="panel_im_control_panel"
+ width="150">
+ <avatar_icon
+ follows="left|top"
+ height="105"
+ left_delta="20"
+ name="avatar_icon"
+ top="-5"
+ width="114"/>
+ <layout_stack
+ mouse_opaque="false"
+ border_size="0"
+ clip="false"
+ follows="all"
+ height="183"
+ layout="topleft"
+ left="5"
+ name="button_stack"
+ orientation="vertical"
+ top_pad="5"
+ width="145">
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/panel_login.xml b/indra/newview/skins/minimal/xui/en/panel_login.xml
new file mode 100644
index 0000000000..ef058e5567
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/panel_login.xml
@@ -0,0 +1,206 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+follows="all"
+height="600"
+layout="topleft"
+left="0"
+name="panel_login"
+focus_root="true"
+top="600"
+ width="996">
+<panel.string
+ name="create_account_url">
+ http://join.secondlife.com/
+</panel.string>
+<string name="reg_in_client_url" translate="false">
+ http://secondlife.eniac15.lindenlab.com/reg-in-client/
+</string>
+<panel.string
+ name="forgot_password_url">
+ http://secondlife.com/account/request.php
+</panel.string>
+<!-- *NOTE: Custom resize logic for login_html in llpanellogin.cpp -->
+<web_browser
+ tab_stop="false"
+trusted_content="true"
+bg_opaque_color="Black"
+border_visible="false"
+bottom="600"
+follows="all"
+hide_loading="true"
+left="0"
+name="login_html"
+start_url=""
+top="0"
+height="600"
+ width="980" />
+<layout_stack
+follows="left|bottom|right"
+name="login_widgets"
+layout="topleft"
+orientation="horizontal"
+top="519"
+width="996"
+height="80">
+<layout_panel
+auto_resize="false"
+follows="left|bottom"
+name="login"
+layout="topleft"
+width="570"
+min_width="570"
+user_resize="false"
+height="80">
+<text
+follows="left|bottom"
+font="SansSerifSmall"
+height="16"
+name="username_text"
+top="20"
+left="20"
+width="150">
+Username:
+</text>
+ <combo_box
+ allow_text_entry="true"
+ follows="left|bottom"
+ height="22"
+ left_delta="0"
+ max_chars="128"
+ combo_editor.prevalidate_callback="ascii"
+ tool_tip="The username you chose when you registered, like bobsmith12 or Steller Sunshine"
+ top_pad="0"
+ name="username_combo"
+ width="178">
+ <combo_box.combo_button
+ visible ="false"/>
+ <combo_box.drop_down_button
+ visible ="false"/>
+ </combo_box>
+<text
+follows="left|bottom"
+font="SansSerifSmall"
+height="15"
+left_pad="-19"
+name="password_text"
+top="20"
+ width="150">
+ Password:
+</text>
+<line_editor
+follows="left|bottom"
+ height="22"
+left_delta="0"
+ max_length_bytes="16"
+name="password_edit"
+is_password="true"
+select_on_focus="true"
+ top_pad="0"
+ width="135" />
+ <check_box
+control_name="RememberPassword"
+follows="left|bottom"
+font="SansSerifSmall"
+height="16"
+label="Remember password"
+ top_pad="3"
+ name="remember_check"
+ width="135" />
+<button
+ follows="left|bottom"
+ height="23"
+ image_unselected="PushButton_On"
+ image_selected="PushButton_On_Selected"
+ label="Log In"
+ label_color="White"
+ layout="topleft"
+ left_pad="10"
+ name="connect_btn"
+ top="35"
+ width="90" />
+ <text
+ follows="left|bottom"
+ font="SansSerifSmall"
+ height="15"
+ left_pad="10"
+ name="mode_selection_text"
+top="20"
+ width="130">
+ Mode:
+ </text>
+<combo_box
+ follows="left|bottom"
+ height="23"
+ max_chars="128"
+ top_pad="0"
+ tool_tip="Select your mode. Choose Basic for fast, easy exploration and chat. Choose Advanced to access more features."
+ control_name="SessionSettingsFile"
+ name="mode_combo"
+ width="120">
+<combo_box.item
+ label="Basic"
+ name="Basic"
+ value="settings_minimal.xml" />
+<combo_box.item
+ label="Advanced"
+ name="Advanced"
+ value="" />
+</combo_box>
+</layout_panel>
+<layout_panel
+tab_stop="false"
+follows="right|bottom"
+name="links"
+width="205"
+min_width="205"
+user_resize="false"
+height="80">
+ <text
+follows="right|bottom"
+font="SansSerifSmall"
+text_color="EmphasisColor"
+halign="right"
+height="16"
+top="12"
+right="-10"
+name="create_new_account_text"
+ width="200">
+ Sign up
+ </text>
+<text
+follows="right|bottom"
+font="SansSerifSmall"
+text_color="EmphasisColor"
+halign="right"
+height="16"
+name="forgot_password_text"
+top_pad="12"
+right="-10"
+ width="200">
+ Forgot your username or password?
+</text>
+<text
+follows="right|bottom"
+font="SansSerifSmall"
+text_color="EmphasisColor"
+halign="right"
+height="16"
+name="login_help"
+top_pad="2"
+right="-10"
+ width="200">
+ Need help logging in? </text>
+<!-- <text
+ follows="right|bottom"
+ font="SansSerifSmall"
+ halign="right"
+ height="28"
+ top_pad="2"
+ name="channel_text"
+ width="180"
+ word_wrap="true">
+ [VERSION]
+ </text>-->
+ </layout_panel>
+</layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml b/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml
new file mode 100644
index 0000000000..6dc1a1c9b0
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/panel_navigation_bar.xml
@@ -0,0 +1,76 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_opaque="true"
+ background_visible="true"
+ bg_opaque_color="MouseGray"
+ follows="left|top|right"
+ height="26"
+ layout="topleft"
+ name="navigation_bar"
+ chrome="true"
+ width="600">
+ <icon
+ follows="all"
+ image_name="NavBar_BG_NoFav_Bevel"
+ mouse_opaque="false"
+ name="bg_icon_no_fav_bevel"
+ scale_image="true"
+ visible="true"
+ left="0"
+ top="0"
+ height="26"
+ width="600"/>
+ <panel
+ background_visible="false"
+ follows="left|top|right"
+ top="3"
+ height="26"
+ layout="topleft"
+ name="navigation_panel"
+ width="600">
+ <pull_button
+follows="left|top"
+direction="down"
+height="23"
+image_overlay="Arrow_Left_Off"
+image_bottom_pad="1"
+layout="topleft"
+left="10"
+name="back_btn"
+tool_tip="Go back to previous location"
+top="2"
+width="31" />
+ <pull_button
+ follows="left|top"
+ direction="down"
+ height="23"
+ image_overlay="Arrow_Right_Off"
+ image_bottom_pad="1"
+ layout="topleft"
+ left_pad="0"
+ name="forward_btn"
+ tool_tip="Go forward one location"
+ top_delta="0"
+ width="31" />
+ <location_input
+ follows="left|right|top"
+ halign="right"
+ height="23"
+ label="Location"
+ layout="topleft"
+ left_pad="7"
+ max_chars="254"
+ mouse_opaque="false"
+ name="location_combo"
+ top_delta="0"
+ width="440">
+ </location_input>
+ <icon follows="right"
+ height="20"
+ width="2"
+ left_pad="2"
+ image_name="Button_Separator"
+ name="separator"
+ top="2"/>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/panel_people.xml b/indra/newview/skins/minimal/xui/en/panel_people.xml
new file mode 100644
index 0000000000..4a72653d76
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/panel_people.xml
@@ -0,0 +1,550 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!-- Side tray panel -->
+<panel
+ default_tab_group="1"
+ follows="all"
+ height="449"
+ label="People"
+ layout="topleft"
+ left="0"
+ min_height="350"
+ name="people_panel"
+ top="0"
+ width="333">
+ <string
+ name="no_recent_people"
+ value="No recent people. Looking for people to hang out with? Try the Destinations button below." />
+ <string
+ name="no_filtered_recent_people"
+ value="No recent people with that name." />
+ <string
+ name="no_one_near"
+ value="No one nearby. Looking for people to hang out with? Try the Destinations button below." />
+ <string
+ name="no_one_filtered_near"
+ value="No one nearby with that name." />
+ <string
+ name="no_friends_online"
+ value="No friends online" />
+ <string
+ name="no_friends"
+ value="No friends" />
+ <string
+ name="no_friends_msg">
+ Right-click on a Resident to add them as a friend.
+Looking for people to hang out with? Try the Destinations button below.
+ </string>
+ <string
+ name="no_filtered_friends_msg">
+ Didn't find what you're looking for? Try the Destinations button below..
+ </string>
+ <string
+ name="people_filter_label"
+ value="Filter People" />
+ <string
+ name="groups_filter_label"
+ value="Filter Groups" />
+ <!--
+ *WORKAROUND: for group_list.no_items_msg & group_list.no_filtered_items_msg attributes.
+ They are not defined as translatable in VLT. See EXT-5931
+ -->
+ <string
+ name="no_filtered_groups_msg"
+ value="Didn't find what you're looking for? Try [secondlife:///app/search/groups/[SEARCH_TERM] Search]." />
+ <string
+ name="no_groups_msg"
+ value="Looking for Groups to join? Try [secondlife:///app/search/groups Search]." />
+ <string
+ name="MiniMapToolTipMsg"
+ value="[REGION](Double-click to open Map, shift-drag to pan)"/>
+ <string
+ name="AltMiniMapToolTipMsg"
+ value="[REGION](Double-click to teleport, shift-drag to pan)"/>
+ <filter_editor
+ follows="left|top|right"
+ height="23"
+ layout="topleft"
+ left="10"
+ label="Filter"
+ max_length="300"
+ name="filter_input"
+ text_color="Black"
+ text_pad_left="10"
+ top="3"
+ width="303" />
+ <tab_container
+ follows="all"
+ height="383"
+ layout="topleft"
+ left="5"
+ name="tabs"
+ tab_group="1"
+ tab_min_width="70"
+ tab_height="30"
+ tab_position="top"
+ top_pad="10"
+ halign="center"
+ width="317">
+ <panel
+ background_opaque="true"
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ bg_opaque_color="DkGray"
+ follows="all"
+ height="383"
+ label="NEARBY"
+ layout="topleft"
+ left="0"
+ help_topic="people_nearby_tab"
+ name="nearby_panel"
+ top="0"
+ width="313">
+ <net_map
+ bg_color="NetMapBackgroundColor"
+ follows="top|left|right"
+ layout="topleft"
+ left="3"
+ mouse_opaque="false"
+ name="Net Map"
+ width="307"
+ height="140"
+ top="0"/>
+ <avatar_list
+ allow_select="true"
+ follows="top|left|bottom|right"
+ height="216"
+ ignore_online_status="true"
+ layout="topleft"
+ left="3"
+ multi_select="true"
+ name="avatar_list"
+ top="145"
+ width="307" />
+ <panel
+ background_visible="true"
+ follows="left|right|bottom"
+ height="27"
+ label="bottom_panel"
+ layout="topleft"
+ left="3"
+ name="bottom_panel"
+ top_pad="0"
+ width="313">
+ <icon
+ follows="bottom|left|right"
+ height="25"
+ image_name="Toolbar_Right_Off"
+ layout="topleft"
+ left_pad="1"
+ name="dummy_icon"
+ width="241"
+ />
+ </panel>
+ </panel>
+ <panel
+ background_opaque="true"
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ bg_opaque_color="DkGray"
+ follows="all"
+ height="383"
+ label="MY FRIENDS"
+ layout="topleft"
+ left="0"
+ help_topic="people_friends_tab"
+ name="friends_panel"
+ top="0"
+ width="313">
+ <accordion
+ background_visible="true"
+ bg_alpha_color="DkGray2"
+ bg_opaque_color="DkGray2"
+ follows="all"
+ height="356"
+ layout="topleft"
+ left="3"
+ name="friends_accordion"
+ top="0"
+ width="307">
+ <accordion_tab
+ layout="topleft"
+ height="172"
+ min_height="150"
+ name="tab_online"
+ title="Online">
+ <avatar_list
+ allow_select="true"
+ follows="all"
+ height="172"
+ layout="topleft"
+ left="0"
+ multi_select="true"
+ name="avatars_online"
+ show_permissions_granted="true"
+ top="0"
+ width="307" />
+ </accordion_tab>
+ <accordion_tab
+ layout="topleft"
+ height="173"
+ name="tab_all"
+ title="All">
+ <avatar_list
+ allow_select="true"
+ follows="all"
+ height="173"
+ layout="topleft"
+ left="0"
+ multi_select="true"
+ name="avatars_all"
+ show_permissions_granted="true"
+ top="0"
+ width="307" />
+ </accordion_tab>
+ </accordion>
+ <panel
+ background_visible="true"
+ follows="left|right|bottom"
+ height="27"
+ label="bottom_panel"
+ layout="topleft"
+ left="3"
+ name="bottom_panel"
+ top_pad="0"
+ width="313">
+
+ <layout_stack
+ animate="false"
+ border_size="0"
+ follows="left|right|bottom"
+ height="25"
+ layout="topleft"
+ orientation="horizontal"
+ top_pad="1"
+ left="0"
+ name="bottom_panel"
+ width="305">
+ <layout_panel
+ auto_resize="true"
+ height="25"
+ layout="topleft"
+ name="dummy_panel"
+ user_resize="false"
+ width="212">
+ <icon
+ follows="bottom|left|right"
+ height="25"
+ image_name="Toolbar_Middle_Off"
+ layout="topleft"
+ left="0"
+ top="0"
+ name="dummy_icon"
+ width="211" />
+ </layout_panel>
+ <layout_panel
+ auto_resize="false"
+ height="25"
+ layout="topleft"
+ name="trash_btn_panel"
+ user_resize="false"
+ width="31">
+ <dnd_button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Right_Over"
+ image_overlay="TrashItem_Off"
+ image_selected="Toolbar_Right_Selected"
+ image_unselected="Toolbar_Right_Off"
+ left="0"
+ layout="topleft"
+ name="del_btn"
+ tool_tip="Remove selected person from your Friends list"
+ top="0"
+ width="31"/>
+ </layout_panel>
+ </layout_stack><!--
+
+ <button
+ follows="bottom|left"
+ tool_tip="Options"
+ height="25"
+ image_hover_unselected="Toolbar_Left_Over"
+ image_overlay="OptionsMenu_Off"
+ image_selected="Toolbar_Left_Selected"
+ image_unselected="Toolbar_Left_Off"
+ layout="topleft"
+ left="0"
+ name="friends_viewsort_btn"
+ top="1"
+ width="31" />
+ <button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="AddItem_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="1"
+ name="add_btn"
+ tool_tip="Offer friendship to a Resident"
+ width="31" />
+ <icon
+ follows="bottom|left|right"
+ height="25"
+ image_name="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="1"
+ name="dummy_icon"
+ width="209"
+ />
+ <button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Right_Over"
+ image_overlay="TrashItem_Off"
+ image_selected="Toolbar_Right_Selected"
+ image_unselected="Toolbar_Right_Off"
+ layout="topleft"
+ left_pad="1"
+ name="del_btn"
+ tool_tip="Remove selected person from your Friends list"
+ width="31" />
+ --></panel>
+ <text
+ follows="all"
+ height="450"
+ left="13"
+ name="no_friends_help_text"
+ top="10"
+ width="293"
+ wrap="true" />
+ </panel>
+ <panel
+ background_opaque="true"
+ background_visible="true"
+ bg_alpha_color="DkGray"
+ bg_opaque_color="DkGray"
+ follows="all"
+ height="383"
+ label="RECENT"
+ layout="topleft"
+ left="0"
+ help_topic="people_recent_tab"
+ name="recent_panel"
+ top="0"
+ width="313">
+ <avatar_list
+ allow_select="true"
+ follows="all"
+ height="356"
+ layout="topleft"
+ left="3"
+ multi_select="true"
+ name="avatar_list"
+ show_last_interaction_time="true"
+ top="0"
+ width="307" />
+ <panel
+ background_visible="true"
+ follows="left|right|bottom"
+ height="27"
+ label="bottom_panel"
+ layout="topleft"
+ left="0"
+ name="bottom_panel"
+ top_pad="0"
+ width="313">
+ <button
+ follows="bottom|left"
+ height="25"
+ image_hover_unselected="Toolbar_Middle_Over"
+ image_overlay="AddItem_Off"
+ image_selected="Toolbar_Middle_Selected"
+ image_unselected="Toolbar_Middle_Off"
+ layout="topleft"
+ left_pad="1"
+ name="add_friend_btn"
+ tool_tip="Add selected Resident to your friends List"
+ width="31">
+ <commit_callback
+ function="People.addFriend" />
+ </button>
+ <icon
+ follows="bottom|left|right"
+ height="25"
+ image_name="Toolbar_Right_Off"
+ layout="topleft"
+ left_pad="1"
+ name="dummy_icon"
+ width="241"
+ />
+ </panel>
+ </panel>
+ </tab_container>
+ <panel
+ follows="bottom|left|right"
+ height="23"
+ layout="topleft"
+ left="8"
+ top_pad="4"
+ name="button_bar"
+ width="313">
+
+<!--********************************Profile; IM; Call, Share, Teleport********************************-->
+ <layout_stack
+ follows="bottom|left|right"
+ height="23"
+ layout="topleft"
+ name="bottom_bar_ls"
+ left="0"
+ orientation="horizontal"
+ top_pad="0"
+ width="313">
+
+ <layout_panel
+ follows="bottom|left|right"
+ height="23"
+ layout="bottomleft"
+ left="0"
+ name="view_profile_btn_lp"
+ user_resize="false"
+ auto_resize="true"
+ width="68">
+ <button
+ follows="bottom|left|right"
+ height="23"
+ label="Profile"
+ layout="topleft"
+ left="1"
+ name="view_profile_btn"
+ tool_tip="Show picture, groups, and other Residents information"
+ top="0"
+ width="67" />
+ </layout_panel>
+
+ <layout_panel
+ follows="bottom|left|right"
+ height="23"
+ layout="bottomleft"
+ left_pad="3"
+ name="chat_btn_lp"
+ user_resize="false"
+ auto_resize="true"
+ width="41">
+ <button
+ follows="bottom|left|right"
+ left="1"
+ height="23"
+ label="IM"
+ layout="topleft"
+ name="im_btn"
+ tool_tip="Open instant message session"
+ top="0"
+ width="40" />
+ </layout_panel>
+
+ <layout_panel
+ follows="bottom|left|right"
+ height="23"
+ layout="bottomleft"
+ left_pad="3"
+ name="chat_btn_lp"
+ user_resize="false"
+ auto_resize="true"
+ width="77">
+ <button
+ follows="bottom|left|right"
+ left="1"
+ height="23"
+ label="Teleport"
+ layout="topleft"
+ name="teleport_btn"
+ tool_tip="Offer teleport"
+ top="0"
+ width="76" />
+ </layout_panel>
+ </layout_stack>
+
+<!--********************************Group Profile; Group Chat; Group Call buttons************************-->
+ <layout_stack
+ follows="bottom|left|right"
+ height="23"
+ layout="topleft"
+ mouse_opaque="false"
+ name="bottom_bar_ls1"
+ left="0"
+ orientation="horizontal"
+ top="0"
+ width="313">
+ <layout_panel
+ follows="bottom|left|right"
+ height="23"
+ layout="bottomleft"
+ left="0"
+ mouse_opaque="false"
+ name="group_info_btn_lp"
+ user_resize="false"
+ auto_resize="true"
+ width="108">
+ <button
+ follows="bottom|left|right"
+ left="1"
+ height="23"
+ label="Group Profile"
+ layout="topleft"
+ mouse_opaque="false"
+ name="group_info_btn"
+ tool_tip="Show group information"
+ top="0"
+ width="107" />
+ </layout_panel>
+
+ <layout_panel
+ follows="bottom|left|right"
+ height="23"
+ layout="bottomleft"
+ left_pad="3"
+ mouse_opaque="false"
+ name="chat_btn_lp"
+ user_resize="false"
+ auto_resize="true"
+ width="101">
+ <button
+ follows="bottom|left|right"
+ left="1"
+ height="23"
+ label="Group Chat"
+ layout="topleft"
+ mouse_opaque="false"
+ name="chat_btn"
+ tool_tip="Open chat session"
+ top="0"
+ width="100" />
+ </layout_panel>
+
+ <layout_panel
+ follows="bottom|left|right"
+ height="23"
+ layout="bottomleft"
+ left_pad="3"
+ mouse_opaque="false"
+ name="group_call_btn_lp"
+ user_resize="false"
+ auto_resize="true"
+ width="96">
+ <button
+ follows="bottom|left|right"
+ left="1"
+ height="23"
+ label="Group Call"
+ layout="topleft"
+ mouse_opaque="false"
+ name="group_call_btn"
+ tool_tip="Call this group"
+ top="0"
+ width="95" />
+ </layout_panel>
+ </layout_stack>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/panel_side_tray_tab_caption.xml b/indra/newview/skins/minimal/xui/en/panel_side_tray_tab_caption.xml
new file mode 100644
index 0000000000..9f2f41ba31
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/panel_side_tray_tab_caption.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_visible="true"
+ bottom="0"
+ follows="left|top|right"
+ height="5"
+ width="333"
+ layout="topleft"
+ left="0"
+ name="sidetray_tab_panel">
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/panel_status_bar.xml b/indra/newview/skins/minimal/xui/en/panel_status_bar.xml
new file mode 100644
index 0000000000..6ccd0e938d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/panel_status_bar.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_opaque="true"
+ background_visible="true"
+ bg_opaque_color="MouseGray"
+ chrome="true"
+ follows="top|right"
+ height="30"
+ layout="topleft"
+ left="0"
+ mouse_opaque="false"
+ name="status"
+ top="19"
+ tab_stop="false"
+ width="70">
+ <panel.string
+ name="packet_loss_tooltip">
+ Packet Loss
+ </panel.string>
+ <panel.string
+ name="bandwidth_tooltip">
+ Bandwidth
+ </panel.string>
+ <panel.string
+ name="time">
+ [hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]
+ </panel.string>
+ <panel.string
+ name="timeTooltip">
+ [weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]
+ </panel.string>
+ <panel.string
+ name="buycurrencylabel">
+ L$ [AMT]
+ </panel.string>
+ <button
+ follows="right|top"
+ height="16"
+ image_selected="Play_Off"
+ image_unselected="Pause_Off"
+ image_pressed="Pause_Press"
+ image_pressed_selected="Play_Press"
+ is_toggle="true"
+ left="15"
+ top="7"
+ name="media_toggle_btn"
+ tool_tip="Start/Stop All Media (Music, Video, Web pages)"
+ width="16" >
+ </button>
+ <button
+ follows="right|top"
+ height="16"
+ image_selected="AudioMute_Off"
+ image_pressed="Audio_Press"
+ image_unselected="Audio_Off"
+ is_toggle="true"
+ left_pad="5"
+ top="8"
+ name="volume_btn"
+ tool_tip="Global Volume Control"
+ width="16" />
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/panel_volume_pulldown.xml b/indra/newview/skins/minimal/xui/en/panel_volume_pulldown.xml
new file mode 100644
index 0000000000..36ad39abe8
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/panel_volume_pulldown.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<panel
+ background_opaque="true"
+ background_visible="true"
+ bg_opaque_image="Volume_Background"
+ bg_alpha_image="Volume_Background"
+ border_visible="false"
+ border="false"
+ chrome="true"
+ follows="bottom"
+ height="150"
+ layout="topleft"
+ name="volumepulldown_floater"
+ width="32">
+ <slider
+ control_name="AudioLevelMaster"
+ follows="left|top"
+ left="0"
+ top="1"
+ orientation="vertical"
+ height="140"
+ increment="0.05"
+ initial_value="0.5"
+ layout="topleft"
+ name="mastervolume"
+ show_text="false"
+ slider_label.halign="right"
+ top_pad="2"
+ volume="true">
+ <slider.commit_callback
+ function="Vol.setControlFalse"
+ parameter="MuteAudio" />
+ </slider>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/en/widgets/location_input.xml b/indra/newview/skins/minimal/xui/en/widgets/location_input.xml
new file mode 100644
index 0000000000..fe06a2d816
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/en/widgets/location_input.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
+<!--
+*TODO: Replace hardcoded buttons width/height with getting this info from the button images.
+ Currently that doesn't work because LLUIImage::getWidth/getHeight() return 1 for the images.
+-->
+<location_input font="SansSerifSmall"
+ maturity_help_topic="maturity_rating"
+ add_landmark_hpad="0"
+ icon_hpad="2"
+ allow_text_entry="true"
+ list_position="below"
+ show_text_as_tentative="false"
+ max_chars="20"
+ follows="left|top"
+ allow_new_values="true"
+ >
+ <!-- *NOTE: Tooltips are in strings.xml so they can be localized.
+ See LocationCtrlAddLandmarkTooltip etc. -->
+ <info_button
+ name="Place Information"
+ width="0"
+ height="0"
+ visible="false"
+ left="6"
+ top="20"
+ follows="left|top"
+ hover_glow_amount="0.15" />
+ <add_landmark_button name="Add Landmark"
+ hover_glow_amount="0.15"
+ width="0"
+ height="0"
+ visible="false"
+ follows="right|top"
+ scale_image="false"
+ top="19"
+ left="-3" />
+ <maturity_button
+ name="maturity_icon"
+ width="0"
+ height="0"
+ visible="false"
+ top="20"
+ follows="left|top"
+ />
+ <for_sale_button
+ name="for_sale_btn"
+ width="0"
+ height="0"
+ visible="false"
+ follows="right|top"
+ scale_image="false"
+ top="21"
+ />
+ <voice_icon
+ enabled="true"
+ name="voice_icon"
+ width="0"
+ height="0"
+ visible="false"
+ top="21"
+ follows="right|top"
+ />
+ <fly_icon
+ name="fly_icon"
+ width="0"
+ height="0"
+ visible="false"
+ top="21"
+ follows="right|top"
+ />
+ <push_icon
+ name="push_icon"
+ width="0"
+ height="0"
+ visible="false"
+ top="21"
+ follows="right|top"
+ />
+ <build_icon
+ name="build_icon"
+ width="0"
+ height="0"
+ visible="false"
+ top="21"
+ follows="right|top"
+ />
+ <scripts_icon
+ name="scripts_icon"
+ width="0"
+ height="0"
+ visible="false"
+ top="21"
+ follows="right|top"
+ />
+ <damage_icon
+ name="damage_icon"
+ width="0"
+ height="0"
+ visible="false"
+ top="19"
+ left="2"
+ follows="right|top"
+ />
+ <!-- Default text color is invisible on top of nav bar background -->
+ <damage_text
+ name="damage_text"
+ width="0"
+ height="0"
+ max_length="0"
+ top="17"
+ follows="right|top"
+ halign="right"
+ font="SansSerifSmall"
+ text_color="TextFgColor"
+ />
+ <combo_button
+ name="Location History"
+ label=""
+ pad_right="0"/>
+ <combo_list
+ bg_writeable_color="MenuDefaultBgColor"
+ page_lines="10"
+ scroll_bar_bg_visible="true" />
+ <combo_editor name="Combo Text Entry"
+ text_pad_left="4"
+ select_on_focus="false"
+ font="SansSerifSmall"
+ bevel_style="none"
+ border_style="line"
+ border.border_thickness="0" />
+</location_input>
diff --git a/indra/newview/skins/minimal/xui/es/floater_camera.xml b/indra/newview/skins/minimal/xui/es/floater_camera.xml
new file mode 100644
index 0000000000..ccf3d4bf91
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/floater_camera.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="camera_floater" title="">
+ <floater.string name="rotate_tooltip">
+ Girar la cámara alrededor de lo enfocado
+ </floater.string>
+ <floater.string name="zoom_tooltip">
+ Hacer zoom con la cámara en lo enfocado
+ </floater.string>
+ <floater.string name="move_tooltip">
+ Mover la cámara arriba y abajo, izquierda y derecha
+ </floater.string>
+ <floater.string name="camera_modes_title">
+ Modos de cámara
+ </floater.string>
+ <floater.string name="pan_mode_title">
+ Orbital - Zoom - Panóramica
+ </floater.string>
+ <floater.string name="presets_mode_title">
+ Vistas predefinidas
+ </floater.string>
+ <floater.string name="free_mode_title">
+ Centrar el objeto
+ </floater.string>
+ <panel name="controls">
+ <panel name="preset_views_list">
+ <panel_camera_item name="front_view">
+ <panel_camera_item.text name="front_view_text">
+ De frente
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="group_view">
+ <panel_camera_item.text name="side_view_text">
+ Vista lateral
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="rear_view">
+ <panel_camera_item.text name="rear_view_text">
+ Desde detrás
+ </panel_camera_item.text>
+ </panel_camera_item>
+ </panel>
+ <panel name="camera_modes_list">
+ <panel_camera_item name="object_view">
+ <panel_camera_item.text name="object_view_text">
+ Vista de objeto
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="mouselook_view">
+ <panel_camera_item.text name="mouselook_view_text">
+ Vista subjetiva
+ </panel_camera_item.text>
+ </panel_camera_item>
+ </panel>
+ <panel name="zoom" tool_tip="Hacer zoom con la cámara en lo enfocado">
+ <joystick_rotate name="cam_rotate_stick" tool_tip="La cámara gira alrededor del punto de vista"/>
+ <slider_bar name="zoom_slider" tool_tip="Hacer zoom en lo enfocado"/>
+ <joystick_track name="cam_track_stick" tool_tip="Mueve la cámara arriba y abajo, a izquierda y derecha"/>
+ </panel>
+ </panel>
+ <panel name="buttons">
+ <button label="" name="presets_btn" tool_tip="Vistas predefinidas"/>
+ <button label="" name="pan_btn" tool_tip="Orbital - Zoom - Panóramica"/>
+ <button label="" name="avatarview_btn" tool_tip="Modos de cámara"/>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/es/floater_help_browser.xml b/indra/newview/skins/minimal/xui/es/floater_help_browser.xml
new file mode 100644
index 0000000000..67590ebfbb
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/floater_help_browser.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_help_browser" title="INDICACIONES">
+ <floater.string name="loading_text">
+ Cargando...
+ </floater.string>
+ <layout_stack name="stack1">
+ <layout_panel name="external_controls"/>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/es/floater_nearby_chat.xml b/indra/newview/skins/minimal/xui/es/floater_nearby_chat.xml
new file mode 100644
index 0000000000..1fee9ab056
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/floater_nearby_chat.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="nearby_chat" title="CHAT">
+ <check_box label="Traducir chat (mediante Google)" name="translate_chat_checkbox"/>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/es/inspect_avatar.xml b/indra/newview/skins/minimal/xui/es/inspect_avatar.xml
new file mode 100644
index 0000000000..1d70fa6a90
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/inspect_avatar.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater name="inspect_avatar">
+ <string name="Subtitle">
+ [AGE]
+ </string>
+ <string name="Details">
+ [SL_PROFILE]
+ </string>
+ <text name="user_details">
+ Ésta es mi descripción de Second Life que, por cierto, me encanta. Pero, por lo que sea, me he enrollado más de la cuenta y la descripción es larguísima.
+ </text>
+ <slider name="volume_slider" tool_tip="Volumen de la voz" value="0.5"/>
+ <button label="Añadir como amigo" name="add_friend_btn"/>
+ <button label="MI" name="im_btn"/>
+ <button label="Perfil" name="view_profile_btn"/>
+ <panel name="moderator_panel">
+ <button label="Desactivar la voz" name="disable_voice"/>
+ <button label="Activar la voz" name="enable_voice"/>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/es/inspect_object.xml b/indra/newview/skins/minimal/xui/es/inspect_object.xml
new file mode 100644
index 0000000000..d608b4a0f7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/inspect_object.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater name="inspect_object">
+ <string name="Creator">
+ Por [CREATOR]
+ </string>
+ <string name="CreatorAndOwner">
+ Por [CREATOR]
+Propietario [OWNER]
+ </string>
+ <string name="Price">
+ [AMOUNT] L$
+ </string>
+ <string name="PriceFree">
+ ¡Gratis!
+ </string>
+ <string name="Touch">
+ Tocar
+ </string>
+ <string name="Sit">
+ Sentarme
+ </string>
+ <text name="object_name" value="Test Object Name That Is actually two lines and Really Long"/>
+ <text name="price_text">
+ 30.000 L$
+ </text>
+ <text name="object_description">
+ This is a really long description for an object being as how it is at least 80 characters in length and so but maybe more like 120 at this point. Who knows, really?
+ </text>
+ <button label="Comprar" name="buy_btn"/>
+ <button label="Pagar" name="pay_btn"/>
+ <button label="Coger una copia" name="take_free_copy_btn"/>
+ <button label="Tocar" name="touch_btn"/>
+ <button label="Sentarme" name="sit_btn"/>
+ <button label="Abrir" name="open_btn"/>
+ <icon name="secure_browsing" tool_tip="Navegación segura"/>
+ <button label="Más" name="more_info_btn"/>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/es/menu_add_wearable_gear.xml b/indra/newview/skins/minimal/xui/es/menu_add_wearable_gear.xml
new file mode 100644
index 0000000000..f2367c72a3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_add_wearable_gear.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Add Wearable Gear Menu">
+ <menu_item_check label="Ordenar por los más recientes" name="sort_by_most_recent"/>
+ <menu_item_check label="Ordenar alfabéticamente" name="sort_by_name"/>
+ <menu_item_check label="Ordenar por tipo" name="sort_by_type"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_attachment_other.xml b/indra/newview/skins/minimal/xui/es/menu_attachment_other.xml
new file mode 100644
index 0000000000..00bdb74881
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_attachment_other.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: See also menu_avatar_other.xml -->
+<context_menu name="Avatar Pie">
+ <menu_item_call label="Ver el perfil" name="Profile..."/>
+ <menu_item_call label="Añadir como amigo" name="Add Friend"/>
+ <menu_item_call label="MI" name="Send IM..."/>
+ <menu_item_call label="Llamada" name="Call"/>
+ <menu_item_call label="Invitar al grupo" name="Invite..."/>
+ <menu_item_call label="Ignorar" name="Avatar Mute"/>
+ <menu_item_call label="Denunciar" name="abuse"/>
+ <menu_item_call label="Congelar" name="Freeze..."/>
+ <menu_item_call label="Expulsar" name="Eject..."/>
+ <menu_item_call label="Depurar las texturas" name="Debug..."/>
+ <menu_item_call label="Acercar el zoom" name="Zoom In"/>
+ <menu_item_call label="Pagar" name="Pay..."/>
+ <menu_item_call label="Perfil del objeto" name="Object Inspect"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_attachment_self.xml b/indra/newview/skins/minimal/xui/es/menu_attachment_self.xml
new file mode 100644
index 0000000000..ab76c92d65
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_attachment_self.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Attachment Pie">
+ <menu_item_call label="Tocar" name="Attachment Object Touch"/>
+ <menu_item_call label="Editar" name="Edit..."/>
+ <menu_item_call label="Quitar" name="Detach"/>
+ <menu_item_call label="Sentarte" name="Sit Down Here"/>
+ <menu_item_call label="Levantarme" name="Stand Up"/>
+ <menu_item_call label="Cambiar vestuario" name="Change Outfit"/>
+ <menu_item_call label="Editar mi vestuario" name="Edit Outfit"/>
+ <menu_item_call label="Editar mi anatomía" name="Edit My Shape"/>
+ <menu_item_call label="Mis amigos" name="Friends..."/>
+ <menu_item_call label="Mis grupos" name="Groups..."/>
+ <menu_item_call label="Mi perfil" name="Profile..."/>
+ <menu_item_call label="Depurar las texturas" name="Debug..."/>
+ <menu_item_call label="Soltar" name="Drop"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_avatar_icon.xml b/indra/newview/skins/minimal/xui/es/menu_avatar_icon.xml
new file mode 100644
index 0000000000..fe7331a108
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_avatar_icon.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Avatar Icon Menu">
+ <menu_item_call label="Ver el perfil" name="Show Profile"/>
+ <menu_item_call label="Enviar un MI..." name="Send IM"/>
+ <menu_item_call label="Añadir como amigo..." name="Add Friend"/>
+ <menu_item_call label="Quitar de los amigos..." name="Remove Friend"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_avatar_other.xml b/indra/newview/skins/minimal/xui/es/menu_avatar_other.xml
new file mode 100644
index 0000000000..7df2d7c4e0
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_avatar_other.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: See also menu_attachment_other.xml -->
+<context_menu name="Avatar Pie">
+ <menu_item_call label="Ver el perfil" name="Profile..."/>
+ <menu_item_call label="Añadir como amigo" name="Add Friend"/>
+ <menu_item_call label="MI" name="Send IM..."/>
+ <menu_item_call label="Llamada" name="Call"/>
+ <menu_item_call label="Invitar al grupo" name="Invite..."/>
+ <menu_item_call label="Ignorar" name="Avatar Mute"/>
+ <menu_item_call label="Denunciar" name="abuse"/>
+ <menu_item_call label="Congelar" name="Freeze..."/>
+ <menu_item_call label="Expulsar" name="Eject..."/>
+ <menu_item_call label="Depurar las texturas" name="Debug..."/>
+ <menu_item_call label="Acercar el zoom" name="Zoom In"/>
+ <menu_item_call label="Pagar" name="Pay..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_avatar_self.xml b/indra/newview/skins/minimal/xui/es/menu_avatar_self.xml
new file mode 100644
index 0000000000..50f8384b0f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_avatar_self.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Self Pie">
+ <menu_item_call label="Sentarte" name="Sit Down Here"/>
+ <menu_item_call label="Levantarme" name="Stand Up"/>
+ <context_menu label="Quitarme" name="Take Off &gt;">
+ <context_menu label="Ropas" name="Clothes &gt;">
+ <menu_item_call label="Camisa" name="Shirt"/>
+ <menu_item_call label="Pantalón" name="Pants"/>
+ <menu_item_call label="Falda" name="Skirt"/>
+ <menu_item_call label="Zapatos" name="Shoes"/>
+ <menu_item_call label="Calcetines" name="Socks"/>
+ <menu_item_call label="Chaqueta" name="Jacket"/>
+ <menu_item_call label="Guantes" name="Gloves"/>
+ <menu_item_call label="Camiseta" name="Self Undershirt"/>
+ <menu_item_call label="Ropa interior" name="Self Underpants"/>
+ <menu_item_call label="Tatuaje" name="Self Tattoo"/>
+ <menu_item_call label="Alfa" name="Self Alpha"/>
+ <menu_item_call label="Toda la ropa" name="All Clothes"/>
+ </context_menu>
+ <context_menu label="HUD" name="Object Detach HUD"/>
+ <context_menu label="Quitar" name="Object Detach"/>
+ <menu_item_call label="Quitarse todo" name="Detach All"/>
+ </context_menu>
+ <menu_item_call label="Cambiar vestuario" name="Chenge Outfit"/>
+ <menu_item_call label="Editar mi vestuario" name="Edit Outfit"/>
+ <menu_item_call label="Editar mi anatomía" name="Edit My Shape"/>
+ <menu_item_call label="Mis amigos" name="Friends..."/>
+ <menu_item_call label="Mis grupos" name="Groups..."/>
+ <menu_item_call label="Mi perfil" name="Profile..."/>
+ <menu_item_call label="Depurar las texturas" name="Debug..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_bottomtray.xml b/indra/newview/skins/minimal/xui/es/menu_bottomtray.xml
new file mode 100644
index 0000000000..62683f3076
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_bottomtray.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="hide_camera_move_controls_menu">
+ <menu_item_check label="Botón Gestos" name="ShowGestureButton"/>
+ <menu_item_check label="Botón Moverse" name="ShowMoveButton"/>
+ <menu_item_check label="Botón Vista" name="ShowCameraButton"/>
+ <menu_item_check label="Botón Foto" name="ShowSnapshotButton"/>
+ <menu_item_check label="Botón Barra lateral" name="ShowSidebarButton"/>
+ <menu_item_check label="Botón Construir" name="ShowBuildButton"/>
+ <menu_item_check label="Botón Buscar" name="ShowSearchButton"/>
+ <menu_item_check label="Botón Mapa" name="ShowWorldMapButton"/>
+ <menu_item_check label="Botón Minimapa" name="ShowMiniMapButton"/>
+ <menu_item_call label="Cortar" name="NearbyChatBar_Cut"/>
+ <menu_item_call label="Copiar" name="NearbyChatBar_Copy"/>
+ <menu_item_call label="Pegar" name="NearbyChatBar_Paste"/>
+ <menu_item_call label="Borrar" name="NearbyChatBar_Delete"/>
+ <menu_item_call label="Seleccionar todo" name="NearbyChatBar_Select_All"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_cof_attachment.xml b/indra/newview/skins/minimal/xui/es/menu_cof_attachment.xml
new file mode 100644
index 0000000000..7541530601
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_cof_attachment.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Attachment">
+ <menu_item_call label="Quitar" name="detach"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_cof_body_part.xml b/indra/newview/skins/minimal/xui/es/menu_cof_body_part.xml
new file mode 100644
index 0000000000..56b95bdc3b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_cof_body_part.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Body">
+ <menu_item_call label="Reemplazar" name="replace"/>
+ <menu_item_call label="Editar" name="edit"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_cof_clothing.xml b/indra/newview/skins/minimal/xui/es/menu_cof_clothing.xml
new file mode 100644
index 0000000000..3c0c588284
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_cof_clothing.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Clothing">
+ <menu_item_call label="Quitarme" name="take_off"/>
+ <menu_item_call label="Editar" name="edit"/>
+ <menu_item_call label="Reemplazar" name="replace"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_cof_gear.xml b/indra/newview/skins/minimal/xui/es/menu_cof_gear.xml
new file mode 100644
index 0000000000..ff8ad0977a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_cof_gear.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear COF">
+ <menu label="Ropas nuevas" name="COF.Gear.New_Clothes"/>
+ <menu label="Nuevas partes del cuerpo" name="COF.Geear.New_Body_Parts"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_edit.xml b/indra/newview/skins/minimal/xui/es/menu_edit.xml
new file mode 100644
index 0000000000..96fc9d8881
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="Editar" name="Edit">
+ <menu_item_call label="Deshacer" name="Undo"/>
+ <menu_item_call label="Rehacer" name="Redo"/>
+ <menu_item_call label="Cortar" name="Cut"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+ <menu_item_call label="Pegar" name="Paste"/>
+ <menu_item_call label="Borrar" name="Delete"/>
+ <menu_item_call label="Duplicar" name="Duplicate"/>
+ <menu_item_call label="Seleccionar todo" name="Select All"/>
+ <menu_item_call label="Deseleccionar" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_favorites.xml b/indra/newview/skins/minimal/xui/es/menu_favorites.xml
new file mode 100644
index 0000000000..c8a7858ddb
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_favorites.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Teleportarse" name="Teleport To Landmark"/>
+ <menu_item_call label="Ver/Editar el hito" name="Landmark Open"/>
+ <menu_item_call label="Copiar la SLurl" name="Copy slurl"/>
+ <menu_item_call label="Mostrar en el mapa" name="Show On Map"/>
+ <menu_item_call label="Copiar" name="Landmark Copy"/>
+ <menu_item_call label="Pegar" name="Landmark Paste"/>
+ <menu_item_call label="Borrar" name="Delete"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_gesture_gear.xml b/indra/newview/skins/minimal/xui/es/menu_gesture_gear.xml
new file mode 100644
index 0000000000..24706eb2c8
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_gesture_gear.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_gesture_gear">
+ <menu_item_call label="Añadir a / Quitar de los favoritos" name="activate"/>
+ <menu_item_call label="Copiar" name="copy_gesture"/>
+ <menu_item_call label="Pegar" name="paste"/>
+ <menu_item_call label="Copiar la UUID" name="copy_uuid"/>
+ <menu_item_call label="Añadir al vestuario actual" name="save_to_outfit"/>
+ <menu_item_call label="Editar" name="edit_gesture"/>
+ <menu_item_call label="Inspeccionar" name="inspect"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_group_plus.xml b/indra/newview/skins/minimal/xui/es/menu_group_plus.xml
new file mode 100644
index 0000000000..6b26ba42c4
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_group_plus.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_call label="Entrar al grupo..." name="item_join"/>
+ <menu_item_call label="Grupo nuevo..." name="item_new"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_hide_navbar.xml b/indra/newview/skins/minimal/xui/es/menu_hide_navbar.xml
new file mode 100644
index 0000000000..22a1873234
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_hide_navbar.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="hide_navbar_menu">
+ <menu_item_check label="Mostrar la barra de navegación" name="ShowNavbarNavigationPanel"/>
+ <menu_item_check label="Mostrar la barra de favoritos" name="ShowNavbarFavoritesPanel"/>
+ <menu_item_check label="Mostrar mini-barra de ubicación" name="ShowMiniLocationPanel"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_im_well_button.xml b/indra/newview/skins/minimal/xui/es/menu_im_well_button.xml
new file mode 100644
index 0000000000..c8f6c217cc
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_im_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="IM Well Button Context Menu">
+ <menu_item_call label="Cerrar todo" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_imchiclet_adhoc.xml b/indra/newview/skins/minimal/xui/es/menu_imchiclet_adhoc.xml
new file mode 100644
index 0000000000..e11e9bdc58
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_imchiclet_adhoc.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet AdHoc Menu">
+ <menu_item_call label="Acabar la sesión" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_imchiclet_group.xml b/indra/newview/skins/minimal/xui/es/menu_imchiclet_group.xml
new file mode 100644
index 0000000000..a5e60ea40b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_imchiclet_group.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet Group Menu">
+ <menu_item_call label="Información del grupo" name="Show Profile"/>
+ <menu_item_call label="Mostrar la sesión" name="Chat"/>
+ <menu_item_call label="Acabar la sesión" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_imchiclet_p2p.xml b/indra/newview/skins/minimal/xui/es/menu_imchiclet_p2p.xml
new file mode 100644
index 0000000000..492801026c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_imchiclet_p2p.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet P2P Menu">
+ <menu_item_call label="Ver el perfil" name="Show Profile"/>
+ <menu_item_call label="Añadir como amigo" name="Add Friend"/>
+ <menu_item_call label="Mostrar la sesión" name="Send IM"/>
+ <menu_item_call label="Acabar la sesión" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_inspect_avatar_gear.xml b/indra/newview/skins/minimal/xui/es/menu_inspect_avatar_gear.xml
new file mode 100644
index 0000000000..ebe33cea11
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_inspect_avatar_gear.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<toggleable_menu name="Gear Menu">
+ <menu_item_call label="Ver el perfil" name="view_profile"/>
+ <menu_item_call label="Añadir como amigo" name="add_friend"/>
+ <menu_item_call label="MI" name="im"/>
+ <menu_item_call label="Teleportarse" name="teleport"/>
+ <menu_item_call label="Ignorar" name="block"/>
+ <menu_item_call label="Designorar" name="unblock"/>
+ <menu_item_call label="Denunciar" name="report"/>
+ <menu_item_call label="Congelar" name="freeze"/>
+ <menu_item_call label="Expulsar" name="eject"/>
+ <menu_item_call label="Expulsar" name="kick"/>
+ <menu_item_call label="CSR" name="csr"/>
+ <menu_item_call label="Depurar las texturas" name="debug"/>
+ <menu_item_call label="Encontrar en el mapa" name="find_on_map"/>
+ <menu_item_call label="Acercar el zoom" name="zoom_in"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_inspect_object_gear.xml b/indra/newview/skins/minimal/xui/es/menu_inspect_object_gear.xml
new file mode 100644
index 0000000000..bcdc25894f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_inspect_object_gear.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu name="Gear Menu">
+ <menu_item_call label="Tocar" name="touch"/>
+ <menu_item_call label="Sentarse" name="sit"/>
+ <menu_item_call label="Pagar" name="pay"/>
+ <menu_item_call label="Comprar" name="buy"/>
+ <menu_item_call label="Tomar" name="take"/>
+ <menu_item_call label="Coger una copia" name="take_copy"/>
+ <menu_item_call label="Abrir" name="open"/>
+ <menu_item_call label="Editar" name="edit"/>
+ <menu_item_call label="Ponerse" name="wear"/>
+ <menu_item_call label="Añadir" name="add"/>
+ <menu_item_call label="Denunciar" name="report"/>
+ <menu_item_call label="Ignorar" name="block"/>
+ <menu_item_call label="Acercar el zoom" name="zoom_in"/>
+ <menu_item_call label="Quitar" name="remove"/>
+ <menu_item_call label="Más información" name="more_info"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml
new file mode 100644
index 0000000000..c8a1e9d9da
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_inspect_self_gear.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu name="Gear Menu">
+ <menu_item_call label="Sentarte" name="sit_down_here"/>
+ <menu_item_call label="Levantarme" name="stand_up"/>
+ <menu_item_call label="Cambiar vestuario" name="change_outfit"/>
+ <menu_item_call label="Mi perfil" name="my_profile"/>
+ <menu_item_call label="Mis amigos" name="my_friends"/>
+ <menu_item_call label="Mis grupos" name="my_groups"/>
+ <menu_item_call label="Depurar las texturas" name="Debug..."/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_inv_offer_chiclet.xml b/indra/newview/skins/minimal/xui/es/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..20d99afde1
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="Cerrar" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_inventory.xml b/indra/newview/skins/minimal/xui/es/menu_inventory.xml
new file mode 100644
index 0000000000..94ee162bbc
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_inventory.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Compartir" name="Share"/>
+ <menu_item_call label="Comprar" name="Task Buy"/>
+ <menu_item_call label="Abrir" name="Task Open"/>
+ <menu_item_call label="Ejecutar" name="Task Play"/>
+ <menu_item_call label="Propiedades" name="Task Properties"/>
+ <menu_item_call label="Renombrar" name="Task Rename"/>
+ <menu_item_call label="Borrar" name="Task Remove"/>
+ <menu_item_call label="Vaciar la papelera" name="Empty Trash"/>
+ <menu_item_call label="Vaciar Objetos Perdidos" name="Empty Lost And Found"/>
+ <menu_item_call label="Carpeta nueva" name="New Folder"/>
+ <menu_item_call label="Script nuevo" name="New Script"/>
+ <menu_item_call label="Nota nueva" name="New Note"/>
+ <menu_item_call label="Gesto nuevo" name="New Gesture"/>
+ <menu label="Ropas nuevas" name="New Clothes">
+ <menu_item_call label="Camisa nueva" name="New Shirt"/>
+ <menu_item_call label="Pantalones nuevos" name="New Pants"/>
+ <menu_item_call label="Zapatos nuevos" name="New Shoes"/>
+ <menu_item_call label="Calcetines nuevos" name="New Socks"/>
+ <menu_item_call label="Chaqueta nueva" name="New Jacket"/>
+ <menu_item_call label="Falda nueva" name="New Skirt"/>
+ <menu_item_call label="Guantes nuevos" name="New Gloves"/>
+ <menu_item_call label="Camiseta nueva" name="New Undershirt"/>
+ <menu_item_call label="Ropa interior nueva" name="New Underpants"/>
+ <menu_item_call label="Nueva capa Alpha" name="New Alpha Mask"/>
+ <menu_item_call label="Tatuaje nuevo" name="New Tattoo"/>
+ </menu>
+ <menu label="Nuevas partes del cuerpo" name="New Body Parts">
+ <menu_item_call label="Forma nueva" name="New Shape"/>
+ <menu_item_call label="Piel nueva" name="New Skin"/>
+ <menu_item_call label="Pelo nuevo" name="New Hair"/>
+ <menu_item_call label="Ojos nuevos" name="New Eyes"/>
+ </menu>
+ <menu label="Change Type" name="Change Type">
+ <menu_item_call label="Por defecto" name="Default"/>
+ <menu_item_call label="Guantes" name="Gloves"/>
+ <menu_item_call label="Chaqueta" name="Jacket"/>
+ <menu_item_call label="Pantalón" name="Pants"/>
+ <menu_item_call label="Forma" name="Shape"/>
+ <menu_item_call label="Zapatos" name="Shoes"/>
+ <menu_item_call label="Camisa" name="Shirt"/>
+ <menu_item_call label="Falda" name="Skirt"/>
+ <menu_item_call label="Ropa interior" name="Underpants"/>
+ <menu_item_call label="Camiseta" name="Undershirt"/>
+ </menu>
+ <menu_item_call label="Teleportar" name="Landmark Open"/>
+ <menu_item_call label="Abrir" name="Animation Open"/>
+ <menu_item_call label="Abrir" name="Sound Open"/>
+ <menu_item_call label="Reemplazar el vestuario" name="Replace Outfit"/>
+ <menu_item_call label="Añadir al vestuario" name="Add To Outfit"/>
+ <menu_item_call label="Quitar del vestuario actual" name="Remove From Outfit"/>
+ <menu_item_call label="Encontrar el original" name="Find Original"/>
+ <menu_item_call label="Eliminar el ítem" name="Purge Item"/>
+ <menu_item_call label="Restaurar el ítem" name="Restore Item"/>
+ <menu_item_call label="Abrir" name="Open"/>
+ <menu_item_call label="Abrir original" name="Open Original"/>
+ <menu_item_call label="Propiedades" name="Properties"/>
+ <menu_item_call label="Renombrar" name="Rename"/>
+ <menu_item_call label="Copiar la UUID" name="Copy Asset UUID"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+ <menu_item_call label="Pegar" name="Paste"/>
+ <menu_item_call label="Pegar como enlace" name="Paste As Link"/>
+ <menu_item_call label="Borrar" name="Remove Link"/>
+ <menu_item_call label="Borrar" name="Delete"/>
+ <menu_item_call label="Borrar carpeta del sistema" name="Delete System Folder"/>
+ <menu_item_call label="Empezar multiconferencia" name="Conference Chat Folder"/>
+ <menu_item_call label="Escuchar" name="Sound Play"/>
+ <menu_item_call label="Acerca del hito" name="About Landmark"/>
+ <menu_item_call label="Escuchar en el mundo" name="Animation Play"/>
+ <menu_item_call label="Ejecutarla para usted" name="Animation Audition"/>
+ <menu_item_call label="Enviar un mensaje instantáneo" name="Send Instant Message"/>
+ <menu_item_call label="Ofrecer teleporte..." name="Offer Teleport..."/>
+ <menu_item_call label="Empezar multiconferencia" name="Conference Chat"/>
+ <menu_item_call label="Activar" name="Activate"/>
+ <menu_item_call label="Desactivar" name="Deactivate"/>
+ <menu_item_call label="Guardar como" name="Save As"/>
+ <menu_item_call label="Quitarse" name="Detach From Yourself"/>
+ <menu_item_call label="Ponerme" name="Wearable And Object Wear"/>
+ <menu label="Anexar a" name="Attach To"/>
+ <menu label="Anexar como HUD" name="Attach To HUD"/>
+ <menu_item_call label="Editar" name="Wearable Edit"/>
+ <menu_item_call label="Añadir" name="Wearable Add"/>
+ <menu_item_call label="Quitarse" name="Take Off"/>
+ <menu_item_call label="--sin opciones--" name="--no options--"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_inventory_add.xml b/indra/newview/skins/minimal/xui/es/menu_inventory_add.xml
new file mode 100644
index 0000000000..ba106e8335
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_inventory_add.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_inventory_add">
+ <menu label="Subir" name="upload">
+ <menu_item_call label="Imagen ([COST] L$)..." name="Upload Image"/>
+ <menu_item_call label="Sonido ([COST] L$)..." name="Upload Sound"/>
+ <menu_item_call label="Animación ([COST] L$)..." name="Upload Animation"/>
+ <menu_item_call label="Masivo ([COST] L$ por archivo)..." name="Bulk Upload"/>
+ <menu_item_call label="Configurar los permisos por defecto de subida" name="perm prefs"/>
+ </menu>
+ <menu_item_call label="Carpeta nueva" name="New Folder"/>
+ <menu_item_call label="Script nuevo" name="New Script"/>
+ <menu_item_call label="Nota nueva" name="New Note"/>
+ <menu_item_call label="Gesto nuevo" name="New Gesture"/>
+ <menu label="Ropas nuevas" name="New Clothes">
+ <menu_item_call label="Camisa nueva" name="New Shirt"/>
+ <menu_item_call label="Pantalón nuevo" name="New Pants"/>
+ <menu_item_call label="Zapatos nuevos" name="New Shoes"/>
+ <menu_item_call label="Calcetines nuevos" name="New Socks"/>
+ <menu_item_call label="Chaqueta nueva" name="New Jacket"/>
+ <menu_item_call label="Falda nueva" name="New Skirt"/>
+ <menu_item_call label="Guantes nuevos" name="New Gloves"/>
+ <menu_item_call label="Camiseta nueva" name="New Undershirt"/>
+ <menu_item_call label="Ropa interior nueva" name="New Underpants"/>
+ <menu_item_call label="Nueva Alfa" name="New Alpha"/>
+ <menu_item_call label="Tatuaje nuevo" name="New Tattoo"/>
+ </menu>
+ <menu label="Nuevas partes del cuerpo" name="New Body Parts">
+ <menu_item_call label="Forma nueva" name="New Shape"/>
+ <menu_item_call label="Piel nueva" name="New Skin"/>
+ <menu_item_call label="Pelo nuevo" name="New Hair"/>
+ <menu_item_call label="Ojos nuevos" name="New Eyes"/>
+ </menu>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_inventory_gear_default.xml b/indra/newview/skins/minimal/xui/es/menu_inventory_gear_default.xml
new file mode 100644
index 0000000000..8e498fefba
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_inventory_gear_default.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="menu_gear_default">
+ <menu_item_call label="Nueva ventana del inventario" name="new_window"/>
+ <menu_item_check label="Ordenar alfabéticamente" name="sort_by_name"/>
+ <menu_item_check label="Ordenar por los más recientes" name="sort_by_recent"/>
+ <menu_item_check label="Las carpetas del sistema, arriba" name="sort_system_folders_to_top"/>
+ <menu_item_call label="Ver los filtros" name="show_filters"/>
+ <menu_item_call label="Restablecer los filtros" name="reset_filters"/>
+ <menu_item_call label="Cerrar todas las carpetas" name="close_folders"/>
+ <menu_item_call label="Vaciar Objetos Perdidos" name="empty_lostnfound"/>
+ <menu_item_call label="Guardar la textura como" name="Save Texture As"/>
+ <menu_item_call label="Compartir" name="Share"/>
+ <menu_item_call label="Encontrar el original" name="Find Original"/>
+ <menu_item_call label="Encontrar todos los enlazados" name="Find All Links"/>
+ <menu_item_call label="Vaciar la Papelera" name="empty_trash"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_land.xml b/indra/newview/skins/minimal/xui/es/menu_land.xml
new file mode 100644
index 0000000000..b0f15be1b6
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_land.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Land Pie">
+ <menu_item_call label="Acerca del terreno" name="Place Information..."/>
+ <menu_item_call label="Sentarme aquí" name="Sit Here"/>
+ <menu_item_call label="Comprar este terreno" name="Land Buy"/>
+ <menu_item_call label="Comprar un pase" name="Land Buy Pass"/>
+ <menu_item_call label="Construir" name="Create"/>
+ <menu_item_call label="Modificar el terreno" name="Edit Terrain"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_landmark.xml b/indra/newview/skins/minimal/xui/es/menu_landmark.xml
new file mode 100644
index 0000000000..f69b1539b8
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_landmark.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="landmark_overflow_menu">
+ <menu_item_call label="Copiar la SLurl" name="copy"/>
+ <menu_item_call label="Borrar" name="delete"/>
+ <menu_item_call label="Crear un Destacado" name="pick"/>
+ <menu_item_call label="Añadir a la barra de favoritos" name="add_to_favbar"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_login.xml b/indra/newview/skins/minimal/xui/es/menu_login.xml
new file mode 100644
index 0000000000..c27d624732
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_login.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu_bar name="Login Menu">
+ <menu label="Yo" name="File">
+ <menu_item_call label="Preferencias" name="Preferences..."/>
+ <menu_item_call label="Salir de [APP_NAME]" name="Quit"/>
+ </menu>
+ <menu label="Ayuda" name="Help">
+ <menu_item_call label="Ayuda de [SECOND_LIFE]" name="Second Life Help"/>
+ <menu_item_call label="Acerca de [APP_NAME]" name="About Second Life"/>
+ </menu>
+ <menu_item_check label="Mostrar el menú &apos;Debug&apos;" name="Show Debug Menu"/>
+ <menu label="Depurar" name="Debug">
+ <menu_item_call label="Mostrar las configuraciones del depurador" name="Debug Settings"/>
+ <menu_item_call label="Configuraciones del Visor/Color" name="UI/Color Settings"/>
+ <menu label="Pruebas de la interfaz" name="UI Tests"/>
+ <menu_item_call label="Definir el tamaño de la ventana..." name="Set Window Size..."/>
+ <menu_item_call label="Mostrar los &apos;TOS&apos;" name="TOS"/>
+ <menu_item_call label="Mostrar mensaje crítico" name="Critical"/>
+ <menu_item_call label="Prueba de navegadores de medios" name="Web Browser Test"/>
+ <menu_item_call label="Prueba de ventanas de contenidos web" name="Web Content Floater Test"/>
+ <menu_item_check label="Mostrar el selector de Grid" name="Show Grid Picker"/>
+ <menu_item_call label="Mostrar la consola de notificaciones" name="Show Notifications Console"/>
+ </menu>
+</menu_bar>
diff --git a/indra/newview/skins/minimal/xui/es/menu_mini_map.xml b/indra/newview/skins/minimal/xui/es/menu_mini_map.xml
new file mode 100644
index 0000000000..07d1b08572
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_mini_map.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Zoom cerca" name="Zoom Close"/>
+ <menu_item_call label="Zoom medio" name="Zoom Medium"/>
+ <menu_item_call label="Zoom lejos" name="Zoom Far"/>
+ <menu_item_call label="Zoom por defecto" name="Zoom Default"/>
+ <menu_item_check label="Girar el mapa" name="Rotate Map"/>
+ <menu_item_check label="Centrar automáticamente" name="Auto Center"/>
+ <menu_item_call label="Parar la búsqueda" name="Stop Tracking"/>
+ <menu_item_call label="Mapa del mundo" name="World Map"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_navbar.xml b/indra/newview/skins/minimal/xui/es/menu_navbar.xml
new file mode 100644
index 0000000000..63e5468020
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_navbar.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Navbar Menu">
+ <menu_item_check label="Mostrar las coordenadas" name="Show Coordinates"/>
+ <menu_item_check label="Mostrar las propiedades de la parcela" name="Show Parcel Properties"/>
+ <menu_item_call label="Hito" name="Landmark"/>
+ <menu_item_call label="Cortar" name="Cut"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+ <menu_item_call label="Pegar" name="Paste"/>
+ <menu_item_call label="Borrar" name="Delete"/>
+ <menu_item_call label="Seleccionar todo" name="Select All"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_nearby_chat.xml b/indra/newview/skins/minimal/xui/es/menu_nearby_chat.xml
new file mode 100644
index 0000000000..94b281b6c7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_nearby_chat.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="NearBy Chat Menu">
+ <menu_item_call label="Mostrar la gente que está cerca..." name="nearby_people"/>
+ <menu_item_check label="Ver el texto ignorado" name="muted_text"/>
+ <menu_item_check label="Mostrar los iconos del amigo" name="show_buddy_icons"/>
+ <menu_item_check label="Mostrar los nombres" name="show_names"/>
+ <menu_item_check label="Mostrar los iconos y los nombres" name="show_icons_and_names"/>
+ <menu_item_call label="Tamaño de la fuente" name="font_size"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_notification_well_button.xml b/indra/newview/skins/minimal/xui/es/menu_notification_well_button.xml
new file mode 100644
index 0000000000..0562d35be7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Cerrar todo" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_object.xml b/indra/newview/skins/minimal/xui/es/menu_object.xml
new file mode 100644
index 0000000000..06121e0c09
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_object.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Object Pie">
+ <menu_item_call label="Tocar" name="Object Touch">
+ <menu_item_call.on_enable name="EnableTouch" parameter="Tocar"/>
+ </menu_item_call>
+ <menu_item_call label="Editar" name="Edit..."/>
+ <menu_item_call label="Construir" name="Build"/>
+ <menu_item_call label="Abrir" name="Open"/>
+ <menu_item_call label="Sentarme aquí" name="Object Sit"/>
+ <menu_item_call label="Levantarme" name="Object Stand Up"/>
+ <menu_item_call label="Perfil del objeto" name="Object Inspect"/>
+ <menu_item_call label="Acercar el zoom" name="Zoom In"/>
+ <context_menu label="Ponerme" name="Put On">
+ <menu_item_call label="Ponerme" name="Wear"/>
+ <menu_item_call label="Añadir" name="Add"/>
+ <context_menu label="Anexar" name="Object Attach"/>
+ <context_menu label="Anexar el HUD" name="Object Attach HUD"/>
+ </context_menu>
+ <context_menu label="Quitar" name="Remove">
+ <menu_item_call label="Denunciar una infracción" name="Report Abuse..."/>
+ <menu_item_call label="Ignorar" name="Object Mute"/>
+ <menu_item_call label="Devolver" name="Return..."/>
+ <menu_item_call label="Eliminar" name="Delete"/>
+ </context_menu>
+ <menu_item_call label="Tomar" name="Pie Object Take"/>
+ <menu_item_call label="Coger una copia" name="Take Copy"/>
+ <menu_item_call label="Pagar" name="Pay..."/>
+ <menu_item_call label="Comprar" name="Buy..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_object_icon.xml b/indra/newview/skins/minimal/xui/es/menu_object_icon.xml
new file mode 100644
index 0000000000..7e4578b950
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_object_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Object Icon Menu">
+ <menu_item_call label="Perfil del objeto..." name="Object Profile"/>
+ <menu_item_call label="Ignorar..." name="Block"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_outfit_gear.xml b/indra/newview/skins/minimal/xui/es/menu_outfit_gear.xml
new file mode 100644
index 0000000000..3b11bceecf
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_outfit_gear.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear Outfit">
+ <menu_item_call label="Ponerme - Reemplazar el vestuario actual" name="wear"/>
+ <menu_item_call label="Ponerme - Añadir al vestuario actual" name="wear_add"/>
+ <menu_item_call label="Quitarme - Quitar del vestuario actual" name="take_off"/>
+ <menu label="Ropas nuevas" name="New Clothes">
+ <menu_item_call label="Camisa nueva" name="New Shirt"/>
+ <menu_item_call label="Pantalón nuevo" name="New Pants"/>
+ <menu_item_call label="Zapatos nuevos" name="New Shoes"/>
+ <menu_item_call label="Calcetines nuevos" name="New Socks"/>
+ <menu_item_call label="Chaqueta nueva" name="New Jacket"/>
+ <menu_item_call label="Falda nueva" name="New Skirt"/>
+ <menu_item_call label="Guantes nuevos" name="New Gloves"/>
+ <menu_item_call label="Camiseta nueva" name="New Undershirt"/>
+ <menu_item_call label="Ropa interior nueva" name="New Underpants"/>
+ <menu_item_call label="Nueva Alfa" name="New Alpha"/>
+ <menu_item_call label="Tatuaje nuevo" name="New Tattoo"/>
+ </menu>
+ <menu label="Nuevas partes del cuerpo" name="New Body Parts">
+ <menu_item_call label="Anatomía nueva" name="New Shape"/>
+ <menu_item_call label="Piel nueva" name="New Skin"/>
+ <menu_item_call label="Pelo nuevo" name="New Hair"/>
+ <menu_item_call label="Ojos nuevos" name="New Eyes"/>
+ </menu>
+ <menu_item_call label="Renombrar el vestuario" name="rename"/>
+ <menu_item_call label="Borrar el vestuario" name="delete_outfit"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_outfit_tab.xml b/indra/newview/skins/minimal/xui/es/menu_outfit_tab.xml
new file mode 100644
index 0000000000..4136082a62
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_outfit_tab.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Outfit">
+ <menu_item_call label="Ponerme - Reemplazar el vestuario actual" name="wear_replace"/>
+ <menu_item_call label="Ponerme - Añadir al vestuario actual" name="wear_add"/>
+ <menu_item_call label="Quitarme - Quitar del vestuario actual" name="take_off"/>
+ <menu_item_call label="Editar el vestuario" name="edit"/>
+ <menu_item_call label="Renombrar el vestuario" name="rename"/>
+ <menu_item_call label="Borrar el vestuario" name="delete"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_participant_list.xml b/indra/newview/skins/minimal/xui/es/menu_participant_list.xml
new file mode 100644
index 0000000000..f6eedd1170
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_participant_list.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Participant List Context Menu">
+ <menu_item_check label="Ordenar alfabéticamente" name="SortByName"/>
+ <menu_item_check label="Ordenar según las intervenciones recientes" name="SortByRecentSpeakers"/>
+ <menu_item_call label="Ver el perfil" name="View Profile"/>
+ <menu_item_call label="Añadir como amigo" name="Add Friend"/>
+ <menu_item_call label="MI" name="IM"/>
+ <menu_item_call label="Llamar" name="Call"/>
+ <menu_item_call label="Compartir" name="Share"/>
+ <menu_item_call label="Pagar" name="Pay"/>
+ <menu_item_check label="Ver los iconos de la gente" name="View Icons"/>
+ <menu_item_check label="Ignorar la voz" name="Block/Unblock"/>
+ <menu_item_check label="Ignorar el texto" name="MuteText"/>
+ <context_menu label="Opciones del moderador" name="Moderator Options">
+ <menu_item_check label="Permitir el chat de texto" name="AllowTextChat"/>
+ <menu_item_call label="Ignorar a este participante" name="ModerateVoiceMuteSelected"/>
+ <menu_item_call label="Quitar el silencio a este participante" name="ModerateVoiceUnMuteSelected"/>
+ <menu_item_call label="Silenciar a todos" name="ModerateVoiceMute"/>
+ <menu_item_call label="Quitar el silencio a todos" name="ModerateVoiceUnmute"/>
+ </context_menu>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_people_friends_view_sort.xml b/indra/newview/skins/minimal/xui/es/menu_people_friends_view_sort.xml
new file mode 100644
index 0000000000..3899ad9e96
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_people_friends_view_sort.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Ordenar alfabéticamente" name="sort_name"/>
+ <menu_item_check label="Ordenar por estatus" name="sort_status"/>
+ <menu_item_check label="Ver los iconos de la gente" name="view_icons"/>
+ <menu_item_check label="Ver permisos concedidos" name="view_permissions"/>
+ <menu_item_call label="Ver la lista de Residentes y Objetos ignorados" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_people_groups.xml b/indra/newview/skins/minimal/xui/es/menu_people_groups.xml
new file mode 100644
index 0000000000..51bd2c7208
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_people_groups.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_call label="Ver la información" name="View Info"/>
+ <menu_item_call label="Chat" name="Chat"/>
+ <menu_item_call label="Llamar" name="Call"/>
+ <menu_item_call label="Activar" name="Activate"/>
+ <menu_item_call label="Dejar" name="Leave"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_people_groups_view_sort.xml b/indra/newview/skins/minimal/xui/es/menu_people_groups_view_sort.xml
new file mode 100644
index 0000000000..1bd3efb611
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_people_groups_view_sort.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Mostrar los iconos de grupo" name="Display Group Icons"/>
+ <menu_item_call label="Dejar el grupo seleccionado" name="Leave Selected Group"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_people_nearby.xml b/indra/newview/skins/minimal/xui/es/menu_people_nearby.xml
new file mode 100644
index 0000000000..dc1486d879
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_people_nearby.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Avatar Context Menu">
+ <menu_item_call label="Ver el perfil" name="View Profile"/>
+ <menu_item_call label="Añadir como amigo" name="Add Friend"/>
+ <menu_item_call label="Quitarle como amigo" name="Remove Friend"/>
+ <menu_item_call label="MI" name="IM"/>
+ <menu_item_call label="Llamar" name="Call"/>
+ <menu_item_call label="Mapa" name="Map"/>
+ <menu_item_call label="Compartir" name="Share"/>
+ <menu_item_call label="Pagar" name="Pay"/>
+ <menu_item_check label="Ignorar / No ignorar" name="Block/Unblock"/>
+ <menu_item_call label="Ofrecer teleporte" name="teleport"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_people_nearby_multiselect.xml b/indra/newview/skins/minimal/xui/es/menu_people_nearby_multiselect.xml
new file mode 100644
index 0000000000..227c5ebe58
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_people_nearby_multiselect.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Multi-Selected People Context Menu">
+ <menu_item_call label="Añadir como amigos" name="Add Friends"/>
+ <menu_item_call label="Quitar amigos" name="Remove Friend"/>
+ <menu_item_call label="MI" name="IM"/>
+ <menu_item_call label="Llamar" name="Call"/>
+ <menu_item_call label="Compartir" name="Share"/>
+ <menu_item_call label="Pagar" name="Pay"/>
+ <menu_item_call label="Ofrecer teleporte" name="teleport"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_people_nearby_view_sort.xml b/indra/newview/skins/minimal/xui/es/menu_people_nearby_view_sort.xml
new file mode 100644
index 0000000000..f0fe383c0c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_people_nearby_view_sort.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Ordenar según las intervenciones recientes" name="sort_by_recent_speakers"/>
+ <menu_item_check label="Ordenar alfabéticamente" name="sort_name"/>
+ <menu_item_check label="Ordenar según distancia" name="sort_distance"/>
+ <menu_item_check label="Ver los iconos de la gente" name="view_icons"/>
+ <menu_item_call label="Ver la lista de Residentes y Objetos ignorados" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_people_recent_view_sort.xml b/indra/newview/skins/minimal/xui/es/menu_people_recent_view_sort.xml
new file mode 100644
index 0000000000..e4aaa89110
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_people_recent_view_sort.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Ordenar por los más recientes" name="sort_most"/>
+ <menu_item_check label="Ordenar alfabéticamente" name="sort_name"/>
+ <menu_item_check label="Ver los iconos de la gente" name="view_icons"/>
+ <menu_item_call label="Ver la lista de Residentes y Objetos ignorados" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_picks.xml b/indra/newview/skins/minimal/xui/es/menu_picks.xml
new file mode 100644
index 0000000000..9da68d7c9b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_picks.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Picks">
+ <menu_item_call label="Información" name="pick_info"/>
+ <menu_item_call label="Editar" name="pick_edit"/>
+ <menu_item_call label="Teleportar" name="pick_teleport"/>
+ <menu_item_call label="Mapa" name="pick_map"/>
+ <menu_item_call label="Eliminar" name="pick_delete"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_picks_plus.xml b/indra/newview/skins/minimal/xui/es/menu_picks_plus.xml
new file mode 100644
index 0000000000..cc59bf1d29
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_picks_plus.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="picks_plus_menu">
+ <menu_item_call label="Destacado nuevo" name="create_pick"/>
+ <menu_item_call label="Clasificado nuevo" name="create_classified"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_place.xml b/indra/newview/skins/minimal/xui/es/menu_place.xml
new file mode 100644
index 0000000000..675f0699e9
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_place.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="place_overflow_menu">
+ <menu_item_call label="Crear un hito" name="landmark"/>
+ <menu_item_call label="Crear un destacado" name="pick"/>
+ <menu_item_call label="Comprar un pase" name="pass"/>
+ <menu_item_call label="Editar" name="edit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_place_add_button.xml b/indra/newview/skins/minimal/xui/es/menu_place_add_button.xml
new file mode 100644
index 0000000000..4b2f908a06
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_place_add_button.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_folder_gear">
+ <menu_item_call label="Añadir una carpeta" name="add_folder"/>
+ <menu_item_call label="Añadir este hito" name="add_landmark"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_places_gear_folder.xml b/indra/newview/skins/minimal/xui/es/menu_places_gear_folder.xml
new file mode 100644
index 0000000000..bf46eb58e3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_places_gear_folder.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_folder_gear">
+ <menu_item_call label="Añadir este hito" name="add_landmark"/>
+ <menu_item_call label="Añadir una carpeta" name="add_folder"/>
+ <menu_item_call label="Cortar" name="cut"/>
+ <menu_item_call label="Copiar" name="copy_folder"/>
+ <menu_item_call label="Pegar" name="paste"/>
+ <menu_item_call label="Renombrar" name="rename"/>
+ <menu_item_call label="Borrar" name="delete"/>
+ <menu_item_call label="Abrir" name="expand"/>
+ <menu_item_call label="Cerrar" name="collapse"/>
+ <menu_item_call label="Abrir todas las carpetas" name="expand_all"/>
+ <menu_item_call label="Cerrar todas las carpetas" name="collapse_all"/>
+ <menu_item_check label="Ordenar por fecha" name="sort_by_date"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_places_gear_landmark.xml b/indra/newview/skins/minimal/xui/es/menu_places_gear_landmark.xml
new file mode 100644
index 0000000000..eac85de846
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_places_gear_landmark.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_ladmark_gear">
+ <menu_item_call label="Teleportar" name="teleport"/>
+ <menu_item_call label="Más información" name="more_info"/>
+ <menu_item_call label="Mostrar en el mapa" name="show_on_map"/>
+ <menu_item_call label="Añadir un hito" name="add_landmark"/>
+ <menu_item_call label="Añadir una carpeta" name="add_folder"/>
+ <menu_item_call label="Cortar" name="cut"/>
+ <menu_item_call label="Copiar el hito" name="copy_landmark"/>
+ <menu_item_call label="Copiar la SLurl" name="copy_slurl"/>
+ <menu_item_call label="Pegar" name="paste"/>
+ <menu_item_call label="Renombrar" name="rename"/>
+ <menu_item_call label="Eliminar" name="delete"/>
+ <menu_item_call label="Abrir todas las carpetas" name="expand_all"/>
+ <menu_item_call label="Cerrar todas las carpetas" name="collapse_all"/>
+ <menu_item_check label="Ordenar por fecha" name="sort_by_date"/>
+ <menu_item_call label="Crear un Destacado" name="create_pick"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_profile_overflow.xml b/indra/newview/skins/minimal/xui/es/menu_profile_overflow.xml
new file mode 100644
index 0000000000..5ee8c50949
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_profile_overflow.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="profile_overflow_menu">
+ <menu_item_call label="Mapa" name="show_on_map"/>
+ <menu_item_call label="Pagar" name="pay"/>
+ <menu_item_call label="Compartir" name="share"/>
+ <menu_item_call label="Ignorar" name="block"/>
+ <menu_item_call label="Designorar" name="unblock"/>
+ <menu_item_call label="Expulsar" name="kick"/>
+ <menu_item_call label="Congelar" name="freeze"/>
+ <menu_item_call label="Descongelar" name="unfreeze"/>
+ <menu_item_call label="CSR" name="csr"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_save_outfit.xml b/indra/newview/skins/minimal/xui/es/menu_save_outfit.xml
new file mode 100644
index 0000000000..a04ec75b60
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="Guardar" name="save_outfit"/>
+ <menu_item_call label="Guardar como" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_script_chiclet.xml b/indra/newview/skins/minimal/xui/es/menu_script_chiclet.xml
new file mode 100644
index 0000000000..f517baf566
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="Cerrar" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_slurl.xml b/indra/newview/skins/minimal/xui/es/menu_slurl.xml
new file mode 100644
index 0000000000..ca19acec6e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_slurl.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Acerca de la URL" name="about_url"/>
+ <menu_item_call label="Teleportar a la URL" name="teleport_to_url"/>
+ <menu_item_call label="Mapa" name="show_on_map"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_teleport_history_gear.xml b/indra/newview/skins/minimal/xui/es/menu_teleport_history_gear.xml
new file mode 100644
index 0000000000..b708f3bc20
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_teleport_history_gear.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Teleport History Gear Context Menu">
+ <menu_item_call label="Abrir todas las carpetas" name="Expand all folders"/>
+ <menu_item_call label="Cerrar todas las carpetas" name="Collapse all folders"/>
+ <menu_item_call label="Limpiar el historial de teleportes" name="Clear Teleport History"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_teleport_history_item.xml b/indra/newview/skins/minimal/xui/es/menu_teleport_history_item.xml
new file mode 100644
index 0000000000..ed33c55aca
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_teleport_history_item.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Teleport History Item Context Menu">
+ <menu_item_call label="Teleportarse" name="Teleport"/>
+ <menu_item_call label="Más información" name="More Information"/>
+ <menu_item_call label="Copiar al portapapeles" name="CopyToClipboard"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_teleport_history_tab.xml b/indra/newview/skins/minimal/xui/es/menu_teleport_history_tab.xml
new file mode 100644
index 0000000000..17e90422a5
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_teleport_history_tab.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Teleport History Item Context Menu">
+ <menu_item_call label="Abrir" name="TabOpen"/>
+ <menu_item_call label="Cerrar" name="TabClose"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_text_editor.xml b/indra/newview/skins/minimal/xui/es/menu_text_editor.xml
new file mode 100644
index 0000000000..095e461734
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_text_editor.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Text editor context menu">
+ <menu_item_call label="Cortar" name="Cut"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+ <menu_item_call label="Pegar" name="Paste"/>
+ <menu_item_call label="Borrar" name="Delete"/>
+ <menu_item_call label="Seleccionar todo" name="Select All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_topinfobar.xml b/indra/newview/skins/minimal/xui/es/menu_topinfobar.xml
new file mode 100644
index 0000000000..2125fd51b2
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_topinfobar.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_topinfobar">
+ <menu_item_check label="Mostrar las coordenadas" name="Show Coordinates"/>
+ <menu_item_check label="Mostrar las propiedades de la parcela" name="Show Parcel Properties"/>
+ <menu_item_call label="Hito" name="Landmark"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_url_agent.xml b/indra/newview/skins/minimal/xui/es/menu_url_agent.xml
new file mode 100644
index 0000000000..a089c8f68e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_url_agent.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar el perfil del Residente" name="show_agent"/>
+ <menu_item_call label="Copiar el nombre al portapapeles" name="url_copy_label"/>
+ <menu_item_call label="Copiar la SLurl al portapapeles" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_url_group.xml b/indra/newview/skins/minimal/xui/es/menu_url_group.xml
new file mode 100644
index 0000000000..79374b9739
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_url_group.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar la información del grupo" name="show_group"/>
+ <menu_item_call label="Copiar el grupo al portapapeles" name="url_copy_label"/>
+ <menu_item_call label="Copiar la SLurl al portapapeles" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_url_http.xml b/indra/newview/skins/minimal/xui/es/menu_url_http.xml
new file mode 100644
index 0000000000..585c059ff3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_url_http.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Abrir la página web" name="url_open"/>
+ <menu_item_call label="Abrir en el navegador incorporado" name="url_open_internal"/>
+ <menu_item_call label="Abrir en mi navegador" name="url_open_external"/>
+ <menu_item_call label="Copiar la URL al portapapeles" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_url_inventory.xml b/indra/newview/skins/minimal/xui/es/menu_url_inventory.xml
new file mode 100644
index 0000000000..13a8711c76
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_url_inventory.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar ítem del inventario" name="show_item"/>
+ <menu_item_call label="Copiar el nombre al portapapeles" name="url_copy_label"/>
+ <menu_item_call label="Copiar la SLurl al portapapeles" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_url_map.xml b/indra/newview/skins/minimal/xui/es/menu_url_map.xml
new file mode 100644
index 0000000000..f96a0c7170
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_url_map.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar en el mapa" name="show_on_map"/>
+ <menu_item_call label="Teleportarse a la localización" name="teleport_to_location"/>
+ <menu_item_call label="Copiar la SLurl al portapapeles" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_url_objectim.xml b/indra/newview/skins/minimal/xui/es/menu_url_objectim.xml
new file mode 100644
index 0000000000..8791a290af
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_url_objectim.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar la información del objeto" name="show_object"/>
+ <menu_item_call label="Mostrar en el mapa" name="show_on_map"/>
+ <menu_item_call label="Teleportarse a la posición del objeto" name="teleport_to_object"/>
+ <menu_item_call label="Copiar el nombre del objeto al portapapeles" name="url_copy_label"/>
+ <menu_item_call label="Copiar la SLurl al portapapeles" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_url_parcel.xml b/indra/newview/skins/minimal/xui/es/menu_url_parcel.xml
new file mode 100644
index 0000000000..9e789ef8ee
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_url_parcel.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar la información de la parcela" name="show_parcel"/>
+ <menu_item_call label="Mostrar en el mapa" name="show_on_map"/>
+ <menu_item_call label="Copiar la SLurl al portapapeles" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_url_slapp.xml b/indra/newview/skins/minimal/xui/es/menu_url_slapp.xml
new file mode 100644
index 0000000000..7147dcd3cf
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_url_slapp.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Ejecutar este comando" name="run_slapp"/>
+ <menu_item_call label="Copiar la SLurl al portapapeles" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_url_slurl.xml b/indra/newview/skins/minimal/xui/es/menu_url_slurl.xml
new file mode 100644
index 0000000000..4ab47c2f61
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_url_slurl.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar la información del lugar" name="show_place"/>
+ <menu_item_call label="Mostrar en el mapa" name="show_on_map"/>
+ <menu_item_call label="Teleportarse a este lugar" name="teleport_to_location"/>
+ <menu_item_call label="Copiar la SLurl al portapapeles" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_url_teleport.xml b/indra/newview/skins/minimal/xui/es/menu_url_teleport.xml
new file mode 100644
index 0000000000..8f86a91be3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_url_teleport.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Teleportarse a este lugar" name="teleport"/>
+ <menu_item_call label="Mostrar en el mapa" name="show_on_map"/>
+ <menu_item_call label="Copiar la SLurl al portapapeles" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_viewer.xml b/indra/newview/skins/minimal/xui/es/menu_viewer.xml
new file mode 100644
index 0000000000..776ccfe21b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_viewer.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu_bar name="Main Menu">
+ <menu label="Ayuda" name="Help">
+ <menu_item_call label="Ayuda de [SECOND_LIFE]" name="Second Life Help"/>
+ </menu>
+ <menu label="Avanzado" name="Advanced">
+ <menu label="Atajos de teclado" name="Shortcuts">
+ <menu_item_check label="Volar" name="Fly"/>
+ <menu_item_call label="Cerrar la ventana" name="Close Window"/>
+ <menu_item_call label="Cerrar todas las ventanas" name="Close All Windows"/>
+ <menu_item_call label="Volver a la vista por defecto" name="Reset View"/>
+ </menu>
+ </menu>
+</menu_bar>
diff --git a/indra/newview/skins/minimal/xui/es/menu_wearable_list_item.xml b/indra/newview/skins/minimal/xui/es/menu_wearable_list_item.xml
new file mode 100644
index 0000000000..4bffa689e7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_wearable_list_item.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Outfit Wearable Context Menu">
+ <menu_item_call label="Reemplazar" name="wear_replace"/>
+ <menu_item_call label="Ponerme" name="wear_wear"/>
+ <menu_item_call label="Añadir" name="wear_add"/>
+ <menu_item_call label="Quitarme / Quitar" name="take_off_or_detach"/>
+ <menu_item_call label="Quitar" name="detach"/>
+ <context_menu label="Anexar a" name="wearable_attach_to"/>
+ <context_menu label="Anexar al HUD" name="wearable_attach_to_hud"/>
+ <menu_item_call label="Quitarme" name="take_off"/>
+ <menu_item_call label="Editar" name="edit"/>
+ <menu_item_call label="Perfil del elemento" name="object_profile"/>
+ <menu_item_call label="Mostrar original" name="show_original"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_wearing_gear.xml b/indra/newview/skins/minimal/xui/es/menu_wearing_gear.xml
new file mode 100644
index 0000000000..9d9ce75e53
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_wearing_gear.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear Wearing">
+ <menu_item_call label="Editar el vestuario" name="edit"/>
+ <menu_item_call label="Quitarme" name="takeoff"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/es/menu_wearing_tab.xml b/indra/newview/skins/minimal/xui/es/menu_wearing_tab.xml
new file mode 100644
index 0000000000..64fd7ce4cf
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/menu_wearing_tab.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Wearing">
+ <menu_item_call label="Quitarme" name="take_off"/>
+ <menu_item_call label="Quitar" name="detach"/>
+ <menu_item_call label="Editar el vestuario" name="edit"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/es/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/es/panel_bottomtray.xml
new file mode 100644
index 0000000000..9ab30b5613
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/panel_bottomtray.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="bottom_tray">
+ <string name="DragIndicationImageName" value="Accordion_ArrowOpened_Off"/>
+ <string name="SpeakBtnToolTip" value="Activa/Desactiva el micrófono"/>
+ <string name="VoiceControlBtnToolTip" value="Muestra/Oculta el panel del control de voz"/>
+ <layout_stack name="toolbar_stack">
+ <layout_panel name="gesture_panel">
+ <gesture_combo_list label="Gestos" name="Gesture" tool_tip="Muestra/Oculta los gestos"/>
+ </layout_panel>
+ <layout_panel name="cam_panel">
+ <bottomtray_button label="Visión" name="camera_btn" tool_tip="Muestra/Oculta los controles de la cámara"/>
+ </layout_panel>
+ <layout_panel name="avatar_and_destinations_panel">
+ <radio_group name="avatar_and_destination_btns">
+ <radio_item name="destination_btn" value="0"/>
+ <radio_item name="avatar_btn" value="1"/>
+ </radio_group>
+ </layout_panel>
+ <layout_panel name="people_panel">
+ <bottomtray_button label="Gente" name="show_people_button" tool_tip="Muestra la ventana de gente"/>
+ </layout_panel>
+ <layout_panel name="profile_panel">
+ <bottomtray_button label="Perfil" name="show_profile_btn" tool_tip="Muestra la ventana del perfil"/>
+ </layout_panel>
+ <layout_panel name="howto_panel">
+ <bottomtray_button label="Indicaciones" name="show_help_btn" tool_tip="Abrir los temas sobre indicaciones de Second Life"/>
+ </layout_panel>
+ <layout_panel name="im_well_panel">
+ <chiclet_im_well name="im_well">
+ <button name="Unread IM messages" tool_tip="Conversaciones"/>
+ </chiclet_im_well>
+ </layout_panel>
+ <layout_panel name="notification_well_panel">
+ <chiclet_notification name="notification_well">
+ <button name="Unread" tool_tip="Notificaciones"/>
+ </chiclet_notification>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/es/panel_im_control_panel.xml b/indra/newview/skins/minimal/xui/es/panel_im_control_panel.xml
new file mode 100644
index 0000000000..7d4db6a630
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/panel_im_control_panel.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_im_control_panel">
+ <layout_stack name="button_stack">
+ <layout_panel name="view_profile_btn_panel">
+ <button label="Perfil" name="view_profile_btn"/>
+ </layout_panel>
+ <layout_panel name="add_friend_btn_panel">
+ <button label="Añadir como amigo" name="add_friend_btn"/>
+ </layout_panel>
+ <layout_panel name="teleport_btn_panel">
+ <button label="Teleportarme" name="teleport_btn" tool_tip="Ofrecer teleporte a esta persona"/>
+ </layout_panel>
+ <layout_panel name="share_btn_panel">
+ <button label="Compartir" name="share_btn"/>
+ </layout_panel>
+ <layout_panel name="pay_btn_panel">
+ <button label="Pagar" name="pay_btn"/>
+ </layout_panel>
+ <layout_panel name="call_btn_panel">
+ <button label="Llamar" name="call_btn"/>
+ </layout_panel>
+ <layout_panel name="end_call_btn_panel">
+ <button label="Colgar" name="end_call_btn"/>
+ </layout_panel>
+ <layout_panel name="voice_ctrls_btn_panel">
+ <button label="Controles de la voz" name="voice_ctrls_btn"/>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/es/panel_login.xml b/indra/newview/skins/minimal/xui/es/panel_login.xml
new file mode 100644
index 0000000000..161ea19b0e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/panel_login.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_login">
+ <panel.string name="create_account_url">
+ http://join.secondlife.com/index.php?lang=es-ES
+ </panel.string>
+ <panel.string name="forgot_password_url">
+ http://secondlife.com/account/request.php?lang=es
+ </panel.string>
+ <layout_stack name="login_widgets">
+ <layout_panel name="login">
+ <text name="username_text">
+ Nombre de usuario:
+ </text>
+ <combo_box name="username_combo" tool_tip="El nombre de usuario que elegiste al registrarte, como bobsmith12 o Steller Sunshine"/>
+ <text name="password_text">
+ Contraseña:
+ </text>
+ <check_box label="Recordar la contraseña" name="remember_check"/>
+ <button label="Iniciar sesión" name="connect_btn"/>
+ <text name="mode_selection_text">
+ Modo:
+ </text>
+ <combo_box name="mode_combo">
+ <combo_box.item label="Básico (Predeterminado)" name="Basic"/>
+ <combo_box.item label="Avanzado" name="Advanced"/>
+ </combo_box>
+ </layout_panel>
+ <layout_panel name="links">
+ <text name="create_new_account_text">
+ Registrarme
+ </text>
+ <text name="forgot_password_text">
+ ¿Olvidaste el nombre de usuario o la contraseña?
+ </text>
+ <text name="login_help">
+ ¿Necesitas ayuda para conectarte?
+ </text>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/es/panel_navigation_bar.xml b/indra/newview/skins/minimal/xui/es/panel_navigation_bar.xml
new file mode 100644
index 0000000000..e8e95c3bac
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/panel_navigation_bar.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="navigation_bar">
+ <panel name="navigation_panel">
+ <pull_button name="back_btn" tool_tip="Volver a lo localización anterior"/>
+ <pull_button name="forward_btn" tool_tip="Ir una localización adelante"/>
+ <button name="home_btn" tool_tip="Teleportar a mi Base"/>
+ <location_input label="Localización" name="location_combo"/>
+ <search_combo_box label="Buscar" name="search_combo_box" tool_tip="Buscar">
+ <combo_editor label="Buscar en [SECOND_LIFE]" name="search_combo_editor"/>
+ </search_combo_box>
+ </panel>
+ <favorites_bar name="favorite" tool_tip="¡Accede rápidamente a tus lugares favoritos de Second Life arrastrando hitos hasta aquí!">
+ <label name="favorites_bar_label" tool_tip="¡Accede rápidamente a tus lugares favoritos de Second Life arrastrando hitos hasta aquí!">
+ Barra de Favoritos
+ </label>
+ <chevron_button name="&gt;&gt;" tool_tip="Ver más de Mis favoritos"/>
+ </favorites_bar>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/es/panel_people.xml b/indra/newview/skins/minimal/xui/es/panel_people.xml
new file mode 100644
index 0000000000..7d3157ef45
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/panel_people.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray panel -->
+<panel label="Gente" name="people_panel">
+ <string name="no_recent_people" value="No hay gente reciente. ¿Estás buscando gente con la que juntarte? Prueba con el botón Destinos que aparece a continuación."/>
+ <string name="no_filtered_recent_people" value="No hay gente reciente con ese nombre."/>
+ <string name="no_one_near" value="No hay nadie cerca. ¿Estás buscando gente con la que juntarte? Prueba con el botón Destinos que aparece a continuación."/>
+ <string name="no_one_filtered_near" value="No hay nadie cerca con ese nombre."/>
+ <string name="no_friends_online" value="No hay amigos conectados"/>
+ <string name="no_friends" value="No hay amigos"/>
+ <string name="no_friends_msg">
+ Haz clic con el botón derecho del ratón en un residente para agregarlo como amigo.
+¿Estás buscando gente con la que juntarte? Prueba con el botón Destinos que aparece a continuación.
+ </string>
+ <string name="no_filtered_friends_msg">
+ ¿No encuentras lo que buscas? Prueba con el botón Destinos que aparece a continuación.
+ </string>
+ <string name="people_filter_label" value="Filtrar a la gente"/>
+ <string name="groups_filter_label" value="Filtrar a los grupos"/>
+ <string name="no_filtered_groups_msg" value="¿No encuentras lo que buscas? Prueba con [secondlife:///app/search/groups/[SEARCH_TERM] Buscar]."/>
+ <string name="no_groups_msg" value="¿Buscas grupos en que participar? Prueba la [secondlife:///app/search/groups Búsqueda]."/>
+ <string name="MiniMapToolTipMsg" value="[REGIÓN](Haz doble clic para abrir el mapa y pulsa la tecla Mayús y arrastra para obtener una vista panorámica)"/>
+ <string name="AltMiniMapToolTipMsg" value="[REGIÓN](Haz doble clic para teleportarte y pulsa la tecla Mayús y arrastra para obtener una vista panorámica)"/>
+ <filter_editor label="Filtrar" name="filter_input"/>
+ <tab_container name="tabs">
+ <panel label="CERCANA" name="nearby_panel">
+ <panel label="bottom_panel" name="bottom_panel"/>
+ </panel>
+ <panel label="MIS AMIGOS" name="friends_panel">
+ <accordion name="friends_accordion">
+ <accordion_tab name="tab_online" title="Conectado"/>
+ <accordion_tab name="tab_all" title="Todos"/>
+ </accordion>
+ <panel label="bottom_panel" name="bottom_panel">
+ <layout_stack name="bottom_panel">
+ <layout_panel name="trash_btn_panel">
+ <dnd_button name="del_btn" tool_tip="Quitar a la persona seleccionada de tu lista de amigos"/>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </panel>
+ <panel label="RECIENTE" name="recent_panel">
+ <panel label="bottom_panel" name="bottom_panel">
+ <button name="add_friend_btn" tool_tip="Añadir al Residente seleccionado a la lista de tus amigos"/>
+ </panel>
+ </panel>
+ </tab_container>
+ <panel name="button_bar">
+ <layout_stack name="bottom_bar_ls">
+ <layout_panel name="view_profile_btn_lp">
+ <button label="Perfil" name="view_profile_btn" tool_tip="Mostrar imágenes, grupos y otra información del Residente"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="MI" name="im_btn" tool_tip="Abrir una sesión de mensajes instantáneos"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="Teleporte" name="teleport_btn" tool_tip="Ofrecer teleporte"/>
+ </layout_panel>
+ </layout_stack>
+ <layout_stack name="bottom_bar_ls1">
+ <layout_panel name="group_info_btn_lp">
+ <button label="Perfil del grupo" name="group_info_btn" tool_tip="Ver la información del grupo"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="Chat de grupo" name="chat_btn" tool_tip="Abrir el chat"/>
+ </layout_panel>
+ <layout_panel name="group_call_btn_lp">
+ <button label="Llamar al grupo" name="group_call_btn" tool_tip="Llama a este grupo"/>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/es/panel_side_tray_tab_caption.xml b/indra/newview/skins/minimal/xui/es/panel_side_tray_tab_caption.xml
new file mode 100644
index 0000000000..775e343dc9
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/panel_side_tray_tab_caption.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="sidetray_tab_panel">
+ <text name="sidetray_tab_title" value="Panel lateral"/>
+ <button name="undock" tool_tip="Soltar"/>
+ <button name="dock" tool_tip="Fijar"/>
+ <button name="show_help" tool_tip="Ver ayuda"/>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/es/panel_status_bar.xml b/indra/newview/skins/minimal/xui/es/panel_status_bar.xml
new file mode 100644
index 0000000000..ab76d3f994
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/es/panel_status_bar.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="status">
+ <panel.string name="StatBarDaysOfWeek">
+ Domingo:Lunes:Martes:Miércoles:Jueves:Viernes:Sábado
+ </panel.string>
+ <panel.string name="StatBarMonthsOfYear">
+ Enero:Febrero:Marzo:Abril:Mayo:Junio:Julio:Agosto:Septiembre:Octubre:Noviembre:Diciembre
+ </panel.string>
+ <panel.string name="packet_loss_tooltip">
+ Pérdida de paquetes
+ </panel.string>
+ <panel.string name="bandwidth_tooltip">
+ Ancho de banda
+ </panel.string>
+ <panel.string name="time">
+ [hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]
+ </panel.string>
+ <panel.string name="timeTooltip">
+ [weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]
+ </panel.string>
+ <panel.string name="buycurrencylabel">
+ [AMT] L$
+ </panel.string>
+ <panel name="balance_bg">
+ <text name="balance" tool_tip="Haz clic para actualizar tu saldo en L$" value="20 L$"/>
+ <button label="COMPRAR L$" name="buyL" tool_tip="Pulsa para comprar más L$"/>
+ </panel>
+ <text name="TimeText" tool_tip="Hora actual (Pacífico)">
+ 24:00 AM PST
+ </text>
+ <button name="media_toggle_btn" tool_tip="Iniciar/Parar todos los media (música, vídeo, páginas web)"/>
+ <button name="volume_btn" tool_tip="Control general del volumen"/>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/fr/floater_camera.xml b/indra/newview/skins/minimal/xui/fr/floater_camera.xml
new file mode 100644
index 0000000000..1d62a89ff2
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/floater_camera.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="camera_floater">
+ <floater.string name="rotate_tooltip">
+ Faire tourner la caméra autour du point central
+ </floater.string>
+ <floater.string name="zoom_tooltip">
+ Zoomer en direction du point central
+ </floater.string>
+ <floater.string name="move_tooltip">
+ Déplacer la caméra vers le haut et le bas, la gauche et la droite
+ </floater.string>
+ <floater.string name="camera_modes_title">
+ Modes
+ </floater.string>
+ <floater.string name="pan_mode_title">
+ Rotation - Zoom - Panoramique
+ </floater.string>
+ <floater.string name="presets_mode_title">
+ Préréglages
+ </floater.string>
+ <floater.string name="free_mode_title">
+ Voir l&apos;objet
+ </floater.string>
+ <panel name="controls">
+ <panel name="preset_views_list">
+ <panel_camera_item name="front_view">
+ <panel_camera_item.text name="front_view_text">
+ Vue frontale
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="group_view">
+ <panel_camera_item.text name="side_view_text">
+ Vue latérale
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="rear_view">
+ <panel_camera_item.text name="rear_view_text">
+ Vue arrière
+ </panel_camera_item.text>
+ </panel_camera_item>
+ </panel>
+ <panel name="camera_modes_list">
+ <panel_camera_item name="object_view">
+ <panel_camera_item.text name="object_view_text">
+ Vue de l&apos;objet
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="mouselook_view">
+ <panel_camera_item.text name="mouselook_view_text">
+ Vue subjective
+ </panel_camera_item.text>
+ </panel_camera_item>
+ </panel>
+ <panel name="zoom" tool_tip="Zoomer en direction du point central">
+ <joystick_rotate name="cam_rotate_stick" tool_tip="Faire tourner la caméra autour du point central"/>
+ <slider_bar name="zoom_slider" tool_tip="Zoomer en direction du point central"/>
+ <joystick_track name="cam_track_stick" tool_tip="Déplacer la caméra vers le haut et le bas, la gauche et la droite"/>
+ </panel>
+ </panel>
+ <panel name="buttons">
+ <button label="" name="presets_btn" tool_tip="Préréglages"/>
+ <button label="" name="pan_btn" tool_tip="Rotation - Zoom - Panoramique"/>
+ <button label="" name="avatarview_btn" tool_tip="Modes"/>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/fr/floater_help_browser.xml b/indra/newview/skins/minimal/xui/fr/floater_help_browser.xml
new file mode 100644
index 0000000000..09d763b809
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/floater_help_browser.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_help_browser" title="AIDE RAPIDE">
+ <floater.string name="loading_text">
+ Chargement…
+ </floater.string>
+ <layout_stack name="stack1">
+ <layout_panel name="external_controls"/>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/fr/floater_nearby_chat.xml b/indra/newview/skins/minimal/xui/fr/floater_nearby_chat.xml
new file mode 100644
index 0000000000..9b1b21c434
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/floater_nearby_chat.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="nearby_chat" title="CHAT PRÈS DE MOI">
+ <check_box label="Traduction du chat (fournie par Google)" name="translate_chat_checkbox"/>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/fr/inspect_avatar.xml b/indra/newview/skins/minimal/xui/fr/inspect_avatar.xml
new file mode 100644
index 0000000000..553646f8e9
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/inspect_avatar.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater name="inspect_avatar">
+ <string name="Subtitle">
+ [AGE]
+ </string>
+ <string name="Details">
+ [SL_PROFILE]
+ </string>
+ <text name="user_subtitle" value="11 mois, 3 jours"/>
+ <text name="user_details">
+ This is my second life description and I really think it is great. But for some reason my description is super extra long because I like to talk a whole lot
+ </text>
+ <slider name="volume_slider" tool_tip="Volume de la voix" value="0.5"/>
+ <button label="Devenir amis" name="add_friend_btn"/>
+ <button label="IM" name="im_btn"/>
+ <button label="Profil" name="view_profile_btn"/>
+ <panel name="moderator_panel">
+ <button label="Désactiver le chat vocal" name="disable_voice"/>
+ <button label="Activer le chat vocal" name="enable_voice"/>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/fr/inspect_object.xml b/indra/newview/skins/minimal/xui/fr/inspect_object.xml
new file mode 100644
index 0000000000..b66af7a2bf
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/inspect_object.xml
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater name="inspect_object">
+ <string name="Creator">
+ Par [CREATOR]
+ </string>
+ <string name="CreatorAndOwner">
+ De [CREATOR]
+Propriétaire [OWNER]
+ </string>
+ <string name="Price">
+ [AMOUNT] L$
+ </string>
+ <string name="PriceFree">
+ Gratuit !
+ </string>
+ <string name="Touch">
+ Toucher
+ </string>
+ <string name="Sit">
+ M&apos;asseoir
+ </string>
+ <text name="object_name" value="Test Object Name That Is actually two lines and Really Long"/>
+ <text name="object_creator">
+ par secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
+owner secondlife:///app/agent/0e346d8b-4433-4d66-a6b0-fd37083abc4c/about
+ </text>
+ <text name="price_text">
+ 30 000 L$
+ </text>
+ <text name="object_description">
+ This is a really long description for an object being as how it is at least 80 characters in length and so but maybe more like 120 at this point. Who knows, really?
+ </text>
+ <text name="object_media_url">
+ http://www.superdupertest.com
+ </text>
+ <button label="Acheter" name="buy_btn"/>
+ <button label="Payer" name="pay_btn"/>
+ <button label="Prendre une copie" name="take_free_copy_btn"/>
+ <button label="Toucher" name="touch_btn"/>
+ <button label="M&apos;asseoir" name="sit_btn"/>
+ <button label="Ouvert" name="open_btn"/>
+ <icon name="secure_browsing" tool_tip="Navigation sécurisée"/>
+ <button label="Plus" name="more_info_btn"/>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_add_wearable_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_add_wearable_gear.xml
new file mode 100644
index 0000000000..7e7993175e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_add_wearable_gear.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Add Wearable Gear Menu">
+ <menu_item_check label="Trier en commençant par le plus récent" name="sort_by_most_recent"/>
+ <menu_item_check label="Trier par nom" name="sort_by_name"/>
+ <menu_item_check label="Trier par type" name="sort_by_type"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_attachment_other.xml b/indra/newview/skins/minimal/xui/fr/menu_attachment_other.xml
new file mode 100644
index 0000000000..f48513eb2b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_attachment_other.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: See also menu_avatar_other.xml -->
+<context_menu name="Avatar Pie">
+ <menu_item_call label="Voir le profil" name="Profile..."/>
+ <menu_item_call label="Devenir amis" name="Add Friend"/>
+ <menu_item_call label="IM" name="Send IM..."/>
+ <menu_item_call label="Appeler" name="Call"/>
+ <menu_item_call label="Inviter dans le groupe" name="Invite..."/>
+ <menu_item_call label="Ignorer" name="Avatar Mute"/>
+ <menu_item_call label="Signaler" name="abuse"/>
+ <menu_item_call label="Figer" name="Freeze..."/>
+ <menu_item_call label="Expulser" name="Eject..."/>
+ <menu_item_call label="Déboguer les textures" name="Debug..."/>
+ <menu_item_call label="Zoomer en avant" name="Zoom In"/>
+ <menu_item_call label="Payer" name="Pay..."/>
+ <menu_item_call label="Profil de l&apos;objet" name="Object Inspect"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_attachment_self.xml b/indra/newview/skins/minimal/xui/fr/menu_attachment_self.xml
new file mode 100644
index 0000000000..78198fb5a8
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_attachment_self.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Attachment Pie">
+ <menu_item_call label="Toucher" name="Attachment Object Touch"/>
+ <menu_item_call label="Modifier" name="Edit..."/>
+ <menu_item_call label="Détacher" name="Detach"/>
+ <menu_item_call label="M&apos;asseoir" name="Sit Down Here"/>
+ <menu_item_call label="Me lever" name="Stand Up"/>
+ <menu_item_call label="Changer de tenue" name="Change Outfit"/>
+ <menu_item_call label="Modifier ma tenue" name="Edit Outfit"/>
+ <menu_item_call label="Modifier ma silhouette" name="Edit My Shape"/>
+ <menu_item_call label="Mes amis" name="Friends..."/>
+ <menu_item_call label="Mes groupes" name="Groups..."/>
+ <menu_item_call label="Mon profil" name="Profile..."/>
+ <menu_item_call label="Déboguer les textures" name="Debug..."/>
+ <menu_item_call label="Lâcher" name="Drop"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_avatar_icon.xml b/indra/newview/skins/minimal/xui/fr/menu_avatar_icon.xml
new file mode 100644
index 0000000000..3bac25c79b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_avatar_icon.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Avatar Icon Menu">
+ <menu_item_call label="Voir le profil" name="Show Profile"/>
+ <menu_item_call label="Envoyer IM..." name="Send IM"/>
+ <menu_item_call label="Devenir amis..." name="Add Friend"/>
+ <menu_item_call label="Supprimer cet ami..." name="Remove Friend"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_avatar_other.xml b/indra/newview/skins/minimal/xui/fr/menu_avatar_other.xml
new file mode 100644
index 0000000000..08d1a20361
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_avatar_other.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: See also menu_attachment_other.xml -->
+<context_menu name="Avatar Pie">
+ <menu_item_call label="Voir le profil" name="Profile..."/>
+ <menu_item_call label="Devenir amis" name="Add Friend"/>
+ <menu_item_call label="IM" name="Send IM..."/>
+ <menu_item_call label="Appeler" name="Call"/>
+ <menu_item_call label="Inviter dans le groupe" name="Invite..."/>
+ <menu_item_call label="Ignorer" name="Avatar Mute"/>
+ <menu_item_call label="Signaler" name="abuse"/>
+ <menu_item_call label="Figer" name="Freeze..."/>
+ <menu_item_call label="Expulser" name="Eject..."/>
+ <menu_item_call label="Déboguer les textures" name="Debug..."/>
+ <menu_item_call label="Zoomer en avant" name="Zoom In"/>
+ <menu_item_call label="Payer" name="Pay..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_avatar_self.xml b/indra/newview/skins/minimal/xui/fr/menu_avatar_self.xml
new file mode 100644
index 0000000000..c7ee2e9f88
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_avatar_self.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Self Pie">
+ <menu_item_call label="M&apos;asseoir" name="Sit Down Here"/>
+ <menu_item_call label="Me lever" name="Stand Up"/>
+ <context_menu label="Enlever" name="Take Off &gt;">
+ <context_menu label="Habits" name="Clothes &gt;">
+ <menu_item_call label="Chemise" name="Shirt"/>
+ <menu_item_call label="Pantalon" name="Pants"/>
+ <menu_item_call label="Jupe" name="Skirt"/>
+ <menu_item_call label="Chaussures" name="Shoes"/>
+ <menu_item_call label="Chaussettes" name="Socks"/>
+ <menu_item_call label="Veste" name="Jacket"/>
+ <menu_item_call label="Gants" name="Gloves"/>
+ <menu_item_call label="Débardeur" name="Self Undershirt"/>
+ <menu_item_call label="Caleçon" name="Self Underpants"/>
+ <menu_item_call label="Tatouage" name="Self Tattoo"/>
+ <menu_item_call label="Alpha" name="Self Alpha"/>
+ <menu_item_call label="Tous les habits" name="All Clothes"/>
+ </context_menu>
+ <context_menu label="HUD" name="Object Detach HUD"/>
+ <context_menu label="Détacher" name="Object Detach"/>
+ <menu_item_call label="Tout détacher" name="Detach All"/>
+ </context_menu>
+ <menu_item_call label="Changer de tenue" name="Chenge Outfit"/>
+ <menu_item_call label="Modifier ma tenue" name="Edit Outfit"/>
+ <menu_item_call label="Modifier ma silhouette" name="Edit My Shape"/>
+ <menu_item_call label="Mes amis" name="Friends..."/>
+ <menu_item_call label="Mes groupes" name="Groups..."/>
+ <menu_item_call label="Mon profil" name="Profile..."/>
+ <menu_item_call label="Déboguer les textures" name="Debug..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_bottomtray.xml b/indra/newview/skins/minimal/xui/fr/menu_bottomtray.xml
new file mode 100644
index 0000000000..bfdc89c5bb
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_bottomtray.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="hide_camera_move_controls_menu">
+ <menu_item_check label="Bouton Geste" name="ShowGestureButton"/>
+ <menu_item_check label="Bouton Bouger" name="ShowMoveButton"/>
+ <menu_item_check label="Bouton Affichage" name="ShowCameraButton"/>
+ <menu_item_check label="Bouton Photo" name="ShowSnapshotButton"/>
+ <menu_item_check label="Bouton Panneau latéral" name="ShowSidebarButton"/>
+ <menu_item_check label="Bouton Construire" name="ShowBuildButton"/>
+ <menu_item_check label="Bouton Rechercher" name="ShowSearchButton"/>
+ <menu_item_check label="Bouton Carte" name="ShowWorldMapButton"/>
+ <menu_item_check label="Bouton Mini-carte" name="ShowMiniMapButton"/>
+ <menu_item_call label="Couper" name="NearbyChatBar_Cut"/>
+ <menu_item_call label="Copier" name="NearbyChatBar_Copy"/>
+ <menu_item_call label="Coller" name="NearbyChatBar_Paste"/>
+ <menu_item_call label="Supprimer" name="NearbyChatBar_Delete"/>
+ <menu_item_call label="Tout sélectionner" name="NearbyChatBar_Select_All"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_cof_attachment.xml b/indra/newview/skins/minimal/xui/fr/menu_cof_attachment.xml
new file mode 100644
index 0000000000..a4ead48b6b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_cof_attachment.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Attachment">
+ <menu_item_call label="Détacher" name="detach"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_cof_body_part.xml b/indra/newview/skins/minimal/xui/fr/menu_cof_body_part.xml
new file mode 100644
index 0000000000..4b6907fcc6
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_cof_body_part.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Body">
+ <menu_item_call label="Remplacer" name="replace"/>
+ <menu_item_call label="Modifier" name="edit"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_cof_clothing.xml b/indra/newview/skins/minimal/xui/fr/menu_cof_clothing.xml
new file mode 100644
index 0000000000..03cc569704
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_cof_clothing.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Clothing">
+ <menu_item_call label="Enlever" name="take_off"/>
+ <menu_item_call label="Modifier" name="edit"/>
+ <menu_item_call label="Remplacer" name="replace"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_cof_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_cof_gear.xml
new file mode 100644
index 0000000000..8276d57025
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_cof_gear.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear COF">
+ <menu label="Nouveaux habits" name="COF.Gear.New_Clothes"/>
+ <menu label="Nouvelles parties du corps" name="COF.Geear.New_Body_Parts"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_edit.xml b/indra/newview/skins/minimal/xui/fr/menu_edit.xml
new file mode 100644
index 0000000000..56669f31e1
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="Modifier" name="Edit">
+ <menu_item_call label="Annuler" name="Undo"/>
+ <menu_item_call label="Refaire" name="Redo"/>
+ <menu_item_call label="Couper" name="Cut"/>
+ <menu_item_call label="Copier" name="Copy"/>
+ <menu_item_call label="Coller" name="Paste"/>
+ <menu_item_call label="Supprimer" name="Delete"/>
+ <menu_item_call label="Dupliquer" name="Duplicate"/>
+ <menu_item_call label="Tout sélectionner" name="Select All"/>
+ <menu_item_call label="Désélectionner" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_favorites.xml b/indra/newview/skins/minimal/xui/fr/menu_favorites.xml
new file mode 100644
index 0000000000..5f1545fde7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_favorites.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Téléporter" name="Teleport To Landmark"/>
+ <menu_item_call label="Voir/Modifier le repère" name="Landmark Open"/>
+ <menu_item_call label="Copier la SLurl" name="Copy slurl"/>
+ <menu_item_call label="Voir sur la carte" name="Show On Map"/>
+ <menu_item_call label="Copier" name="Landmark Copy"/>
+ <menu_item_call label="Coller" name="Landmark Paste"/>
+ <menu_item_call label="Supprimer" name="Delete"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_gesture_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_gesture_gear.xml
new file mode 100644
index 0000000000..062dd0f005
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_gesture_gear.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_gesture_gear">
+ <menu_item_call label="Ajouter/Supprimer des favoris" name="activate"/>
+ <menu_item_call label="Copier" name="copy_gesture"/>
+ <menu_item_call label="Coller" name="paste"/>
+ <menu_item_call label="Copier l&apos;UUID" name="copy_uuid"/>
+ <menu_item_call label="Enregistrer dans la tenue actuelle" name="save_to_outfit"/>
+ <menu_item_call label="Modifier" name="edit_gesture"/>
+ <menu_item_call label="Inspecter" name="inspect"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_group_plus.xml b/indra/newview/skins/minimal/xui/fr/menu_group_plus.xml
new file mode 100644
index 0000000000..0db5afedc7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_group_plus.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_call label="Rejoindre des groupes..." name="item_join"/>
+ <menu_item_call label="Nouveau groupe..." name="item_new"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_hide_navbar.xml b/indra/newview/skins/minimal/xui/fr/menu_hide_navbar.xml
new file mode 100644
index 0000000000..20af901ddc
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_hide_navbar.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="hide_navbar_menu">
+ <menu_item_check label="Afficher la barre de navigation" name="ShowNavbarNavigationPanel"/>
+ <menu_item_check label="Afficher la barre des favoris" name="ShowNavbarFavoritesPanel"/>
+ <menu_item_check label="Afficher la mini-barre d&apos;emplacement" name="ShowMiniLocationPanel"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_im_well_button.xml b/indra/newview/skins/minimal/xui/fr/menu_im_well_button.xml
new file mode 100644
index 0000000000..8ef1529e6b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_im_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="IM Well Button Context Menu">
+ <menu_item_call label="Tout fermer" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_imchiclet_adhoc.xml b/indra/newview/skins/minimal/xui/fr/menu_imchiclet_adhoc.xml
new file mode 100644
index 0000000000..4d9a103058
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_imchiclet_adhoc.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet AdHoc Menu">
+ <menu_item_call label="Mettre fin à la session" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_imchiclet_group.xml b/indra/newview/skins/minimal/xui/fr/menu_imchiclet_group.xml
new file mode 100644
index 0000000000..59f97d8b48
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_imchiclet_group.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet Group Menu">
+ <menu_item_call label="Profil du groupe" name="Show Profile"/>
+ <menu_item_call label="Afficher la session" name="Chat"/>
+ <menu_item_call label="Mettre fin à la session" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_imchiclet_p2p.xml b/indra/newview/skins/minimal/xui/fr/menu_imchiclet_p2p.xml
new file mode 100644
index 0000000000..ecc8cee413
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_imchiclet_p2p.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet P2P Menu">
+ <menu_item_call label="Voir le profil" name="Show Profile"/>
+ <menu_item_call label="Devenir amis" name="Add Friend"/>
+ <menu_item_call label="Afficher la session" name="Send IM"/>
+ <menu_item_call label="Mettre fin à la session" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_inspect_avatar_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_inspect_avatar_gear.xml
new file mode 100644
index 0000000000..231a175ee5
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_inspect_avatar_gear.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<toggleable_menu name="Gear Menu">
+ <menu_item_call label="Voir le profil" name="view_profile"/>
+ <menu_item_call label="Devenir amis" name="add_friend"/>
+ <menu_item_call label="IM" name="im"/>
+ <menu_item_call label="Téléporter" name="teleport"/>
+ <menu_item_call label="Ignorer" name="block"/>
+ <menu_item_call label="Ne plus ignorer" name="unblock"/>
+ <menu_item_call label="Signaler" name="report"/>
+ <menu_item_call label="Figer" name="freeze"/>
+ <menu_item_call label="Expulser" name="eject"/>
+ <menu_item_call label="Éjecter" name="kick"/>
+ <menu_item_call label="Représentant de l&apos;Assistance client" name="csr"/>
+ <menu_item_call label="Déboguer les textures" name="debug"/>
+ <menu_item_call label="Situer sur la carte" name="find_on_map"/>
+ <menu_item_call label="Zoomer en avant" name="zoom_in"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_inspect_object_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_inspect_object_gear.xml
new file mode 100644
index 0000000000..074bb54cdc
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_inspect_object_gear.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu name="Gear Menu">
+ <menu_item_call label="Toucher" name="touch"/>
+ <menu_item_call label="M&apos;asseoir" name="sit"/>
+ <menu_item_call label="Payer" name="pay"/>
+ <menu_item_call label="Acheter" name="buy"/>
+ <menu_item_call label="Prendre" name="take"/>
+ <menu_item_call label="Prendre une copie" name="take_copy"/>
+ <menu_item_call label="Ouvrir" name="open"/>
+ <menu_item_call label="Modifier" name="edit"/>
+ <menu_item_call label="Porter" name="wear"/>
+ <menu_item_call label="Ajouter" name="add"/>
+ <menu_item_call label="Signaler" name="report"/>
+ <menu_item_call label="Ignorer" name="block"/>
+ <menu_item_call label="Zoomer en avant" name="zoom_in"/>
+ <menu_item_call label="Supprimer" name="remove"/>
+ <menu_item_call label="En savoir plus" name="more_info"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml
new file mode 100644
index 0000000000..3bc164788a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_inspect_self_gear.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu name="Gear Menu">
+ <menu_item_call label="M&apos;asseoir" name="sit_down_here"/>
+ <menu_item_call label="Me lever" name="stand_up"/>
+ <menu_item_call label="Changer de tenue" name="change_outfit"/>
+ <menu_item_call label="Mon profil" name="my_profile"/>
+ <menu_item_call label="Mes amis" name="my_friends"/>
+ <menu_item_call label="Mes groupes" name="my_groups"/>
+ <menu_item_call label="Déboguer les textures" name="Debug..."/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_inv_offer_chiclet.xml b/indra/newview/skins/minimal/xui/fr/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..a9b2883cca
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="Fermer" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_inventory.xml b/indra/newview/skins/minimal/xui/fr/menu_inventory.xml
new file mode 100644
index 0000000000..a2279cf0ac
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_inventory.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Partager" name="Share"/>
+ <menu_item_call label="Acheter" name="Task Buy"/>
+ <menu_item_call label="Ouvrir" name="Task Open"/>
+ <menu_item_call label="Jouer" name="Task Play"/>
+ <menu_item_call label="Propriétés" name="Task Properties"/>
+ <menu_item_call label="Renommer" name="Task Rename"/>
+ <menu_item_call label="Supprimer" name="Task Remove"/>
+ <menu_item_call label="Vider la corbeille" name="Empty Trash"/>
+ <menu_item_call label="Vider les objets trouvés" name="Empty Lost And Found"/>
+ <menu_item_call label="Nouveau dossier" name="New Folder"/>
+ <menu_item_call label="Nouveau script" name="New Script"/>
+ <menu_item_call label="Nouvelle note" name="New Note"/>
+ <menu_item_call label="Nouveau geste" name="New Gesture"/>
+ <menu label="Nouveaux habits" name="New Clothes">
+ <menu_item_call label="Nouvelle chemise" name="New Shirt"/>
+ <menu_item_call label="Nouveau pantalon" name="New Pants"/>
+ <menu_item_call label="Nouvelles chaussures" name="New Shoes"/>
+ <menu_item_call label="Nouvelles chaussettes" name="New Socks"/>
+ <menu_item_call label="Nouvelle veste" name="New Jacket"/>
+ <menu_item_call label="Nouvelle jupe" name="New Skirt"/>
+ <menu_item_call label="Nouveaux gants" name="New Gloves"/>
+ <menu_item_call label="Nouveau débardeur" name="New Undershirt"/>
+ <menu_item_call label="Nouveau caleçon" name="New Underpants"/>
+ <menu_item_call label="Nouveau masque alpha" name="New Alpha Mask"/>
+ <menu_item_call label="Nouveau tatouage" name="New Tattoo"/>
+ </menu>
+ <menu label="Nouvelles parties du corps" name="New Body Parts">
+ <menu_item_call label="Nouvelle silhouette" name="New Shape"/>
+ <menu_item_call label="Nouvelle peau" name="New Skin"/>
+ <menu_item_call label="Nouveaux cheveux" name="New Hair"/>
+ <menu_item_call label="Nouveaux yeux" name="New Eyes"/>
+ </menu>
+ <menu label="Changer de type" name="Change Type">
+ <menu_item_call label="Défaut" name="Default"/>
+ <menu_item_call label="Gants" name="Gloves"/>
+ <menu_item_call label="Veste" name="Jacket"/>
+ <menu_item_call label="Pantalon" name="Pants"/>
+ <menu_item_call label="Silhouette" name="Shape"/>
+ <menu_item_call label="Chaussures" name="Shoes"/>
+ <menu_item_call label="Chemise" name="Shirt"/>
+ <menu_item_call label="Jupe" name="Skirt"/>
+ <menu_item_call label="Caleçon" name="Underpants"/>
+ <menu_item_call label="Débardeur" name="Undershirt"/>
+ </menu>
+ <menu_item_call label="Téléporter" name="Landmark Open"/>
+ <menu_item_call label="Ouvrir" name="Animation Open"/>
+ <menu_item_call label="Ouvrir" name="Sound Open"/>
+ <menu_item_call label="Remplacer la tenue actuelle" name="Replace Outfit"/>
+ <menu_item_call label="Ajouter à la tenue actuelle" name="Add To Outfit"/>
+ <menu_item_call label="Enlever de la tenue actuelle" name="Remove From Outfit"/>
+ <menu_item_call label="Trouver l&apos;original" name="Find Original"/>
+ <menu_item_call label="Purger l&apos;objet" name="Purge Item"/>
+ <menu_item_call label="Restaurer l&apos;objet" name="Restore Item"/>
+ <menu_item_call label="Ouvrir" name="Open"/>
+ <menu_item_call label="Ouvrir l&apos;original" name="Open Original"/>
+ <menu_item_call label="Propriétés" name="Properties"/>
+ <menu_item_call label="Renommer" name="Rename"/>
+ <menu_item_call label="Copier l&apos;UUID (identifiant universel unique)" name="Copy Asset UUID"/>
+ <menu_item_call label="Copier" name="Copy"/>
+ <menu_item_call label="Coller" name="Paste"/>
+ <menu_item_call label="Coller comme lien" name="Paste As Link"/>
+ <menu_item_call label="Supprimer" name="Remove Link"/>
+ <menu_item_call label="Supprimer" name="Delete"/>
+ <menu_item_call label="Supprimer le dossier système" name="Delete System Folder"/>
+ <menu_item_call label="Démarrer le chat conférence" name="Conference Chat Folder"/>
+ <menu_item_call label="Jouer" name="Sound Play"/>
+ <menu_item_call label="À propos du repère" name="About Landmark"/>
+ <menu_item_call label="Jouer dans Second Life" name="Animation Play"/>
+ <menu_item_call label="Jouer localement" name="Animation Audition"/>
+ <menu_item_call label="Envoyer un message instantané" name="Send Instant Message"/>
+ <menu_item_call label="Offrir de téléporter..." name="Offer Teleport..."/>
+ <menu_item_call label="Démarrer le chat conférence" name="Conference Chat"/>
+ <menu_item_call label="Activer" name="Activate"/>
+ <menu_item_call label="Désactiver" name="Deactivate"/>
+ <menu_item_call label="Enregistrer sous" name="Save As"/>
+ <menu_item_call label="Détacher de vous" name="Detach From Yourself"/>
+ <menu_item_call label="Porter" name="Wearable And Object Wear"/>
+ <menu label="Attacher à" name="Attach To"/>
+ <menu label="Attacher au HUD " name="Attach To HUD"/>
+ <menu_item_call label="Modifier" name="Wearable Edit"/>
+ <menu_item_call label="Ajouter" name="Wearable Add"/>
+ <menu_item_call label="Enlever" name="Take Off"/>
+ <menu_item_call label="--aucune option--" name="--no options--"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_inventory_add.xml b/indra/newview/skins/minimal/xui/fr/menu_inventory_add.xml
new file mode 100644
index 0000000000..fe096b4a7e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_inventory_add.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_inventory_add">
+ <menu label="Importer" name="upload">
+ <menu_item_call label="Image ([COST] L$)..." name="Upload Image"/>
+ <menu_item_call label="Son ([COST] L$)..." name="Upload Sound"/>
+ <menu_item_call label="Animation ([COST] L$)..." name="Upload Animation"/>
+ <menu_item_call label="Lot ([COST] L$ par fichier)..." name="Bulk Upload"/>
+ <menu_item_call label="Définir les droits de chargement par défaut" name="perm prefs"/>
+ </menu>
+ <menu_item_call label="Nouveau dossier" name="New Folder"/>
+ <menu_item_call label="Nouveau script" name="New Script"/>
+ <menu_item_call label="Nouvelle note" name="New Note"/>
+ <menu_item_call label="Nouveau geste" name="New Gesture"/>
+ <menu label="Nouveaux habits" name="New Clothes">
+ <menu_item_call label="Nouvelle chemise" name="New Shirt"/>
+ <menu_item_call label="Nouveau pantalon" name="New Pants"/>
+ <menu_item_call label="Nouvelles chaussures" name="New Shoes"/>
+ <menu_item_call label="Nouvelles chaussettes" name="New Socks"/>
+ <menu_item_call label="Nouvelle veste" name="New Jacket"/>
+ <menu_item_call label="Nouvelle jupe" name="New Skirt"/>
+ <menu_item_call label="Nouveaux gants" name="New Gloves"/>
+ <menu_item_call label="Nouveau débardeur" name="New Undershirt"/>
+ <menu_item_call label="Nouveau caleçon" name="New Underpants"/>
+ <menu_item_call label="Nouvel alpha" name="New Alpha"/>
+ <menu_item_call label="Nouveau tatouage" name="New Tattoo"/>
+ </menu>
+ <menu label="Nouvelles parties du corps" name="New Body Parts">
+ <menu_item_call label="Nouvelle silhouette" name="New Shape"/>
+ <menu_item_call label="Nouvelle peau" name="New Skin"/>
+ <menu_item_call label="Nouveaux cheveux" name="New Hair"/>
+ <menu_item_call label="Nouveaux yeux" name="New Eyes"/>
+ </menu>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_inventory_gear_default.xml b/indra/newview/skins/minimal/xui/fr/menu_inventory_gear_default.xml
new file mode 100644
index 0000000000..f28918ae14
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_inventory_gear_default.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="menu_gear_default">
+ <menu_item_call label="Nouvelle fenêtre d&apos;inventaire" name="new_window"/>
+ <menu_item_check label="Trier par nom" name="sort_by_name"/>
+ <menu_item_check label="Trier en commençant par le plus récent" name="sort_by_recent"/>
+ <menu_item_check label="Dossiers système en premier" name="sort_system_folders_to_top"/>
+ <menu_item_call label="Afficher les filtres" name="show_filters"/>
+ <menu_item_call label="Réinitialiser les filtres" name="reset_filters"/>
+ <menu_item_call label="Fermer tous les dossiers" name="close_folders"/>
+ <menu_item_call label="Vider les objets trouvés" name="empty_lostnfound"/>
+ <menu_item_call label="Enregistrer la texture sous" name="Save Texture As"/>
+ <menu_item_call label="Partager" name="Share"/>
+ <menu_item_call label="Trouver l&apos;original" name="Find Original"/>
+ <menu_item_call label="Trouver tous les liens" name="Find All Links"/>
+ <menu_item_call label="Vider la corbeille" name="empty_trash"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_land.xml b/indra/newview/skins/minimal/xui/fr/menu_land.xml
new file mode 100644
index 0000000000..b84daee3ae
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_land.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Land Pie">
+ <menu_item_call label="À propos du terrain" name="Place Information..."/>
+ <menu_item_call label="M&apos;asseoir ici" name="Sit Here"/>
+ <menu_item_call label="Acheter ce terrain" name="Land Buy"/>
+ <menu_item_call label="Acheter un pass" name="Land Buy Pass"/>
+ <menu_item_call label="Construire" name="Create"/>
+ <menu_item_call label="Modifier le terrain" name="Edit Terrain"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_landmark.xml b/indra/newview/skins/minimal/xui/fr/menu_landmark.xml
new file mode 100644
index 0000000000..73eaa4af7e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_landmark.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="landmark_overflow_menu">
+ <menu_item_call label="Copier la SLurl" name="copy"/>
+ <menu_item_call label="Supprimer" name="delete"/>
+ <menu_item_call label="Créer un favori" name="pick"/>
+ <menu_item_call label="Ajouter à la barre des favoris" name="add_to_favbar"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_login.xml b/indra/newview/skins/minimal/xui/fr/menu_login.xml
new file mode 100644
index 0000000000..400c77e51a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_login.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu_bar name="Login Menu">
+ <menu label="Moi" name="File">
+ <menu_item_call label="Préférences" name="Preferences..."/>
+ <menu_item_call label="Quitter [APP_NAME]" name="Quit"/>
+ </menu>
+ <menu label="Aide" name="Help">
+ <menu_item_call label="Aide de [SECOND_LIFE]" name="Second Life Help"/>
+ <menu_item_call label="À propos de [APP_NAME]" name="About Second Life"/>
+ </menu>
+ <menu_item_check label="Afficher le menu de débogage" name="Show Debug Menu"/>
+ <menu label="Débogage" name="Debug">
+ <menu_item_call label="Afficher les paramètres de débogage" name="Debug Settings"/>
+ <menu_item_call label="Paramètres de couleurs/interface" name="UI/Color Settings"/>
+ <menu_item_call label="Outil d&apos;aperçu XUI" name="UI Preview Tool"/>
+ <menu label="Tests de l&apos;interface" name="UI Tests"/>
+ <menu_item_call label="Définir la taille de la fenêtre..." name="Set Window Size..."/>
+ <menu_item_call label="Afficher les conditions d&apos;utilisation" name="TOS"/>
+ <menu_item_call label="Afficher le message critique" name="Critical"/>
+ <menu_item_call label="Test du navigateur de médias" name="Web Browser Test"/>
+ <menu_item_call label="Test de la fenêtre flottante du contenu Web" name="Web Content Floater Test"/>
+ <menu_item_check label="Afficher le sélecteur de grille" name="Show Grid Picker"/>
+ <menu_item_call label="Afficher la console des notifications" name="Show Notifications Console"/>
+ </menu>
+</menu_bar>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_mini_map.xml b/indra/newview/skins/minimal/xui/fr/menu_mini_map.xml
new file mode 100644
index 0000000000..b9d0a70383
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_mini_map.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Zoom rapproché" name="Zoom Close"/>
+ <menu_item_call label="Zoom moyen" name="Zoom Medium"/>
+ <menu_item_call label="Zoom éloigné" name="Zoom Far"/>
+ <menu_item_call label="Zoom par défaut" name="Zoom Default"/>
+ <menu_item_check label="Faire pivoter la carte" name="Rotate Map"/>
+ <menu_item_check label="Centrage auto" name="Auto Center"/>
+ <menu_item_call label="Arrêter de suivre" name="Stop Tracking"/>
+ <menu_item_call label="Carte du monde" name="World Map"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_navbar.xml b/indra/newview/skins/minimal/xui/fr/menu_navbar.xml
new file mode 100644
index 0000000000..08d810b653
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_navbar.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Navbar Menu">
+ <menu_item_check label="Voir les coordonnées" name="Show Coordinates"/>
+ <menu_item_check label="Afficher les propriétés de la parcelle" name="Show Parcel Properties"/>
+ <menu_item_call label="Repère" name="Landmark"/>
+ <menu_item_call label="Couper" name="Cut"/>
+ <menu_item_call label="Copier" name="Copy"/>
+ <menu_item_call label="Coller" name="Paste"/>
+ <menu_item_call label="Supprimer" name="Delete"/>
+ <menu_item_call label="Tout sélectionner" name="Select All"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_nearby_chat.xml b/indra/newview/skins/minimal/xui/fr/menu_nearby_chat.xml
new file mode 100644
index 0000000000..99e22aeff7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_nearby_chat.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="NearBy Chat Menu">
+ <menu_item_call label="Afficher les personnes près de vous..." name="nearby_people"/>
+ <menu_item_check label="Afficher le texte ignoré" name="muted_text"/>
+ <menu_item_check label="Afficher les icônes des Buddy" name="show_buddy_icons"/>
+ <menu_item_check label="Afficher les noms" name="show_names"/>
+ <menu_item_check label="Afficher les icônes et les noms" name="show_icons_and_names"/>
+ <menu_item_call label="Taille de la police" name="font_size"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_notification_well_button.xml b/indra/newview/skins/minimal/xui/fr/menu_notification_well_button.xml
new file mode 100644
index 0000000000..323bfdbf16
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Tout fermer" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_object.xml b/indra/newview/skins/minimal/xui/fr/menu_object.xml
new file mode 100644
index 0000000000..a50a9df4b1
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_object.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Object Pie">
+ <menu_item_call label="Toucher" name="Object Touch">
+ <menu_item_call.on_enable name="EnableTouch" parameter="Toucher"/>
+ </menu_item_call>
+ <menu_item_call label="Modifier" name="Edit..."/>
+ <menu_item_call label="Construire" name="Build"/>
+ <menu_item_call label="Ouvrir" name="Open"/>
+ <menu_item_call label="M&apos;asseoir ici" name="Object Sit"/>
+ <menu_item_call label="Me lever" name="Object Stand Up"/>
+ <menu_item_call label="Profil de l&apos;objet" name="Object Inspect"/>
+ <menu_item_call label="Zoomer en avant" name="Zoom In"/>
+ <context_menu label="Porter" name="Put On">
+ <menu_item_call label="Porter" name="Wear"/>
+ <menu_item_call label="Ajouter" name="Add"/>
+ <context_menu label="Attacher" name="Object Attach"/>
+ <context_menu label="Attacher HUD" name="Object Attach HUD"/>
+ </context_menu>
+ <context_menu label="Supprimer" name="Remove">
+ <menu_item_call label="Signaler une infraction" name="Report Abuse..."/>
+ <menu_item_call label="Ignorer" name="Object Mute"/>
+ <menu_item_call label="Retour" name="Return..."/>
+ <menu_item_call label="Supprimer" name="Delete"/>
+ </context_menu>
+ <menu_item_call label="Prendre" name="Pie Object Take"/>
+ <menu_item_call label="Prendre une copie" name="Take Copy"/>
+ <menu_item_call label="Payer" name="Pay..."/>
+ <menu_item_call label="Acheter" name="Buy..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_object_icon.xml b/indra/newview/skins/minimal/xui/fr/menu_object_icon.xml
new file mode 100644
index 0000000000..69f8e88a0d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_object_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Object Icon Menu">
+ <menu_item_call label="Profil de l&apos;objet..." name="Object Profile"/>
+ <menu_item_call label="Ignorer..." name="Block"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_outfit_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_outfit_gear.xml
new file mode 100644
index 0000000000..5db7f176b5
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_outfit_gear.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear Outfit">
+ <menu_item_call label="Porter - Remplacer la tenue actuelle" name="wear"/>
+ <menu_item_call label="Porter - Ajouter à la tenue actuelle" name="wear_add"/>
+ <menu_item_call label="Enlever - Supprimer de la tenue actuelle" name="take_off"/>
+ <menu label="Nouveaux habits" name="New Clothes">
+ <menu_item_call label="Nouvelle chemise" name="New Shirt"/>
+ <menu_item_call label="Nouveau pantalon" name="New Pants"/>
+ <menu_item_call label="Nouvelles chaussures" name="New Shoes"/>
+ <menu_item_call label="Nouvelles chaussettes" name="New Socks"/>
+ <menu_item_call label="Nouvelle veste" name="New Jacket"/>
+ <menu_item_call label="Nouvelle jupe" name="New Skirt"/>
+ <menu_item_call label="Nouveaux gants" name="New Gloves"/>
+ <menu_item_call label="Nouveau débardeur" name="New Undershirt"/>
+ <menu_item_call label="Nouveau caleçon" name="New Underpants"/>
+ <menu_item_call label="Nouvel alpha" name="New Alpha"/>
+ <menu_item_call label="Nouveau tatouage" name="New Tattoo"/>
+ </menu>
+ <menu label="Nouvelles parties du corps" name="New Body Parts">
+ <menu_item_call label="Nouvelle silhouette" name="New Shape"/>
+ <menu_item_call label="Nouvelle peau" name="New Skin"/>
+ <menu_item_call label="Nouveaux cheveux" name="New Hair"/>
+ <menu_item_call label="Nouveaux yeux" name="New Eyes"/>
+ </menu>
+ <menu_item_call label="Renommer la tenue" name="rename"/>
+ <menu_item_call label="Supprimer la tenue" name="delete_outfit"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_outfit_tab.xml b/indra/newview/skins/minimal/xui/fr/menu_outfit_tab.xml
new file mode 100644
index 0000000000..2a7f618e07
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_outfit_tab.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Outfit">
+ <menu_item_call label="Porter - Remplacer la tenue actuelle" name="wear_replace"/>
+ <menu_item_call label="Porter - Ajouter à la tenue actuelle" name="wear_add"/>
+ <menu_item_call label="Enlever - Supprimer de la tenue actuelle" name="take_off"/>
+ <menu_item_call label="Modifier la tenue" name="edit"/>
+ <menu_item_call label="Renommer la tenue" name="rename"/>
+ <menu_item_call label="Supprimer la tenue" name="delete"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_participant_list.xml b/indra/newview/skins/minimal/xui/fr/menu_participant_list.xml
new file mode 100644
index 0000000000..f91a30f6bb
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_participant_list.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Participant List Context Menu">
+ <menu_item_check label="Trier par nom" name="SortByName"/>
+ <menu_item_check label="Trier par intervenants récents" name="SortByRecentSpeakers"/>
+ <menu_item_call label="Voir le profil" name="View Profile"/>
+ <menu_item_call label="Devenir amis" name="Add Friend"/>
+ <menu_item_call label="IM" name="IM"/>
+ <menu_item_call label="Appeler" name="Call"/>
+ <menu_item_call label="Partager" name="Share"/>
+ <menu_item_call label="Payer" name="Pay"/>
+ <menu_item_check label="Afficher les icônes des résidents" name="View Icons"/>
+ <menu_item_check label="Bloquer le chat vocal" name="Block/Unblock"/>
+ <menu_item_check label="Ignorer le texte" name="MuteText"/>
+ <context_menu label="Options du modérateur" name="Moderator Options">
+ <menu_item_check label="Autoriser les chats écrits" name="AllowTextChat"/>
+ <menu_item_call label="Ignorer ce participant" name="ModerateVoiceMuteSelected"/>
+ <menu_item_call label="Ne plus ignorer ce participant" name="ModerateVoiceUnMuteSelected"/>
+ <menu_item_call label="Ignorer les autres" name="ModerateVoiceMute"/>
+ <menu_item_call label="Ne plus ignorer les autres" name="ModerateVoiceUnmute"/>
+ </context_menu>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_people_friends_view_sort.xml b/indra/newview/skins/minimal/xui/fr/menu_people_friends_view_sort.xml
new file mode 100644
index 0000000000..a6170a6c16
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_people_friends_view_sort.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Trier par nom" name="sort_name"/>
+ <menu_item_check label="Trier par statut" name="sort_status"/>
+ <menu_item_check label="Afficher les icônes des résidents" name="view_icons"/>
+ <menu_item_check label="Afficher les droits octroyés" name="view_permissions"/>
+ <menu_item_call label="Afficher les résidents et les objets ignorés" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_people_groups.xml b/indra/newview/skins/minimal/xui/fr/menu_people_groups.xml
new file mode 100644
index 0000000000..eb51b4cf7e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_people_groups.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_call label="Afficher les infos" name="View Info"/>
+ <menu_item_call label="Chat" name="Chat"/>
+ <menu_item_call label="Appeler" name="Call"/>
+ <menu_item_call label="Activer" name="Activate"/>
+ <menu_item_call label="Quitter" name="Leave"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_people_groups_view_sort.xml b/indra/newview/skins/minimal/xui/fr/menu_people_groups_view_sort.xml
new file mode 100644
index 0000000000..34f949cf2c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_people_groups_view_sort.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Afficher les icônes des groupes" name="Display Group Icons"/>
+ <menu_item_call label="Quitter le groupe sélectionné" name="Leave Selected Group"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_people_nearby.xml b/indra/newview/skins/minimal/xui/fr/menu_people_nearby.xml
new file mode 100644
index 0000000000..26bd3978a9
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_people_nearby.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Avatar Context Menu">
+ <menu_item_call label="Voir le profil" name="View Profile"/>
+ <menu_item_call label="Devenir amis" name="Add Friend"/>
+ <menu_item_call label="Supprimer cet ami" name="Remove Friend"/>
+ <menu_item_call label="IM" name="IM"/>
+ <menu_item_call label="Appeler" name="Call"/>
+ <menu_item_call label="Carte" name="Map"/>
+ <menu_item_call label="Partager" name="Share"/>
+ <menu_item_call label="Payer" name="Pay"/>
+ <menu_item_check label="Ignorer/Ne plus ignorer" name="Block/Unblock"/>
+ <menu_item_call label="Proposer une téléportation" name="teleport"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_people_nearby_multiselect.xml b/indra/newview/skins/minimal/xui/fr/menu_people_nearby_multiselect.xml
new file mode 100644
index 0000000000..8400ec0a14
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_people_nearby_multiselect.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Multi-Selected People Context Menu">
+ <menu_item_call label="Devenir amis" name="Add Friends"/>
+ <menu_item_call label="Supprimer des amis" name="Remove Friend"/>
+ <menu_item_call label="IM" name="IM"/>
+ <menu_item_call label="Appeler" name="Call"/>
+ <menu_item_call label="Partager" name="Share"/>
+ <menu_item_call label="Payer" name="Pay"/>
+ <menu_item_call label="Proposer une téléportation" name="teleport"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_people_nearby_view_sort.xml b/indra/newview/skins/minimal/xui/fr/menu_people_nearby_view_sort.xml
new file mode 100644
index 0000000000..45f97e062e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_people_nearby_view_sort.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Trier par intervenants récents" name="sort_by_recent_speakers"/>
+ <menu_item_check label="Trier par nom" name="sort_name"/>
+ <menu_item_check label="Trier par distance" name="sort_distance"/>
+ <menu_item_check label="Afficher les icônes des résidents" name="view_icons"/>
+ <menu_item_call label="Afficher les résidents et les objets interdits" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_people_recent_view_sort.xml b/indra/newview/skins/minimal/xui/fr/menu_people_recent_view_sort.xml
new file mode 100644
index 0000000000..93b90ae61c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_people_recent_view_sort.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Trier en commençant par le plus récent" name="sort_most"/>
+ <menu_item_check label="Trier par nom" name="sort_name"/>
+ <menu_item_check label="Afficher les icônes des résidents" name="view_icons"/>
+ <menu_item_call label="Afficher les résidents et les objets ignorés" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_picks.xml b/indra/newview/skins/minimal/xui/fr/menu_picks.xml
new file mode 100644
index 0000000000..7d7174d43c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_picks.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Picks">
+ <menu_item_call label="Infos" name="pick_info"/>
+ <menu_item_call label="Modifier" name="pick_edit"/>
+ <menu_item_call label="Téléporter" name="pick_teleport"/>
+ <menu_item_call label="Carte" name="pick_map"/>
+ <menu_item_call label="Supprimer" name="pick_delete"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_picks_plus.xml b/indra/newview/skins/minimal/xui/fr/menu_picks_plus.xml
new file mode 100644
index 0000000000..b6cde6d6e2
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_picks_plus.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="picks_plus_menu">
+ <menu_item_call label="Nouveau favori" name="create_pick"/>
+ <menu_item_call label="Nouvelle petite annonce" name="create_classified"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_place.xml b/indra/newview/skins/minimal/xui/fr/menu_place.xml
new file mode 100644
index 0000000000..6b0f4db752
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_place.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="place_overflow_menu">
+ <menu_item_call label="Enregistrer comme repère" name="landmark"/>
+ <menu_item_call label="Créer un favori" name="pick"/>
+ <menu_item_call label="Acheter un pass" name="pass"/>
+ <menu_item_call label="Modifier" name="edit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_place_add_button.xml b/indra/newview/skins/minimal/xui/fr/menu_place_add_button.xml
new file mode 100644
index 0000000000..92f9e7719d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_place_add_button.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_folder_gear">
+ <menu_item_call label="Ajouter un dossier" name="add_folder"/>
+ <menu_item_call label="Ajouter un repère" name="add_landmark"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_places_gear_folder.xml b/indra/newview/skins/minimal/xui/fr/menu_places_gear_folder.xml
new file mode 100644
index 0000000000..3570bdec7f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_places_gear_folder.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_folder_gear">
+ <menu_item_call label="Ajouter un repère" name="add_landmark"/>
+ <menu_item_call label="Ajouter un dossier" name="add_folder"/>
+ <menu_item_call label="Couper" name="cut"/>
+ <menu_item_call label="Copier" name="copy_folder"/>
+ <menu_item_call label="Coller" name="paste"/>
+ <menu_item_call label="Renommer" name="rename"/>
+ <menu_item_call label="Supprimer" name="delete"/>
+ <menu_item_call label="Agrandir" name="expand"/>
+ <menu_item_call label="Réduire" name="collapse"/>
+ <menu_item_call label="Développer tous les dossiers" name="expand_all"/>
+ <menu_item_call label="Réduire tous les dossiers" name="collapse_all"/>
+ <menu_item_check label="Trier par date" name="sort_by_date"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_places_gear_landmark.xml b/indra/newview/skins/minimal/xui/fr/menu_places_gear_landmark.xml
new file mode 100644
index 0000000000..5491c1b3fc
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_places_gear_landmark.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_ladmark_gear">
+ <menu_item_call label="Téléporter" name="teleport"/>
+ <menu_item_call label="Plus d&apos;informations" name="more_info"/>
+ <menu_item_call label="Voir sur la carte" name="show_on_map"/>
+ <menu_item_call label="Ajouter un repère" name="add_landmark"/>
+ <menu_item_call label="Ajouter un dossier" name="add_folder"/>
+ <menu_item_call label="Couper" name="cut"/>
+ <menu_item_call label="Copier le repère" name="copy_landmark"/>
+ <menu_item_call label="Copier la SLurl" name="copy_slurl"/>
+ <menu_item_call label="Coller" name="paste"/>
+ <menu_item_call label="Renommer" name="rename"/>
+ <menu_item_call label="Supprimer" name="delete"/>
+ <menu_item_call label="Développer tous les dossiers" name="expand_all"/>
+ <menu_item_call label="Réduire tous les dossiers" name="collapse_all"/>
+ <menu_item_check label="Trier par date" name="sort_by_date"/>
+ <menu_item_call label="Créer un favori" name="create_pick"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_profile_overflow.xml b/indra/newview/skins/minimal/xui/fr/menu_profile_overflow.xml
new file mode 100644
index 0000000000..ddf898b791
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_profile_overflow.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="profile_overflow_menu">
+ <menu_item_call label="Carte" name="show_on_map"/>
+ <menu_item_call label="Payer" name="pay"/>
+ <menu_item_call label="Partager" name="share"/>
+ <menu_item_call label="Ignorer" name="block"/>
+ <menu_item_call label="Ne plus ignorer" name="unblock"/>
+ <menu_item_call label="Éjecter" name="kick"/>
+ <menu_item_call label="Figer" name="freeze"/>
+ <menu_item_call label="Libérer" name="unfreeze"/>
+ <menu_item_call label="Représentant du service consommateur" name="csr"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_save_outfit.xml b/indra/newview/skins/minimal/xui/fr/menu_save_outfit.xml
new file mode 100644
index 0000000000..f78db411b3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="Enregistrer" name="save_outfit"/>
+ <menu_item_call label="Enregistrer sous" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_script_chiclet.xml b/indra/newview/skins/minimal/xui/fr/menu_script_chiclet.xml
new file mode 100644
index 0000000000..46efa30bd6
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="Fermer" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_slurl.xml b/indra/newview/skins/minimal/xui/fr/menu_slurl.xml
new file mode 100644
index 0000000000..ddfa5c0849
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_slurl.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="À propos de l&apos;URL" name="about_url"/>
+ <menu_item_call label="Téléporter vers l&apos;URL" name="teleport_to_url"/>
+ <menu_item_call label="Carte" name="show_on_map"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_teleport_history_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_teleport_history_gear.xml
new file mode 100644
index 0000000000..3dea662cc2
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_teleport_history_gear.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Teleport History Gear Context Menu">
+ <menu_item_call label="Développer tous les dossiers" name="Expand all folders"/>
+ <menu_item_call label="Réduire tous les dossiers" name="Collapse all folders"/>
+ <menu_item_call label="Effacer l&apos;historique des téléportations" name="Clear Teleport History"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_teleport_history_item.xml b/indra/newview/skins/minimal/xui/fr/menu_teleport_history_item.xml
new file mode 100644
index 0000000000..fb4582dbce
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_teleport_history_item.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Teleport History Item Context Menu">
+ <menu_item_call label="Téléporter" name="Teleport"/>
+ <menu_item_call label="Plus d&apos;informations" name="More Information"/>
+ <menu_item_call label="Copier dans le presse-papiers" name="CopyToClipboard"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_teleport_history_tab.xml b/indra/newview/skins/minimal/xui/fr/menu_teleport_history_tab.xml
new file mode 100644
index 0000000000..369680985d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_teleport_history_tab.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Teleport History Item Context Menu">
+ <menu_item_call label="Ouvrir" name="TabOpen"/>
+ <menu_item_call label="Fermer" name="TabClose"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_text_editor.xml b/indra/newview/skins/minimal/xui/fr/menu_text_editor.xml
new file mode 100644
index 0000000000..b6f429aec9
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_text_editor.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Text editor context menu">
+ <menu_item_call label="Couper" name="Cut"/>
+ <menu_item_call label="Copier" name="Copy"/>
+ <menu_item_call label="Coller" name="Paste"/>
+ <menu_item_call label="Supprimer" name="Delete"/>
+ <menu_item_call label="Tout sélectionner" name="Select All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_topinfobar.xml b/indra/newview/skins/minimal/xui/fr/menu_topinfobar.xml
new file mode 100644
index 0000000000..dc68f40fe7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_topinfobar.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_topinfobar">
+ <menu_item_check label="Afficher les coordonnées" name="Show Coordinates"/>
+ <menu_item_check label="Afficher les propriétés de la parcelle" name="Show Parcel Properties"/>
+ <menu_item_call label="Repère" name="Landmark"/>
+ <menu_item_call label="Copier" name="Copy"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_url_agent.xml b/indra/newview/skins/minimal/xui/fr/menu_url_agent.xml
new file mode 100644
index 0000000000..5ed627fbc3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_url_agent.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Voir le profil du résident" name="show_agent"/>
+ <menu_item_call label="Copier le nom dans le presse-papiers" name="url_copy_label"/>
+ <menu_item_call label="Copier la SLurl dans le presse-papiers" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_url_group.xml b/indra/newview/skins/minimal/xui/fr/menu_url_group.xml
new file mode 100644
index 0000000000..de90c3ff7e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_url_group.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Voir le profil du groupe" name="show_group"/>
+ <menu_item_call label="Copier le groupe dans le presse-papiers" name="url_copy_label"/>
+ <menu_item_call label="Copier la SLurl dans le presse-papiers" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_url_http.xml b/indra/newview/skins/minimal/xui/fr/menu_url_http.xml
new file mode 100644
index 0000000000..5e96352999
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_url_http.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Ouvrir la page Web" name="url_open"/>
+ <menu_item_call label="Ouvrir dans un navigateur interne" name="url_open_internal"/>
+ <menu_item_call label="Ouvrir dans un navigateur externe" name="url_open_external"/>
+ <menu_item_call label="Copier l&apos;URL dans le presse-papiers" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_url_inventory.xml b/indra/newview/skins/minimal/xui/fr/menu_url_inventory.xml
new file mode 100644
index 0000000000..8ab88b4be7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_url_inventory.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Afficher l&apos;article d&apos;inventaire" name="show_item"/>
+ <menu_item_call label="Copier le nom dans le presse-papiers" name="url_copy_label"/>
+ <menu_item_call label="Copier la SLurl dans le presse-papiers" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_url_map.xml b/indra/newview/skins/minimal/xui/fr/menu_url_map.xml
new file mode 100644
index 0000000000..67e6986f5d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_url_map.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Voir sur la carte" name="show_on_map"/>
+ <menu_item_call label="Me téléporter à cet endroit" name="teleport_to_location"/>
+ <menu_item_call label="Copier la SLurl dans le presse-papiers" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_url_objectim.xml b/indra/newview/skins/minimal/xui/fr/menu_url_objectim.xml
new file mode 100644
index 0000000000..f581c3ef9d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_url_objectim.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Afficher les informations sur l&apos;objet" name="show_object"/>
+ <menu_item_call label="Voir sur la carte" name="show_on_map"/>
+ <menu_item_call label="Me téléporter à l&apos;emplacement de l&apos;objet" name="teleport_to_object"/>
+ <menu_item_call label="Copier le nom de l&apos;objet dans le presse-papiers" name="url_copy_label"/>
+ <menu_item_call label="Copier la SLurl dans le presse-papiers" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_url_parcel.xml b/indra/newview/skins/minimal/xui/fr/menu_url_parcel.xml
new file mode 100644
index 0000000000..07b0eeca49
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_url_parcel.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Afficher les informations sur la parcelle" name="show_parcel"/>
+ <menu_item_call label="Voir sur la carte" name="show_on_map"/>
+ <menu_item_call label="Copier la SLurl dans le presse-papiers" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_url_slapp.xml b/indra/newview/skins/minimal/xui/fr/menu_url_slapp.xml
new file mode 100644
index 0000000000..f4b7e212ca
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_url_slapp.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Exécuter cette commande" name="run_slapp"/>
+ <menu_item_call label="Copier la SLurl dans le presse-papiers" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_url_slurl.xml b/indra/newview/skins/minimal/xui/fr/menu_url_slurl.xml
new file mode 100644
index 0000000000..e44943cf15
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_url_slurl.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Afficher les informations sur ce lieu" name="show_place"/>
+ <menu_item_call label="Voir sur la carte" name="show_on_map"/>
+ <menu_item_call label="Me téléporter à cet endroit" name="teleport_to_location"/>
+ <menu_item_call label="Copier la SLurl dans le presse-papiers" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_url_teleport.xml b/indra/newview/skins/minimal/xui/fr/menu_url_teleport.xml
new file mode 100644
index 0000000000..a5075a2740
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_url_teleport.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Me téléporter à cet endroit." name="teleport"/>
+ <menu_item_call label="Voir sur la carte" name="show_on_map"/>
+ <menu_item_call label="Copier la SLurl dans le presse-papiers" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_viewer.xml b/indra/newview/skins/minimal/xui/fr/menu_viewer.xml
new file mode 100644
index 0000000000..bd1c077f52
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_viewer.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu_bar name="Main Menu">
+ <menu label="Aide" name="Help">
+ <menu_item_call label="Aide de [SECOND_LIFE]" name="Second Life Help"/>
+ </menu>
+ <menu label="Avancé" name="Advanced">
+ <menu label="Raccourcis" name="Shortcuts">
+ <menu_item_check label="Voler" name="Fly"/>
+ <menu_item_call label="Fermer la fenêtre" name="Close Window"/>
+ <menu_item_call label="Fermer toutes les fenêtres" name="Close All Windows"/>
+ <menu_item_call label="Réinitialiser la vue" name="Reset View"/>
+ </menu>
+ </menu>
+</menu_bar>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_wearable_list_item.xml b/indra/newview/skins/minimal/xui/fr/menu_wearable_list_item.xml
new file mode 100644
index 0000000000..187cb4bcd2
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_wearable_list_item.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Outfit Wearable Context Menu">
+ <menu_item_call label="Remplacer" name="wear_replace"/>
+ <menu_item_call label="Porter" name="wear_wear"/>
+ <menu_item_call label="Ajouter" name="wear_add"/>
+ <menu_item_call label="Enlever / Détacher" name="take_off_or_detach"/>
+ <menu_item_call label="Détacher" name="detach"/>
+ <context_menu label="Attacher à" name="wearable_attach_to"/>
+ <context_menu label="Attacher au HUD" name="wearable_attach_to_hud"/>
+ <menu_item_call label="Enlever" name="take_off"/>
+ <menu_item_call label="Modifier" name="edit"/>
+ <menu_item_call label="Profil de l&apos;article" name="object_profile"/>
+ <menu_item_call label="Afficher l&apos;original" name="show_original"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_wearing_gear.xml b/indra/newview/skins/minimal/xui/fr/menu_wearing_gear.xml
new file mode 100644
index 0000000000..0ca9fe1879
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_wearing_gear.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear Wearing">
+ <menu_item_call label="Modifier la tenue" name="edit"/>
+ <menu_item_call label="Enlever" name="takeoff"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/fr/menu_wearing_tab.xml b/indra/newview/skins/minimal/xui/fr/menu_wearing_tab.xml
new file mode 100644
index 0000000000..4d88445506
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/menu_wearing_tab.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Wearing">
+ <menu_item_call label="Enlever" name="take_off"/>
+ <menu_item_call label="Détacher" name="detach"/>
+ <menu_item_call label="Modifier la tenue" name="edit"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/fr/panel_bottomtray.xml
new file mode 100644
index 0000000000..3a01571f54
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/panel_bottomtray.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="bottom_tray">
+ <string name="DragIndicationImageName" value="Accordion_ArrowOpened_Off"/>
+ <string name="SpeakBtnToolTip" value="Active/Désactive le micro"/>
+ <string name="VoiceControlBtnToolTip" value="Affiche/Masque le panneau de contrôle de la voix"/>
+ <layout_stack name="toolbar_stack">
+ <layout_panel name="gesture_panel">
+ <gesture_combo_list label="Geste" name="Gesture" tool_tip="Affiche/Masque les gestes"/>
+ </layout_panel>
+ <layout_panel name="cam_panel">
+ <bottomtray_button label="Affichage" name="camera_btn" tool_tip="Affiche/Masque le contrôle de la caméra"/>
+ </layout_panel>
+ <layout_panel name="avatar_and_destinations_panel">
+ <radio_group name="avatar_and_destination_btns">
+ <radio_item name="destination_btn" value="0"/>
+ <radio_item name="avatar_btn" value="1"/>
+ </radio_group>
+ </layout_panel>
+ <layout_panel name="people_panel">
+ <bottomtray_button label="Personnes" name="show_people_button" tool_tip="Afficher la fenêtre des personnes."/>
+ </layout_panel>
+ <layout_panel name="profile_panel">
+ <bottomtray_button label="Profil" name="show_profile_btn" tool_tip="Afficher la fenêtre de profil."/>
+ </layout_panel>
+ <layout_panel name="howto_panel">
+ <bottomtray_button label="Aide rapide" name="show_help_btn" tool_tip="Ouvrir les rubriques d&apos;aide rapide Second Life."/>
+ </layout_panel>
+ <layout_panel name="im_well_panel">
+ <chiclet_im_well name="im_well">
+ <button name="Unread IM messages" tool_tip="Conversations"/>
+ </chiclet_im_well>
+ </layout_panel>
+ <layout_panel name="notification_well_panel">
+ <chiclet_notification name="notification_well">
+ <button name="Unread" tool_tip="Notifications"/>
+ </chiclet_notification>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_im_control_panel.xml b/indra/newview/skins/minimal/xui/fr/panel_im_control_panel.xml
new file mode 100644
index 0000000000..1f2169e22c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/panel_im_control_panel.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_im_control_panel">
+ <text name="avatar_name" value="Inconnu"/>
+ <layout_stack name="button_stack">
+ <layout_panel name="view_profile_btn_panel">
+ <button label="Profil" name="view_profile_btn"/>
+ </layout_panel>
+ <layout_panel name="add_friend_btn_panel">
+ <button label="Devenir amis" name="add_friend_btn"/>
+ </layout_panel>
+ <layout_panel name="teleport_btn_panel">
+ <button label="Téléporter" name="teleport_btn" tool_tip="Proposer de téléporter cette personne"/>
+ </layout_panel>
+ <layout_panel name="share_btn_panel">
+ <button label="Partager" name="share_btn"/>
+ </layout_panel>
+ <layout_panel name="pay_btn_panel">
+ <button label="Payer" name="pay_btn"/>
+ </layout_panel>
+ <layout_panel name="call_btn_panel">
+ <button label="Appeler" name="call_btn"/>
+ </layout_panel>
+ <layout_panel name="end_call_btn_panel">
+ <button label="Quitter l&apos;appel" name="end_call_btn"/>
+ </layout_panel>
+ <layout_panel name="voice_ctrls_btn_panel">
+ <button label="Contrôles vocaux" name="voice_ctrls_btn"/>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_login.xml b/indra/newview/skins/minimal/xui/fr/panel_login.xml
new file mode 100644
index 0000000000..cb4822e96b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/panel_login.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_login">
+ <panel.string name="create_account_url">
+ http://fr.secondlife.com/registration/
+ </panel.string>
+ <panel.string name="forgot_password_url">
+ http://secondlife.com/account/request.php?lang=fr
+ </panel.string>
+ <layout_stack name="login_widgets">
+ <layout_panel name="login">
+ <text name="username_text">
+ Nom d&apos;utilisateur :
+ </text>
+ <combo_box name="username_combo" tool_tip="Nom d&apos;utilisateur que vous avez choisi lors de votre inscription (par exemple, bobsmith12 ou Steller Sunshine)."/>
+ <text name="password_text">
+ Mot de passe :
+ </text>
+ <check_box label="Enregistrer" name="remember_check"/>
+ <button label="Connexion" name="connect_btn"/>
+ <text name="mode_selection_text">
+ Mode :
+ </text>
+ <combo_box name="mode_combo">
+ <combo_box.item label="Basique (par défaut)" name="Basic"/>
+ <combo_box.item label="Avancé" name="Advanced"/>
+ </combo_box>
+ </layout_panel>
+ <layout_panel name="links">
+ <text name="create_new_account_text">
+ S&apos;inscrire
+ </text>
+ <text name="forgot_password_text">
+ Nom d&apos;utilisateur ou mot de passe oublié ?
+ </text>
+ <text name="login_help">
+ Besoin d&apos;aide ?
+ </text>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_navigation_bar.xml b/indra/newview/skins/minimal/xui/fr/panel_navigation_bar.xml
new file mode 100644
index 0000000000..45caf2323d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/panel_navigation_bar.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="navigation_bar">
+ <panel name="navigation_panel">
+ <pull_button name="back_btn" tool_tip="Revenir à l&apos;emplacement précédent"/>
+ <pull_button name="forward_btn" tool_tip="Avancer d&apos;un emplacement"/>
+ <button name="home_btn" tool_tip="Me téléporter jusqu&apos;à mon domicile"/>
+ <location_input label="Emplacement" name="location_combo"/>
+ <search_combo_box label="Rechercher" name="search_combo_box" tool_tip="Rechercher">
+ <combo_editor label="Rechercher dans [SECOND_LIFE]" name="search_combo_editor"/>
+ </search_combo_box>
+ </panel>
+ <favorites_bar name="favorite" tool_tip="Faites glisser des repères ici pour un accès rapide à vos lieux favoris dans Second Life.">
+ <label name="favorites_bar_label" tool_tip="Faites glisser des repères ici pour un accès rapide à vos lieux favoris dans Second Life.">
+ Favoris
+ </label>
+ <chevron_button name="&gt;&gt;" tool_tip="Afficher d&apos;avantage de Favoris"/>
+ </favorites_bar>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_people.xml b/indra/newview/skins/minimal/xui/fr/panel_people.xml
new file mode 100644
index 0000000000..88409a2a86
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/panel_people.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray panel -->
+<panel label="Résidents" name="people_panel">
+ <string name="no_recent_people" value="Personne de récent. Vous recherchez des résidents avec qui passer du temps ? Essayez avec le bouton Destinations ci-dessous."/>
+ <string name="no_filtered_recent_people" value="Personne de récent portant ce nom."/>
+ <string name="no_one_near" value="Personne près de vous. Vous recherchez des résidents avec qui passer du temps ? Essayez avec le bouton Destinations ci-dessous."/>
+ <string name="no_one_filtered_near" value="Personne près de vous portant ce nom."/>
+ <string name="no_friends_online" value="Pas d&apos;amis connectés"/>
+ <string name="no_friends" value="Pas d&apos;amis"/>
+ <string name="no_friends_msg">
+ Pour ajouter un résident à votre liste d&apos;amis, cliquez-droit dessus.
+Vous recherchez des résidents avec qui passer du temps ? Essayez avec le bouton Destinations ci-dessous.
+ </string>
+ <string name="no_filtered_friends_msg">
+ Vous n&apos;avez pas trouvé ce que vous cherchiez ? Essayez avec le bouton Destinations ci-dessous.
+ </string>
+ <string name="people_filter_label" value="Filtrer les personnes"/>
+ <string name="groups_filter_label" value="Filtrer les groupes"/>
+ <string name="no_filtered_groups_msg" value="Vous n&apos;avez pas trouvé ce que vous cherchiez ? Essayez [secondlife:///app/search/groups/[SEARCH_TERM] Rechercher]."/>
+ <string name="no_groups_msg" value="Vous souhaitez trouver des groupes à rejoindre ? Utilisez [secondlife:///app/search/groups Rechercher]."/>
+ <string name="MiniMapToolTipMsg" value="[REGION](Carte : double-clic ; Panoramique : Maj + faire glisser)"/>
+ <string name="AltMiniMapToolTipMsg" value="[REGION](Téléportation : double-clic ; Panoramique : Maj + faire glisser)"/>
+ <filter_editor label="Filtre" name="filter_input"/>
+ <tab_container name="tabs">
+ <panel label="PRÈS DE VOUS" name="nearby_panel">
+ <panel label="bottom_panel" name="bottom_panel"/>
+ </panel>
+ <panel label="MES AMIS" name="friends_panel">
+ <accordion name="friends_accordion">
+ <accordion_tab name="tab_online" title="En ligne"/>
+ <accordion_tab name="tab_all" title="Tout"/>
+ </accordion>
+ <panel label="bottom_panel" name="bottom_panel">
+ <layout_stack name="bottom_panel">
+ <layout_panel name="trash_btn_panel">
+ <dnd_button name="del_btn" tool_tip="Supprimer le résident sélectionné de votre liste d&apos;amis."/>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </panel>
+ <panel label="RÉCENT" name="recent_panel">
+ <panel label="bottom_panel" name="bottom_panel">
+ <button name="add_friend_btn" tool_tip="Ajouter le résident sélectionné à votre liste d&apos;amis"/>
+ </panel>
+ </panel>
+ </tab_container>
+ <panel name="button_bar">
+ <layout_stack name="bottom_bar_ls">
+ <layout_panel name="view_profile_btn_lp">
+ <button label="Profil" name="view_profile_btn" tool_tip="Afficher la photo, les groupes et autres infos des résidents"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="IM" name="im_btn" tool_tip="Ouvrir une session IM"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="Téléporter" name="teleport_btn" tool_tip="Proposer une téléportation"/>
+ </layout_panel>
+ </layout_stack>
+ <layout_stack name="bottom_bar_ls1">
+ <layout_panel name="group_info_btn_lp">
+ <button label="Profil du groupe" name="group_info_btn" tool_tip="Afficher les informations sur le groupe"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="Chat de groupe" name="chat_btn" tool_tip="Ouvrir une session de chat"/>
+ </layout_panel>
+ <layout_panel name="group_call_btn_lp">
+ <button label="Appel de groupe" name="group_call_btn" tool_tip="Appeler ce groupe"/>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_side_tray_tab_caption.xml b/indra/newview/skins/minimal/xui/fr/panel_side_tray_tab_caption.xml
new file mode 100644
index 0000000000..45efbdc980
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/panel_side_tray_tab_caption.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="sidetray_tab_panel">
+ <text name="sidetray_tab_title" value="Panneau latéral"/>
+ <button name="undock" tool_tip="Détacher"/>
+ <button name="dock" tool_tip="Attacher"/>
+ <button name="show_help" tool_tip="Afficher l&apos;aide"/>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/fr/panel_status_bar.xml b/indra/newview/skins/minimal/xui/fr/panel_status_bar.xml
new file mode 100644
index 0000000000..69aec99e1d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/fr/panel_status_bar.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="status">
+ <panel.string name="StatBarDaysOfWeek">
+ Sunday:Monday:Tuesday:Wednesday:Thursday:Friday:Saturday
+ </panel.string>
+ <panel.string name="StatBarMonthsOfYear">
+ January:February:March:April:May:June:July:August:September:October:November:December
+ </panel.string>
+ <panel.string name="packet_loss_tooltip">
+ Perte de paquets
+ </panel.string>
+ <panel.string name="bandwidth_tooltip">
+ Bande passante
+ </panel.string>
+ <panel.string name="time">
+ [hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]
+ </panel.string>
+ <panel.string name="timeTooltip">
+ [weekday, datetime, slt] [sday, datetime, slt] [month, datetime, slt] [year, datetime, slt]
+ </panel.string>
+ <panel.string name="buycurrencylabel">
+ [AMT] L$
+ </panel.string>
+ <panel name="balance_bg">
+ <text name="balance" tool_tip="Cliquer sur ce bouton pour actualiser votre solde en L$." value="20 L$"/>
+ <button label="ACHETER L$" name="buyL" tool_tip="Cliquer pour acheter plus de L$"/>
+ </panel>
+ <text name="TimeText" tool_tip="Heure actuelle (Pacifique)">
+ 00h00 PST
+ </text>
+ <button name="media_toggle_btn" tool_tip="Arrêter tous les médias (musique, vidéo, pages web)"/>
+ <button name="volume_btn" tool_tip="Contrôle du volume global"/>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/pt/floater_camera.xml b/indra/newview/skins/minimal/xui/pt/floater_camera.xml
new file mode 100644
index 0000000000..4f3729c623
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/floater_camera.xml
@@ -0,0 +1,65 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="camera_floater" title="">
+ <floater.string name="rotate_tooltip">
+ Girar a Câmera ao redor do Foco
+ </floater.string>
+ <floater.string name="zoom_tooltip">
+ Aproximar a Câmera in direção ao Foco
+ </floater.string>
+ <floater.string name="move_tooltip">
+ Mover a Câmera para Cima e para Baixo, para a Esquerda e para a Direita
+ </floater.string>
+ <floater.string name="camera_modes_title">
+ Modos de câmera
+ </floater.string>
+ <floater.string name="pan_mode_title">
+ Pan zoom orbital
+ </floater.string>
+ <floater.string name="presets_mode_title">
+ Ângulos predefinidos
+ </floater.string>
+ <floater.string name="free_mode_title">
+ Visualizar objeto
+ </floater.string>
+ <panel name="controls">
+ <panel name="preset_views_list">
+ <panel_camera_item name="front_view">
+ <panel_camera_item.text name="front_view_text">
+ Vista frontal
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="group_view">
+ <panel_camera_item.text name="side_view_text">
+ Vista lateral
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="rear_view">
+ <panel_camera_item.text name="rear_view_text">
+ Vista de trás
+ </panel_camera_item.text>
+ </panel_camera_item>
+ </panel>
+ <panel name="camera_modes_list">
+ <panel_camera_item name="object_view">
+ <panel_camera_item.text name="object_view_text">
+ Vista de objetos
+ </panel_camera_item.text>
+ </panel_camera_item>
+ <panel_camera_item name="mouselook_view">
+ <panel_camera_item.text name="mouselook_view_text">
+ Vista do mouse
+ </panel_camera_item.text>
+ </panel_camera_item>
+ </panel>
+ <panel name="zoom" tool_tip="Aproximar a Câmera in direção ao Foco">
+ <joystick_rotate name="cam_rotate_stick" tool_tip="Girar câmera ao redor do foco"/>
+ <slider_bar name="zoom_slider" tool_tip="Zoom de câmera para focalizar"/>
+ <joystick_track name="cam_track_stick" tool_tip="Move a câmera para cima e para baixo, direita e esquerda"/>
+ </panel>
+ </panel>
+ <panel name="buttons">
+ <button label="" name="presets_btn" tool_tip="Ângulos predefinidos"/>
+ <button label="" name="pan_btn" tool_tip="Pan zoom orbital"/>
+ <button label="" name="avatarview_btn" tool_tip="Modos de câmera"/>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/pt/floater_help_browser.xml b/indra/newview/skins/minimal/xui/pt/floater_help_browser.xml
new file mode 100644
index 0000000000..11428ff651
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/floater_help_browser.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="floater_help_browser" title="COMO">
+ <floater.string name="loading_text">
+ Carregando...
+ </floater.string>
+ <layout_stack name="stack1">
+ <layout_panel name="external_controls"/>
+ </layout_stack>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/pt/floater_nearby_chat.xml b/indra/newview/skins/minimal/xui/pt/floater_nearby_chat.xml
new file mode 100644
index 0000000000..60edfa505f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/floater_nearby_chat.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<floater name="nearby_chat" title="Bate-papo local">
+ <check_box label="Traduzir bate-papo (via Google)" name="translate_chat_checkbox"/>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/pt/inspect_avatar.xml b/indra/newview/skins/minimal/xui/pt/inspect_avatar.xml
new file mode 100644
index 0000000000..a199c58c15
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/inspect_avatar.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater name="inspect_avatar">
+ <string name="Subtitle">
+ [IDADE]
+ </string>
+ <string name="Details">
+ [PERFIL_SL]
+ </string>
+ <text name="user_details">
+ This is my second life description and I really think it is great. But for some reason my description is super extra long because I like to talk a whole lot
+ </text>
+ <slider name="volume_slider" tool_tip="Volume de Voz" value="0.5"/>
+ <button label="Adicionar amigo" name="add_friend_btn"/>
+ <button label="MI" name="im_btn"/>
+ <button label="Perfil" name="view_profile_btn"/>
+ <panel name="moderator_panel">
+ <button label="Disabilitar Voz" name="disable_voice"/>
+ <button label="Habilitar Voz" name="enable_voice"/>
+ </panel>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/pt/inspect_object.xml b/indra/newview/skins/minimal/xui/pt/inspect_object.xml
new file mode 100644
index 0000000000..b72de7038d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/inspect_object.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!--
+ Not can_close / no title to avoid window chrome
+ Single instance - only have one at a time, recycle it each spawn
+-->
+<floater name="inspect_object">
+ <string name="Creator">
+ Autor: [CREATOR]
+ </string>
+ <string name="CreatorAndOwner">
+ Autor [CREATOR]
+Proprietário [OWNER]
+ </string>
+ <string name="Price">
+ L$[AMOUNT]
+ </string>
+ <string name="PriceFree">
+ Grátis!
+ </string>
+ <string name="Touch">
+ Tocar
+ </string>
+ <string name="Sit">
+ Sentar
+ </string>
+ <text name="object_name" value="Test Object Name That Is actually two lines and Really Long"/>
+ <text name="price_text">
+ L$30.000
+ </text>
+ <text name="object_description">
+ This is a really long description for an object being as how it is at least 80 characters in length and so but maybe more like 120 at this point. Who knows, really?
+ </text>
+ <button label="Comprar" name="buy_btn"/>
+ <button label="Pagar" name="pay_btn"/>
+ <button label="Pegar uma cópia" name="take_free_copy_btn"/>
+ <button label="Tocar" name="touch_btn"/>
+ <button label="Sentar" name="sit_btn"/>
+ <button label="Abrir" name="open_btn"/>
+ <icon name="secure_browsing" tool_tip="Navegação segura"/>
+ <button label="Mais" name="more_info_btn"/>
+</floater>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_add_wearable_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_add_wearable_gear.xml
new file mode 100644
index 0000000000..4b81276ab3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_add_wearable_gear.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Add Wearable Gear Menu">
+ <menu_item_check label="Ordenar por mais recente" name="sort_by_most_recent"/>
+ <menu_item_check label="Ordenar por nome" name="sort_by_name"/>
+ <menu_item_check label="Ordenar por tipo" name="sort_by_type"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_attachment_other.xml b/indra/newview/skins/minimal/xui/pt/menu_attachment_other.xml
new file mode 100644
index 0000000000..cfd69158bc
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_attachment_other.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: See also menu_avatar_other.xml -->
+<context_menu name="Avatar Pie">
+ <menu_item_call label="Ver perfil" name="Profile..."/>
+ <menu_item_call label="Adicionar amigo..." name="Add Friend"/>
+ <menu_item_call label="MI" name="Send IM..."/>
+ <menu_item_call label="Ligar" name="Call"/>
+ <menu_item_call label="Convidar para entrar no grupo" name="Invite..."/>
+ <menu_item_call label="Bloquear" name="Avatar Mute"/>
+ <menu_item_call label="Denunciar" name="abuse"/>
+ <menu_item_call label="Congelar" name="Freeze..."/>
+ <menu_item_call label="Ejetar" name="Eject..."/>
+ <menu_item_call label="Depurar texturas" name="Debug..."/>
+ <menu_item_call label="Mais zoom" name="Zoom In"/>
+ <menu_item_call label="Pagar" name="Pay..."/>
+ <menu_item_call label="Perfil do objeto" name="Object Inspect"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_attachment_self.xml b/indra/newview/skins/minimal/xui/pt/menu_attachment_self.xml
new file mode 100644
index 0000000000..09060cf3ae
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_attachment_self.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Attachment Pie">
+ <menu_item_call label="Tocar" name="Attachment Object Touch"/>
+ <menu_item_call label="Editar" name="Edit..."/>
+ <menu_item_call label="Tirar" name="Detach"/>
+ <menu_item_call label="Sentar" name="Sit Down Here"/>
+ <menu_item_call label="Ficar de pé" name="Stand Up"/>
+ <menu_item_call label="Trocar de look" name="Change Outfit"/>
+ <menu_item_call label="Editar meu look" name="Edit Outfit"/>
+ <menu_item_call label="Editar meu corpo" name="Edit My Shape"/>
+ <menu_item_call label="Meus amigos" name="Friends..."/>
+ <menu_item_call label="Meus grupos" name="Groups..."/>
+ <menu_item_call label="Meu perfil" name="Profile..."/>
+ <menu_item_call label="Depurar texturas" name="Debug..."/>
+ <menu_item_call label="Largar" name="Drop"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_avatar_icon.xml b/indra/newview/skins/minimal/xui/pt/menu_avatar_icon.xml
new file mode 100644
index 0000000000..beba969b7e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_avatar_icon.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Avatar Icon Menu">
+ <menu_item_call label="Ver perfil" name="Show Profile"/>
+ <menu_item_call label="Enviar MI..." name="Send IM"/>
+ <menu_item_call label="Adicionar amigo..." name="Add Friend"/>
+ <menu_item_call label="Remover amigo..." name="Remove Friend"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_avatar_other.xml b/indra/newview/skins/minimal/xui/pt/menu_avatar_other.xml
new file mode 100644
index 0000000000..a4a26144c7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_avatar_other.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- *NOTE: See also menu_attachment_other.xml -->
+<context_menu name="Avatar Pie">
+ <menu_item_call label="Ver perfil" name="Profile..."/>
+ <menu_item_call label="Adicionar amigo..." name="Add Friend"/>
+ <menu_item_call label="MI" name="Send IM..."/>
+ <menu_item_call label="Ligar" name="Call"/>
+ <menu_item_call label="Convidar para entrar no grupo" name="Invite..."/>
+ <menu_item_call label="Bloquear" name="Avatar Mute"/>
+ <menu_item_call label="Denunciar" name="abuse"/>
+ <menu_item_call label="Congelar" name="Freeze..."/>
+ <menu_item_call label="Ejetar" name="Eject..."/>
+ <menu_item_call label="Depurar texturas" name="Debug..."/>
+ <menu_item_call label="Mais zoom" name="Zoom In"/>
+ <menu_item_call label="Pagar" name="Pay..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_avatar_self.xml b/indra/newview/skins/minimal/xui/pt/menu_avatar_self.xml
new file mode 100644
index 0000000000..6e203d5a25
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_avatar_self.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Self Pie">
+ <menu_item_call label="Sentar" name="Sit Down Here"/>
+ <menu_item_call label="Ficar de pé" name="Stand Up"/>
+ <context_menu label="Tirar" name="Take Off &gt;">
+ <context_menu label="Roupa" name="Clothes &gt;">
+ <menu_item_call label="Camisa" name="Shirt"/>
+ <menu_item_call label="Calças" name="Pants"/>
+ <menu_item_call label="Saia" name="Skirt"/>
+ <menu_item_call label="Sapatos" name="Shoes"/>
+ <menu_item_call label="Meias" name="Socks"/>
+ <menu_item_call label="Jaqueta" name="Jacket"/>
+ <menu_item_call label="Luvas" name="Gloves"/>
+ <menu_item_call label="Camiseta" name="Self Undershirt"/>
+ <menu_item_call label="Roupa de baixo" name="Self Underpants"/>
+ <menu_item_call label="Tatuagem" name="Self Tattoo"/>
+ <menu_item_call label="Alpha" name="Self Alpha"/>
+ <menu_item_call label="Todas as roupas" name="All Clothes"/>
+ </context_menu>
+ <context_menu label="HUD" name="Object Detach HUD"/>
+ <context_menu label="Tirar" name="Object Detach"/>
+ <menu_item_call label="Tirar tudo" name="Detach All"/>
+ </context_menu>
+ <menu_item_call label="Trocar de look" name="Chenge Outfit"/>
+ <menu_item_call label="Editar meu look" name="Edit Outfit"/>
+ <menu_item_call label="Editar meu corpo" name="Edit My Shape"/>
+ <menu_item_call label="Meus amigos" name="Friends..."/>
+ <menu_item_call label="Meus grupos" name="Groups..."/>
+ <menu_item_call label="Meu perfil" name="Profile..."/>
+ <menu_item_call label="Depurar texturas" name="Debug..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_bottomtray.xml b/indra/newview/skins/minimal/xui/pt/menu_bottomtray.xml
new file mode 100644
index 0000000000..479d02512f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_bottomtray.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="hide_camera_move_controls_menu">
+ <menu_item_check label="Botão de gestos" name="ShowGestureButton"/>
+ <menu_item_check label="Botão de movimento" name="ShowMoveButton"/>
+ <menu_item_check label="Botão de ver" name="ShowCameraButton"/>
+ <menu_item_check label="Botão de fotos" name="ShowSnapshotButton"/>
+ <menu_item_check label="Botão da Barra lateral" name="ShowSidebarButton"/>
+ <menu_item_check label="Botão Construir" name="ShowBuildButton"/>
+ <menu_item_check label="Botão Buscar" name="ShowSearchButton"/>
+ <menu_item_check label="Botão Mapa" name="ShowWorldMapButton"/>
+ <menu_item_check label="Botão do Mini Mapa" name="ShowMiniMapButton"/>
+ <menu_item_call label="Cortar" name="NearbyChatBar_Cut"/>
+ <menu_item_call label="Copiar" name="NearbyChatBar_Copy"/>
+ <menu_item_call label="Colar" name="NearbyChatBar_Paste"/>
+ <menu_item_call label="Excluir" name="NearbyChatBar_Delete"/>
+ <menu_item_call label="Selecionar tudo" name="NearbyChatBar_Select_All"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_cof_attachment.xml b/indra/newview/skins/minimal/xui/pt/menu_cof_attachment.xml
new file mode 100644
index 0000000000..527e3af3c9
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_cof_attachment.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Attachment">
+ <menu_item_call label="Separar" name="detach"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_cof_body_part.xml b/indra/newview/skins/minimal/xui/pt/menu_cof_body_part.xml
new file mode 100644
index 0000000000..704fd226eb
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_cof_body_part.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Body">
+ <menu_item_call label="Trocar" name="replace"/>
+ <menu_item_call label="Editar" name="edit"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_cof_clothing.xml b/indra/newview/skins/minimal/xui/pt/menu_cof_clothing.xml
new file mode 100644
index 0000000000..051323ae6a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_cof_clothing.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="COF Clothing">
+ <menu_item_call label="Tirar" name="take_off"/>
+ <menu_item_call label="Editar" name="edit"/>
+ <menu_item_call label="Trocar" name="replace"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_cof_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_cof_gear.xml
new file mode 100644
index 0000000000..8716992a5e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_cof_gear.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear COF">
+ <menu label="Roupas novas" name="COF.Gear.New_Clothes"/>
+ <menu label="Nova parte do corpo" name="COF.Geear.New_Body_Parts"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_edit.xml b/indra/newview/skins/minimal/xui/pt/menu_edit.xml
new file mode 100644
index 0000000000..ff431c9a21
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_edit.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu label="Editar" name="Edit">
+ <menu_item_call label="Desfazer" name="Undo"/>
+ <menu_item_call label="Repetir" name="Redo"/>
+ <menu_item_call label="Cortar" name="Cut"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+ <menu_item_call label="Colar" name="Paste"/>
+ <menu_item_call label="Excluir" name="Delete"/>
+ <menu_item_call label="Replicar" name="Duplicate"/>
+ <menu_item_call label="Selecionar tudo" name="Select All"/>
+ <menu_item_call label="Desfazer seleção" name="Deselect"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_favorites.xml b/indra/newview/skins/minimal/xui/pt/menu_favorites.xml
new file mode 100644
index 0000000000..062820fbca
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_favorites.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Teletransportar" name="Teleport To Landmark"/>
+ <menu_item_call label="Ver/Editar marco" name="Landmark Open"/>
+ <menu_item_call label="Copiar SLurl" name="Copy slurl"/>
+ <menu_item_call label="Mostrar no mapa" name="Show On Map"/>
+ <menu_item_call label="Copiar" name="Landmark Copy"/>
+ <menu_item_call label="Colar" name="Landmark Paste"/>
+ <menu_item_call label="Excluir" name="Delete"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_gesture_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_gesture_gear.xml
new file mode 100644
index 0000000000..70d8ae7a8e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_gesture_gear.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_gesture_gear">
+ <menu_item_call label="Adicionar/remover de favoritos" name="activate"/>
+ <menu_item_call label="Copiar" name="copy_gesture"/>
+ <menu_item_call label="Colar" name="paste"/>
+ <menu_item_call label="Copiar UUID" name="copy_uuid"/>
+ <menu_item_call label="Salvar para look atual" name="save_to_outfit"/>
+ <menu_item_call label="Editar" name="edit_gesture"/>
+ <menu_item_call label="Verificar" name="inspect"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_group_plus.xml b/indra/newview/skins/minimal/xui/pt/menu_group_plus.xml
new file mode 100644
index 0000000000..1083845d68
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_group_plus.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_call label="Entrar no grupo..." name="item_join"/>
+ <menu_item_call label="Novo grupo..." name="item_new"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_hide_navbar.xml b/indra/newview/skins/minimal/xui/pt/menu_hide_navbar.xml
new file mode 100644
index 0000000000..c2b063193e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_hide_navbar.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="hide_navbar_menu">
+ <menu_item_check label="Mostrar barra de navegação" name="ShowNavbarNavigationPanel"/>
+ <menu_item_check label="Mostrar barra de favoritos" name="ShowNavbarFavoritesPanel"/>
+ <menu_item_check label="Mostrar minibarra de localização" name="ShowMiniLocationPanel"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_im_well_button.xml b/indra/newview/skins/minimal/xui/pt/menu_im_well_button.xml
new file mode 100644
index 0000000000..2d37cefd6f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_im_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="IM Well Button Context Menu">
+ <menu_item_call label="Fechar tudo" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_imchiclet_adhoc.xml b/indra/newview/skins/minimal/xui/pt/menu_imchiclet_adhoc.xml
new file mode 100644
index 0000000000..ead949ba13
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_imchiclet_adhoc.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet AdHoc Menu">
+ <menu_item_call label="Encerrar esta sessão" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_imchiclet_group.xml b/indra/newview/skins/minimal/xui/pt/menu_imchiclet_group.xml
new file mode 100644
index 0000000000..dd177d1b8d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_imchiclet_group.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet Group Menu">
+ <menu_item_call label="Sobre o grupo" name="Show Profile"/>
+ <menu_item_call label="Mostrar sessão" name="Chat"/>
+ <menu_item_call label="Encerrar esta sessão" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_imchiclet_p2p.xml b/indra/newview/skins/minimal/xui/pt/menu_imchiclet_p2p.xml
new file mode 100644
index 0000000000..d821b3ded0
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_imchiclet_p2p.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="IMChiclet P2P Menu">
+ <menu_item_call label="Ver perfil" name="Show Profile"/>
+ <menu_item_call label="Adicionar amigo..." name="Add Friend"/>
+ <menu_item_call label="Mostrar sessão" name="Send IM"/>
+ <menu_item_call label="Encerrar esta sessão" name="End Session"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_inspect_avatar_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_inspect_avatar_gear.xml
new file mode 100644
index 0000000000..f7fe5640ef
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_inspect_avatar_gear.xml
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<toggleable_menu name="Gear Menu">
+ <menu_item_call label="Ver perfil" name="view_profile"/>
+ <menu_item_call label="Adicionar amigo..." name="add_friend"/>
+ <menu_item_call label="MI" name="im"/>
+ <menu_item_call label="Teletransportar" name="teleport"/>
+ <menu_item_call label="Bloquear" name="block"/>
+ <menu_item_call label="Desbloquear" name="unblock"/>
+ <menu_item_call label="Denunciar" name="report"/>
+ <menu_item_call label="Congelar" name="freeze"/>
+ <menu_item_call label="Ejetar" name="eject"/>
+ <menu_item_call label="Chutar" name="kick"/>
+ <menu_item_call label="CSR" name="csr"/>
+ <menu_item_call label="Depurar texturas" name="debug"/>
+ <menu_item_call label="Localizar no mapa" name="find_on_map"/>
+ <menu_item_call label="Mais zoom" name="zoom_in"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_inspect_object_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_inspect_object_gear.xml
new file mode 100644
index 0000000000..184db26538
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_inspect_object_gear.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu name="Gear Menu">
+ <menu_item_call label="Tocar" name="touch"/>
+ <menu_item_call label="Sentar" name="sit"/>
+ <menu_item_call label="Pagar" name="pay"/>
+ <menu_item_call label="Comprar" name="buy"/>
+ <menu_item_call label="Pegar" name="take"/>
+ <menu_item_call label="Pegar uma cópia" name="take_copy"/>
+ <menu_item_call label="Abrir" name="open"/>
+ <menu_item_call label="Editar" name="edit"/>
+ <menu_item_call label="Vestir" name="wear"/>
+ <menu_item_call label="Adicionar" name="add"/>
+ <menu_item_call label="Denunciar" name="report"/>
+ <menu_item_call label="Bloquear" name="block"/>
+ <menu_item_call label="Mais zoom" name="zoom_in"/>
+ <menu_item_call label="Tirar" name="remove"/>
+ <menu_item_call label="Mais informações" name="more_info"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml
new file mode 100644
index 0000000000..7e67f4cfd4
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_inspect_self_gear.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8"?>
+<menu name="Gear Menu">
+ <menu_item_call label="Sentar" name="sit_down_here"/>
+ <menu_item_call label="Ficar de pé" name="stand_up"/>
+ <menu_item_call label="Trocar de look" name="change_outfit"/>
+ <menu_item_call label="Meu perfil" name="my_profile"/>
+ <menu_item_call label="Meus amigos" name="my_friends"/>
+ <menu_item_call label="Meus grupos" name="my_groups"/>
+ <menu_item_call label="Depurar texturas" name="Debug..."/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_inv_offer_chiclet.xml b/indra/newview/skins/minimal/xui/pt/menu_inv_offer_chiclet.xml
new file mode 100644
index 0000000000..c404719c95
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_inv_offer_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="InvOfferChiclet Menu">
+ <menu_item_call label="Fechar" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_inventory.xml b/indra/newview/skins/minimal/xui/pt/menu_inventory.xml
new file mode 100644
index 0000000000..1b1efd3270
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_inventory.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Compartilhar" name="Share"/>
+ <menu_item_call label="Comprar" name="Task Buy"/>
+ <menu_item_call label="Abrir" name="Task Open"/>
+ <menu_item_call label="Executar" name="Task Play"/>
+ <menu_item_call label="Propriedades" name="Task Properties"/>
+ <menu_item_call label="Renomear" name="Task Rename"/>
+ <menu_item_call label="Apagar" name="Task Remove"/>
+ <menu_item_call label="Limpar lixeira" name="Empty Trash"/>
+ <menu_item_call label="Limpar Achados &amp; perdidos" name="Empty Lost And Found"/>
+ <menu_item_call label="Nova pasta" name="New Folder"/>
+ <menu_item_call label="Novo script" name="New Script"/>
+ <menu_item_call label="Nova anotação" name="New Note"/>
+ <menu_item_call label="Novo gesto" name="New Gesture"/>
+ <menu label="Novas roupas" name="New Clothes">
+ <menu_item_call label="Nova camisa" name="New Shirt"/>
+ <menu_item_call label="Nova calça" name="New Pants"/>
+ <menu_item_call label="Novos sapatos" name="New Shoes"/>
+ <menu_item_call label="Novas meias" name="New Socks"/>
+ <menu_item_call label="Nova jaqueta" name="New Jacket"/>
+ <menu_item_call label="Nova saia" name="New Skirt"/>
+ <menu_item_call label="Novas luvas" name="New Gloves"/>
+ <menu_item_call label="Nova anágua" name="New Undershirt"/>
+ <menu_item_call label="Nova roupa de baixo" name="New Underpants"/>
+ <menu_item_call label="Nova máscara alfa" name="New Alpha Mask"/>
+ <menu_item_call label="Nova tatuagem" name="New Tattoo"/>
+ </menu>
+ <menu label="Nova parte do corpo" name="New Body Parts">
+ <menu_item_call label="Nova forma" name="New Shape"/>
+ <menu_item_call label="Nova pele" name="New Skin"/>
+ <menu_item_call label="Novo cabelo" name="New Hair"/>
+ <menu_item_call label="Novos olhos" name="New Eyes"/>
+ </menu>
+ <menu label="Alterar fonte" name="Change Type">
+ <menu_item_call label="Padrão" name="Default"/>
+ <menu_item_call label="Luvas" name="Gloves"/>
+ <menu_item_call label="Jaqueta" name="Jacket"/>
+ <menu_item_call label="Calças" name="Pants"/>
+ <menu_item_call label="Silhueta" name="Shape"/>
+ <menu_item_call label="Sapatos" name="Shoes"/>
+ <menu_item_call label="Camisa" name="Shirt"/>
+ <menu_item_call label="Saia" name="Skirt"/>
+ <menu_item_call label="Roupa de baixo" name="Underpants"/>
+ <menu_item_call label="Camiseta" name="Undershirt"/>
+ </menu>
+ <menu_item_call label="Teletransporte" name="Landmark Open"/>
+ <menu_item_call label="Abrir" name="Animation Open"/>
+ <menu_item_call label="Abrir" name="Sound Open"/>
+ <menu_item_call label="Substituir look" name="Replace Outfit"/>
+ <menu_item_call label="Adicionar a look" name="Add To Outfit"/>
+ <menu_item_call label="Tirar do look atual" name="Remove From Outfit"/>
+ <menu_item_call label="Encontrar original" name="Find Original"/>
+ <menu_item_call label="Remover item" name="Purge Item"/>
+ <menu_item_call label="Restaurar item" name="Restore Item"/>
+ <menu_item_call label="Abrir" name="Open"/>
+ <menu_item_call label="Abrir original" name="Open Original"/>
+ <menu_item_call label="Propriedades" name="Properties"/>
+ <menu_item_call label="Renomear" name="Rename"/>
+ <menu_item_call label="Copiar item UUID" name="Copy Asset UUID"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+ <menu_item_call label="Colar" name="Paste"/>
+ <menu_item_call label="Colar como link" name="Paste As Link"/>
+ <menu_item_call label="Excluir" name="Remove Link"/>
+ <menu_item_call label="Apagar" name="Delete"/>
+ <menu_item_call label="Excluir pasta do sistema" name="Delete System Folder"/>
+ <menu_item_call label="Pasta conversa em conferência" name="Conference Chat Folder"/>
+ <menu_item_call label="Executar som" name="Sound Play"/>
+ <menu_item_call label="Sobre o marco" name="About Landmark"/>
+ <menu_item_call label="Executar animação" name="Animation Play"/>
+ <menu_item_call label="Executar áudio" name="Animation Audition"/>
+ <menu_item_call label="Mandar MI" name="Send Instant Message"/>
+ <menu_item_call label="Oferecer teletransporte..." name="Offer Teleport..."/>
+ <menu_item_call label="Bate-papo em conferência" name="Conference Chat"/>
+ <menu_item_call label="Ativar" name="Activate"/>
+ <menu_item_call label="Desativar" name="Deactivate"/>
+ <menu_item_call label="Salvar como" name="Save As"/>
+ <menu_item_call label="Tirar de si mesmo" name="Detach From Yourself"/>
+ <menu_item_call label="Vestir" name="Wearable And Object Wear"/>
+ <menu label="Anexar a" name="Attach To"/>
+ <menu label="Anexar ao HUD" name="Attach To HUD"/>
+ <menu_item_call label="Editar" name="Wearable Edit"/>
+ <menu_item_call label="Adicionar" name="Wearable Add"/>
+ <menu_item_call label="Tirar" name="Take Off"/>
+ <menu_item_call label="--Sem opções--" name="--no options--"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_inventory_add.xml b/indra/newview/skins/minimal/xui/pt/menu_inventory_add.xml
new file mode 100644
index 0000000000..2723f39287
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_inventory_add.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_inventory_add">
+ <menu label="Upload" name="upload">
+ <menu_item_call label="Imagem (L$[COST])..." name="Upload Image"/>
+ <menu_item_call label="Som (L$[COST])..." name="Upload Sound"/>
+ <menu_item_call label="Animação (L$[COST])..." name="Upload Animation"/>
+ <menu_item_call label="Volume (L$[COST] per file)..." name="Bulk Upload"/>
+ <menu_item_call label="Autorizações de upload padrão" name="perm prefs"/>
+ </menu>
+ <menu_item_call label="Nova pasta" name="New Folder"/>
+ <menu_item_call label="Novo script" name="New Script"/>
+ <menu_item_call label="Nova anotação" name="New Note"/>
+ <menu_item_call label="Novo gesto" name="New Gesture"/>
+ <menu label="Novas roupas" name="New Clothes">
+ <menu_item_call label="Nova camisa" name="New Shirt"/>
+ <menu_item_call label="Novas calças" name="New Pants"/>
+ <menu_item_call label="Novos sapatos" name="New Shoes"/>
+ <menu_item_call label="Novas meias" name="New Socks"/>
+ <menu_item_call label="Nova blusa" name="New Jacket"/>
+ <menu_item_call label="Nova saia" name="New Skirt"/>
+ <menu_item_call label="Novas luvas" name="New Gloves"/>
+ <menu_item_call label="Nova camiseta" name="New Undershirt"/>
+ <menu_item_call label="Novas roupa de baixo" name="New Underpants"/>
+ <menu_item_call label="Novo alpha" name="New Alpha"/>
+ <menu_item_call label="Nova tatuagem" name="New Tattoo"/>
+ </menu>
+ <menu label="Nova parte do corpo" name="New Body Parts">
+ <menu_item_call label="Nova forma" name="New Shape"/>
+ <menu_item_call label="Nova pele" name="New Skin"/>
+ <menu_item_call label="Novo cabelo" name="New Hair"/>
+ <menu_item_call label="Novos olhos" name="New Eyes"/>
+ </menu>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_inventory_gear_default.xml b/indra/newview/skins/minimal/xui/pt/menu_inventory_gear_default.xml
new file mode 100644
index 0000000000..3400578d9a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_inventory_gear_default.xml
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="menu_gear_default">
+ <menu_item_call label="Nova janela de inventário" name="new_window"/>
+ <menu_item_check label="Ordenar por nome" name="sort_by_name"/>
+ <menu_item_check label="Ordenar por mais recente" name="sort_by_recent"/>
+ <menu_item_check label="Pastas do sistema no topo" name="sort_system_folders_to_top"/>
+ <menu_item_call label="Mostrar filtros" name="show_filters"/>
+ <menu_item_call label="Restabelecer filtros" name="reset_filters"/>
+ <menu_item_call label="Fechar todas as pastas" name="close_folders"/>
+ <menu_item_call label="Esvaziar achados e perdidos" name="empty_lostnfound"/>
+ <menu_item_call label="Salvar textura como" name="Save Texture As"/>
+ <menu_item_call label="Compartilhar" name="Share"/>
+ <menu_item_call label="Encontrar original" name="Find Original"/>
+ <menu_item_call label="Encontrar todos os links" name="Find All Links"/>
+ <menu_item_call label="Esvaziar lixeira" name="empty_trash"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_land.xml b/indra/newview/skins/minimal/xui/pt/menu_land.xml
new file mode 100644
index 0000000000..9182ce321a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_land.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Land Pie">
+ <menu_item_call label="Sobre terrenos" name="Place Information..."/>
+ <menu_item_call label="Sentar aqui" name="Sit Here"/>
+ <menu_item_call label="Comprar este terreno" name="Land Buy"/>
+ <menu_item_call label="Comprar passe" name="Land Buy Pass"/>
+ <menu_item_call label="Construir" name="Create"/>
+ <menu_item_call label="Editar a topografia" name="Edit Terrain"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_landmark.xml b/indra/newview/skins/minimal/xui/pt/menu_landmark.xml
new file mode 100644
index 0000000000..6accfebee7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_landmark.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="landmark_overflow_menu">
+ <menu_item_call label="Copiar SLurl" name="copy"/>
+ <menu_item_call label="Excluir" name="delete"/>
+ <menu_item_call label="Criar destaque" name="pick"/>
+ <menu_item_call label="Adicionar à barra de favoritos" name="add_to_favbar"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_login.xml b/indra/newview/skins/minimal/xui/pt/menu_login.xml
new file mode 100644
index 0000000000..3dff3d7c8a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_login.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu_bar name="Login Menu">
+ <menu label="Eu" name="File">
+ <menu_item_call label="Preferências" name="Preferences..."/>
+ <menu_item_call label="Sair do [APP_NAME]" name="Quit"/>
+ </menu>
+ <menu label="Ajuda" name="Help">
+ <menu_item_call label="Ajuda do [SECOND_LIFE]" name="Second Life Help"/>
+ <menu_item_call label="Sobre [APP_NAME]" name="About Second Life"/>
+ </menu>
+ <menu_item_check label="Exibir menu de depuração" name="Show Debug Menu"/>
+ <menu label="Depurar" name="Debug">
+ <menu_item_call label="Mostrar configurações" name="Debug Settings"/>
+ <menu_item_call label="Configurações da interface e cor" name="UI/Color Settings"/>
+ <menu label="Testes de UI" name="UI Tests"/>
+ <menu_item_call label="Definir tamanho da janela:" name="Set Window Size..."/>
+ <menu_item_call label="Mostrar TOS" name="TOS"/>
+ <menu_item_call label="Mostrar mensagem crítica" name="Critical"/>
+ <menu_item_call label="Teste de mídia do navegador" name="Web Browser Test"/>
+ <menu_item_call label="Teste de conteúdo web" name="Web Content Floater Test"/>
+ <menu_item_check label="Exibir seletor da grade" name="Show Grid Picker"/>
+ <menu_item_call label="Exibir painel de notificações" name="Show Notifications Console"/>
+ </menu>
+</menu_bar>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_mini_map.xml b/indra/newview/skins/minimal/xui/pt/menu_mini_map.xml
new file mode 100644
index 0000000000..6a3fe55de5
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_mini_map.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Zoom Perto" name="Zoom Close"/>
+ <menu_item_call label="Zoom Médio" name="Zoom Medium"/>
+ <menu_item_call label="Zoom Longe" name="Zoom Far"/>
+ <menu_item_call label="Zoom padrão" name="Zoom Default"/>
+ <menu_item_check label="Girar mapa" name="Rotate Map"/>
+ <menu_item_check label="Auto Center" name="Auto Center"/>
+ <menu_item_call label="Parar Acompanhamento" name="Stop Tracking"/>
+ <menu_item_call label="Mapa-múndi" name="World Map"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_navbar.xml b/indra/newview/skins/minimal/xui/pt/menu_navbar.xml
new file mode 100644
index 0000000000..57c1471de3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_navbar.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Navbar Menu">
+ <menu_item_check label="Mostrar coordenadas" name="Show Coordinates"/>
+ <menu_item_check label="Mostrar as propriedades do terreno" name="Show Parcel Properties"/>
+ <menu_item_call label="Marco" name="Landmark"/>
+ <menu_item_call label="Cortar" name="Cut"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+ <menu_item_call label="Colar" name="Paste"/>
+ <menu_item_call label="Excluir" name="Delete"/>
+ <menu_item_call label="Selecionar tudo" name="Select All"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_nearby_chat.xml b/indra/newview/skins/minimal/xui/pt/menu_nearby_chat.xml
new file mode 100644
index 0000000000..f1ea83c837
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_nearby_chat.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="NearBy Chat Menu">
+ <menu_item_call label="Mostrar quem está aqui..." name="nearby_people"/>
+ <menu_item_check label="Mostrar texto bloqueado" name="muted_text"/>
+ <menu_item_check label="Mostrar ícones de amigos" name="show_buddy_icons"/>
+ <menu_item_check label="Mostrar nomes" name="show_names"/>
+ <menu_item_check label="Mostrar ícones e nomes" name="show_icons_and_names"/>
+ <menu_item_call label="Tamanho da fonte" name="font_size"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_notification_well_button.xml b/indra/newview/skins/minimal/xui/pt/menu_notification_well_button.xml
new file mode 100644
index 0000000000..43ad4134ec
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_notification_well_button.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Notification Well Button Context Menu">
+ <menu_item_call label="Fechar tudo" name="Close All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_object.xml b/indra/newview/skins/minimal/xui/pt/menu_object.xml
new file mode 100644
index 0000000000..bf94859699
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_object.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Object Pie">
+ <menu_item_call label="Tocar" name="Object Touch">
+ <menu_item_call.on_enable name="EnableTouch" parameter="Tocar"/>
+ </menu_item_call>
+ <menu_item_call label="Editar" name="Edit..."/>
+ <menu_item_call label="Construir" name="Build"/>
+ <menu_item_call label="Abrir" name="Open"/>
+ <menu_item_call label="Sentar aqui" name="Object Sit"/>
+ <menu_item_call label="Ficar de pé" name="Object Stand Up"/>
+ <menu_item_call label="Perfil do objeto" name="Object Inspect"/>
+ <menu_item_call label="Mais zoom" name="Zoom In"/>
+ <context_menu label="Colocar no(a)" name="Put On">
+ <menu_item_call label="Vestir" name="Wear"/>
+ <menu_item_call label="Adicionar" name="Add"/>
+ <context_menu label="Anexar" name="Object Attach"/>
+ <context_menu label="Anexar o HUD" name="Object Attach HUD"/>
+ </context_menu>
+ <context_menu label="Tirar" name="Remove">
+ <menu_item_call label="Denunciar abuso" name="Report Abuse..."/>
+ <menu_item_call label="Bloquear" name="Object Mute"/>
+ <menu_item_call label="Devolver" name="Return..."/>
+ <menu_item_call label="Excluir" name="Delete"/>
+ </context_menu>
+ <menu_item_call label="Pegar" name="Pie Object Take"/>
+ <menu_item_call label="Pegar uma cópia" name="Take Copy"/>
+ <menu_item_call label="Pagar" name="Pay..."/>
+ <menu_item_call label="Comprar" name="Buy..."/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_object_icon.xml b/indra/newview/skins/minimal/xui/pt/menu_object_icon.xml
new file mode 100644
index 0000000000..7af760a6ee
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_object_icon.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Object Icon Menu">
+ <menu_item_call label="Perfil do objeto..." name="Object Profile"/>
+ <menu_item_call label="Bloquear..." name="Block"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_outfit_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_outfit_gear.xml
new file mode 100644
index 0000000000..11b3e653c6
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_outfit_gear.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear Outfit">
+ <menu_item_call label="Vestir - Substituir look atual" name="wear"/>
+ <menu_item_call label="Vestir - Adicionar ao look atual" name="wear_add"/>
+ <menu_item_call label="Tirar - Tirar do look atual" name="take_off"/>
+ <menu label="Roupas novas" name="New Clothes">
+ <menu_item_call label="Nova camisa" name="New Shirt"/>
+ <menu_item_call label="Novas calças" name="New Pants"/>
+ <menu_item_call label="Novos sapatos" name="New Shoes"/>
+ <menu_item_call label="Novas meias" name="New Socks"/>
+ <menu_item_call label="Nova blusa" name="New Jacket"/>
+ <menu_item_call label="Nova saia" name="New Skirt"/>
+ <menu_item_call label="Novas luvas" name="New Gloves"/>
+ <menu_item_call label="Nova camiseta" name="New Undershirt"/>
+ <menu_item_call label="Novas roupa de baixo" name="New Underpants"/>
+ <menu_item_call label="Novo alpha" name="New Alpha"/>
+ <menu_item_call label="Nova tatuagem" name="New Tattoo"/>
+ </menu>
+ <menu label="Nova parte do corpo" name="New Body Parts">
+ <menu_item_call label="Nova silhueta" name="New Shape"/>
+ <menu_item_call label="Nova pele" name="New Skin"/>
+ <menu_item_call label="Novo cabelo" name="New Hair"/>
+ <menu_item_call label="Novos olhos" name="New Eyes"/>
+ </menu>
+ <menu_item_call label="Renomear look" name="rename"/>
+ <menu_item_call label="Excluir visual" name="delete_outfit"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_outfit_tab.xml b/indra/newview/skins/minimal/xui/pt/menu_outfit_tab.xml
new file mode 100644
index 0000000000..8db5e405b3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_outfit_tab.xml
@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Outfit">
+ <menu_item_call label="Vestir - Substituir look atual" name="wear_replace"/>
+ <menu_item_call label="Vestir - Sem tirar look atual" name="wear_add"/>
+ <menu_item_call label="Tirar - Tirar do look atual" name="take_off"/>
+ <menu_item_call label="Editar look" name="edit"/>
+ <menu_item_call label="Renomear look" name="rename"/>
+ <menu_item_call label="Excluir visual" name="delete"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_participant_list.xml b/indra/newview/skins/minimal/xui/pt/menu_participant_list.xml
new file mode 100644
index 0000000000..01f1d4ef80
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_participant_list.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Participant List Context Menu">
+ <menu_item_check label="Ordenar por nome" name="SortByName"/>
+ <menu_item_check label="Ordenar por conversas mais recentes" name="SortByRecentSpeakers"/>
+ <menu_item_call label="Ver perfil" name="View Profile"/>
+ <menu_item_call label="Adicionar amigo..." name="Add Friend"/>
+ <menu_item_call label="MI" name="IM"/>
+ <menu_item_call label="Ligar" name="Call"/>
+ <menu_item_call label="Compartilhar" name="Share"/>
+ <menu_item_call label="Pagar" name="Pay"/>
+ <menu_item_check label="Ver ícones de pessoas" name="View Icons"/>
+ <menu_item_check label="Bloquear voz" name="Block/Unblock"/>
+ <menu_item_check label="Bloquear texto" name="MuteText"/>
+ <context_menu label="Opções do moderador &gt;" name="Moderator Options">
+ <menu_item_check label="Pode bater papo por escrito" name="AllowTextChat"/>
+ <menu_item_call label="Silenciar este participante" name="ModerateVoiceMuteSelected"/>
+ <menu_item_call label="Desfazer silenciar deste participante" name="ModerateVoiceUnMuteSelected"/>
+ <menu_item_call label="Silenciar todos" name="ModerateVoiceMute"/>
+ <menu_item_call label="Desfazer silenciar para todos" name="ModerateVoiceUnmute"/>
+ </context_menu>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_people_friends_view_sort.xml b/indra/newview/skins/minimal/xui/pt/menu_people_friends_view_sort.xml
new file mode 100644
index 0000000000..e7c325010f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_people_friends_view_sort.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Ordenar por nome" name="sort_name"/>
+ <menu_item_check label="Ordenar por status" name="sort_status"/>
+ <menu_item_check label="Ver ícones de pessoas" name="view_icons"/>
+ <menu_item_check label="Autorizações de visualização dadas" name="view_permissions"/>
+ <menu_item_call label="Ver residentes e objetos bloqueados" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_people_groups.xml b/indra/newview/skins/minimal/xui/pt/menu_people_groups.xml
new file mode 100644
index 0000000000..9a924ad7b9
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_people_groups.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_call label="Ver dados" name="View Info"/>
+ <menu_item_call label="Bate-papo" name="Chat"/>
+ <menu_item_call label="Ligar" name="Call"/>
+ <menu_item_call label="Ativar" name="Activate"/>
+ <menu_item_call label="Sair" name="Leave"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_people_groups_view_sort.xml b/indra/newview/skins/minimal/xui/pt/menu_people_groups_view_sort.xml
new file mode 100644
index 0000000000..86a9d2263f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_people_groups_view_sort.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Mostrar ícones de grupos" name="Display Group Icons"/>
+ <menu_item_call label="Sair do grupo selecionado" name="Leave Selected Group"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_people_nearby.xml b/indra/newview/skins/minimal/xui/pt/menu_people_nearby.xml
new file mode 100644
index 0000000000..7c720f262b
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_people_nearby.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Avatar Context Menu">
+ <menu_item_call label="Ver perfil" name="View Profile"/>
+ <menu_item_call label="Adicionar amigo..." name="Add Friend"/>
+ <menu_item_call label="Remover amigo..." name="Remove Friend"/>
+ <menu_item_call label="MI" name="IM"/>
+ <menu_item_call label="Ligar" name="Call"/>
+ <menu_item_call label="Mapa" name="Map"/>
+ <menu_item_call label="Compartilhar" name="Share"/>
+ <menu_item_call label="Pagar" name="Pay"/>
+ <menu_item_check label="Bloquear/desbloquear" name="Block/Unblock"/>
+ <menu_item_call label="Teletransportar?" name="teleport"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_people_nearby_multiselect.xml b/indra/newview/skins/minimal/xui/pt/menu_people_nearby_multiselect.xml
new file mode 100644
index 0000000000..79edb96b1c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_people_nearby_multiselect.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Multi-Selected People Context Menu">
+ <menu_item_call label="Adicionar amigo..." name="Add Friends"/>
+ <menu_item_call label="Remover amigo..." name="Remove Friend"/>
+ <menu_item_call label="MI" name="IM"/>
+ <menu_item_call label="Ligar" name="Call"/>
+ <menu_item_call label="Compartilhar" name="Share"/>
+ <menu_item_call label="Pagar" name="Pay"/>
+ <menu_item_call label="Teletransportar?" name="teleport"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_people_nearby_view_sort.xml b/indra/newview/skins/minimal/xui/pt/menu_people_nearby_view_sort.xml
new file mode 100644
index 0000000000..228ce46a31
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_people_nearby_view_sort.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Ordenar por conversas mais recentes" name="sort_by_recent_speakers"/>
+ <menu_item_check label="Ordenar por nome" name="sort_name"/>
+ <menu_item_check label="Ordenar por distância" name="sort_distance"/>
+ <menu_item_check label="Ver ícones de pessoas" name="view_icons"/>
+ <menu_item_call label="Ver residentes e objetos bloqueados" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_people_recent_view_sort.xml b/indra/newview/skins/minimal/xui/pt/menu_people_recent_view_sort.xml
new file mode 100644
index 0000000000..f3b89e01cd
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_people_recent_view_sort.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_group_plus">
+ <menu_item_check label="Ordenar por mais recente" name="sort_most"/>
+ <menu_item_check label="Ordenar por nome" name="sort_name"/>
+ <menu_item_check label="Ver ícones de pessoas" name="view_icons"/>
+ <menu_item_call label="Ver residentes e objetos bloqueados" name="show_blocked_list"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_picks.xml b/indra/newview/skins/minimal/xui/pt/menu_picks.xml
new file mode 100644
index 0000000000..8b9e10fc02
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_picks.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Picks">
+ <menu_item_call label="Info" name="pick_info"/>
+ <menu_item_call label="Editar" name="pick_edit"/>
+ <menu_item_call label="Teletransportar" name="pick_teleport"/>
+ <menu_item_call label="Mapa" name="pick_map"/>
+ <menu_item_call label="Excluir" name="pick_delete"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_picks_plus.xml b/indra/newview/skins/minimal/xui/pt/menu_picks_plus.xml
new file mode 100644
index 0000000000..95a7c05262
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_picks_plus.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="picks_plus_menu">
+ <menu_item_call label="Adicionar" name="create_pick"/>
+ <menu_item_call label="Novo anúncio" name="create_classified"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_place.xml b/indra/newview/skins/minimal/xui/pt/menu_place.xml
new file mode 100644
index 0000000000..282ea20a7a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_place.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="place_overflow_menu">
+ <menu_item_call label="Criar marco" name="landmark"/>
+ <menu_item_call label="Criar destaque" name="pick"/>
+ <menu_item_call label="Comprar passe" name="pass"/>
+ <menu_item_call label="Editar" name="edit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_place_add_button.xml b/indra/newview/skins/minimal/xui/pt/menu_place_add_button.xml
new file mode 100644
index 0000000000..d099d04f8d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_place_add_button.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_folder_gear">
+ <menu_item_call label="Adicionar pasta" name="add_folder"/>
+ <menu_item_call label="Adicionar marco" name="add_landmark"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_places_gear_folder.xml b/indra/newview/skins/minimal/xui/pt/menu_places_gear_folder.xml
new file mode 100644
index 0000000000..2059a9ed2d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_places_gear_folder.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_folder_gear">
+ <menu_item_call label="Adicionar marco" name="add_landmark"/>
+ <menu_item_call label="Adicionar pasta" name="add_folder"/>
+ <menu_item_call label="Cortar" name="cut"/>
+ <menu_item_call label="Copiar" name="copy_folder"/>
+ <menu_item_call label="Colar" name="paste"/>
+ <menu_item_call label="Renomear" name="rename"/>
+ <menu_item_call label="Excluir" name="delete"/>
+ <menu_item_call label="Expanda" name="expand"/>
+ <menu_item_call label="Recolher" name="collapse"/>
+ <menu_item_call label="Expandir todas as pastas" name="expand_all"/>
+ <menu_item_call label="Recolher todas as pastas" name="collapse_all"/>
+ <menu_item_check label="Ordenar por data" name="sort_by_date"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_places_gear_landmark.xml b/indra/newview/skins/minimal/xui/pt/menu_places_gear_landmark.xml
new file mode 100644
index 0000000000..52a9d13735
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_places_gear_landmark.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_ladmark_gear">
+ <menu_item_call label="Teletransportar" name="teleport"/>
+ <menu_item_call label="Mais informações" name="more_info"/>
+ <menu_item_call label="Mostrar no mapa" name="show_on_map"/>
+ <menu_item_call label="Adicionar marco" name="add_landmark"/>
+ <menu_item_call label="Adicionar pasta" name="add_folder"/>
+ <menu_item_call label="Cortar" name="cut"/>
+ <menu_item_call label="Copiar marco" name="copy_landmark"/>
+ <menu_item_call label="Copiar SLurl" name="copy_slurl"/>
+ <menu_item_call label="Colar" name="paste"/>
+ <menu_item_call label="Renomear" name="rename"/>
+ <menu_item_call label="Excluir" name="delete"/>
+ <menu_item_call label="Expandir todas as pastas" name="expand_all"/>
+ <menu_item_call label="Recolher todas as pastas" name="collapse_all"/>
+ <menu_item_check label="Ordenar por data" name="sort_by_date"/>
+ <menu_item_call label="Criar destaque" name="create_pick"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_profile_overflow.xml b/indra/newview/skins/minimal/xui/pt/menu_profile_overflow.xml
new file mode 100644
index 0000000000..d41ecbd755
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_profile_overflow.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="profile_overflow_menu">
+ <menu_item_call label="Mapa" name="show_on_map"/>
+ <menu_item_call label="Pagar" name="pay"/>
+ <menu_item_call label="Compartilhar" name="share"/>
+ <menu_item_call label="Bloquear" name="block"/>
+ <menu_item_call label="Desbloquear" name="unblock"/>
+ <menu_item_call label="Chutar" name="kick"/>
+ <menu_item_call label="Congelar" name="freeze"/>
+ <menu_item_call label="Descongelar" name="unfreeze"/>
+ <menu_item_call label="CSR" name="csr"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_save_outfit.xml b/indra/newview/skins/minimal/xui/pt/menu_save_outfit.xml
new file mode 100644
index 0000000000..61c6b9202f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_save_outfit.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<toggleable_menu name="save_outfit_menu">
+ <menu_item_call label="Salvar" name="save_outfit"/>
+ <menu_item_call label="Salvar como" name="save_as_new_outfit"/>
+</toggleable_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_script_chiclet.xml b/indra/newview/skins/minimal/xui/pt/menu_script_chiclet.xml
new file mode 100644
index 0000000000..ccf3878e14
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_script_chiclet.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="ScriptChiclet Menu">
+ <menu_item_call label="Fechar" name="Close"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_slurl.xml b/indra/newview/skins/minimal/xui/pt/menu_slurl.xml
new file mode 100644
index 0000000000..6d4c84fc3c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_slurl.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Popup">
+ <menu_item_call label="Sobre a URL" name="about_url"/>
+ <menu_item_call label="Teletransporte para a URL" name="teleport_to_url"/>
+ <menu_item_call label="Mapa" name="show_on_map"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_teleport_history_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_teleport_history_gear.xml
new file mode 100644
index 0000000000..f034509be8
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_teleport_history_gear.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Teleport History Gear Context Menu">
+ <menu_item_call label="Expandir todas as pastas" name="Expand all folders"/>
+ <menu_item_call label="Recolher todas as pastas" name="Collapse all folders"/>
+ <menu_item_call label="Limpar histórico de teletransporte" name="Clear Teleport History"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_teleport_history_item.xml b/indra/newview/skins/minimal/xui/pt/menu_teleport_history_item.xml
new file mode 100644
index 0000000000..ec1e7a0950
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_teleport_history_item.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Teleport History Item Context Menu">
+ <menu_item_call label="Teletransportar" name="Teleport"/>
+ <menu_item_call label="Mais informações" name="More Information"/>
+ <menu_item_call label="Copiar" name="CopyToClipboard"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_teleport_history_tab.xml b/indra/newview/skins/minimal/xui/pt/menu_teleport_history_tab.xml
new file mode 100644
index 0000000000..6a633cf74c
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_teleport_history_tab.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Teleport History Item Context Menu">
+ <menu_item_call label="Abrir" name="TabOpen"/>
+ <menu_item_call label="Fechar" name="TabClose"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_text_editor.xml b/indra/newview/skins/minimal/xui/pt/menu_text_editor.xml
new file mode 100644
index 0000000000..31c284c6ed
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_text_editor.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Text editor context menu">
+ <menu_item_call label="Cortar" name="Cut"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+ <menu_item_call label="Colar" name="Paste"/>
+ <menu_item_call label="Excluir" name="Delete"/>
+ <menu_item_call label="Selecionar tudo" name="Select All"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_topinfobar.xml b/indra/newview/skins/minimal/xui/pt/menu_topinfobar.xml
new file mode 100644
index 0000000000..d9347950b1
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_topinfobar.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="menu_topinfobar">
+ <menu_item_check label="Mostrar coordenadas" name="Show Coordinates"/>
+ <menu_item_check label="Mostrar as propriedades do terreno" name="Show Parcel Properties"/>
+ <menu_item_call label="Marco" name="Landmark"/>
+ <menu_item_call label="Copiar" name="Copy"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_url_agent.xml b/indra/newview/skins/minimal/xui/pt/menu_url_agent.xml
new file mode 100644
index 0000000000..ba5e055124
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_url_agent.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar perfil de residente" name="show_agent"/>
+ <menu_item_call label="Copiar nome para área de transferência" name="url_copy_label"/>
+ <menu_item_call label="Copiar SLurl para área de transferência" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_url_group.xml b/indra/newview/skins/minimal/xui/pt/menu_url_group.xml
new file mode 100644
index 0000000000..5b67a69c9a
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_url_group.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar informações do grupo" name="show_group"/>
+ <menu_item_call label="Copiar SLurl para área de transferência" name="url_copy_label"/>
+ <menu_item_call label="Copiar SLurl para área de transferência" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_url_http.xml b/indra/newview/skins/minimal/xui/pt/menu_url_http.xml
new file mode 100644
index 0000000000..e53a2572b8
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_url_http.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Abrir página da web" name="url_open"/>
+ <menu_item_call label="Abrir no navegador do SL" name="url_open_internal"/>
+ <menu_item_call label="Abrir no navegador externo" name="url_open_external"/>
+ <menu_item_call label="Copiar URL para área de transferência" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_url_inventory.xml b/indra/newview/skins/minimal/xui/pt/menu_url_inventory.xml
new file mode 100644
index 0000000000..45c14355d0
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_url_inventory.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar item de inventário" name="show_item"/>
+ <menu_item_call label="Copiar nome para área de transferência" name="url_copy_label"/>
+ <menu_item_call label="Copiar SLurl para área de transferência" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_url_map.xml b/indra/newview/skins/minimal/xui/pt/menu_url_map.xml
new file mode 100644
index 0000000000..ba114cccaa
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_url_map.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar no mapa" name="show_on_map"/>
+ <menu_item_call label="Teletransportar para este lugar" name="teleport_to_location"/>
+ <menu_item_call label="Copiar SLurl para área de transferência" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_url_objectim.xml b/indra/newview/skins/minimal/xui/pt/menu_url_objectim.xml
new file mode 100644
index 0000000000..c197444181
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_url_objectim.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar informações sobre o objeto" name="show_object"/>
+ <menu_item_call label="Mostrar no mapa" name="show_on_map"/>
+ <menu_item_call label="Teletransportar para lugar do objeto" name="teleport_to_object"/>
+ <menu_item_call label="Copiar nome do objeto para área de transferência" name="url_copy_label"/>
+ <menu_item_call label="Copiar SLurl para área de transferência" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_url_parcel.xml b/indra/newview/skins/minimal/xui/pt/menu_url_parcel.xml
new file mode 100644
index 0000000000..6cc668bfd3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_url_parcel.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar informações sobre este lote" name="show_parcel"/>
+ <menu_item_call label="Mostrar no mapa" name="show_on_map"/>
+ <menu_item_call label="Copiar SLurl para área de transferência" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_url_slapp.xml b/indra/newview/skins/minimal/xui/pt/menu_url_slapp.xml
new file mode 100644
index 0000000000..d0784149ac
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_url_slapp.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Executar este comando" name="run_slapp"/>
+ <menu_item_call label="Copiar SLurl para área de transferência" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_url_slurl.xml b/indra/newview/skins/minimal/xui/pt/menu_url_slurl.xml
new file mode 100644
index 0000000000..7216ccf0b3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_url_slurl.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Mostrar informações sobre este lugar" name="show_place"/>
+ <menu_item_call label="Mostrar no mapa" name="show_on_map"/>
+ <menu_item_call label="Teletransportar para este lugar" name="teleport_to_location"/>
+ <menu_item_call label="Copiar SLurl para área de transferência" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_url_teleport.xml b/indra/newview/skins/minimal/xui/pt/menu_url_teleport.xml
new file mode 100644
index 0000000000..f007425646
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_url_teleport.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Url Popup">
+ <menu_item_call label="Teletransportar para este lugar" name="teleport"/>
+ <menu_item_call label="Mostrar no mapa" name="show_on_map"/>
+ <menu_item_call label="Copiar SLurl para área de transferência" name="url_copy"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_viewer.xml b/indra/newview/skins/minimal/xui/pt/menu_viewer.xml
new file mode 100644
index 0000000000..2bd1e88279
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_viewer.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu_bar name="Main Menu">
+ <menu label="Ajuda" name="Help">
+ <menu_item_call label="[SECOND_LIFE] Ajuda" name="Second Life Help"/>
+ </menu>
+ <menu label="Avançado" name="Advanced">
+ <menu label="Atalhos" name="Shortcuts">
+ <menu_item_check label="Voar" name="Fly"/>
+ <menu_item_call label="Fechar janela" name="Close Window"/>
+ <menu_item_call label="Fechar todas as janelas" name="Close All Windows"/>
+ <menu_item_call label="Visão padrão" name="Reset View"/>
+ </menu>
+ </menu>
+</menu_bar>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_wearable_list_item.xml b/indra/newview/skins/minimal/xui/pt/menu_wearable_list_item.xml
new file mode 100644
index 0000000000..2487f6779f
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_wearable_list_item.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Outfit Wearable Context Menu">
+ <menu_item_call label="Trocar" name="wear_replace"/>
+ <menu_item_call label="Vestir" name="wear_wear"/>
+ <menu_item_call label="Adicionar" name="wear_add"/>
+ <menu_item_call label="Tirar / Separar" name="take_off_or_detach"/>
+ <menu_item_call label="Separar" name="detach"/>
+ <context_menu label="Colocar em" name="wearable_attach_to"/>
+ <context_menu label="Anexar ao HUD" name="wearable_attach_to_hud"/>
+ <menu_item_call label="Tirar" name="take_off"/>
+ <menu_item_call label="Editar" name="edit"/>
+ <menu_item_call label="Perfil do item" name="object_profile"/>
+ <menu_item_call label="Mostrar original" name="show_original"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_wearing_gear.xml b/indra/newview/skins/minimal/xui/pt/menu_wearing_gear.xml
new file mode 100644
index 0000000000..7b6ce4d87e
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_wearing_gear.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<menu name="Gear Wearing">
+ <menu_item_call label="Editar look" name="edit"/>
+ <menu_item_call label="Tirar" name="takeoff"/>
+</menu>
diff --git a/indra/newview/skins/minimal/xui/pt/menu_wearing_tab.xml b/indra/newview/skins/minimal/xui/pt/menu_wearing_tab.xml
new file mode 100644
index 0000000000..4e6e52ebc7
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/menu_wearing_tab.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<context_menu name="Wearing">
+ <menu_item_call label="Tirar" name="take_off"/>
+ <menu_item_call label="Tirar" name="detach"/>
+ <menu_item_call label="Editar look" name="edit"/>
+</context_menu>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_adhoc_control_panel.xml b/indra/newview/skins/minimal/xui/pt/panel_adhoc_control_panel.xml
new file mode 100644
index 0000000000..bd50d4953d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/panel_adhoc_control_panel.xml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_im_control_panel">
+ <layout_stack name="vertical_stack">
+ <layout_panel name="call_btn_panel">
+ <button label="Ligar" name="call_btn"/>
+ </layout_panel>
+ <layout_panel name="end_call_btn_panel">
+ <button label="Desligar" name="end_call_btn"/>
+ </layout_panel>
+ <layout_panel name="voice_ctrls_btn_panel">
+ <button label="Controles de voz" name="voice_ctrls_btn"/>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_bottomtray.xml b/indra/newview/skins/minimal/xui/pt/panel_bottomtray.xml
new file mode 100644
index 0000000000..243f323f09
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/panel_bottomtray.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="bottom_tray">
+ <string name="DragIndicationImageName" value="Accordion_ArrowOpened_Off"/>
+ <string name="SpeakBtnToolTip" value="Liga e desliga o microfone"/>
+ <string name="VoiceControlBtnToolTip" value="Mostra/oculta os controles de voz"/>
+ <layout_stack name="toolbar_stack">
+ <layout_panel name="gesture_panel">
+ <gesture_combo_list label="Gesto" name="Gesture" tool_tip="Mostra/oculta os gestos"/>
+ </layout_panel>
+ <layout_panel name="cam_panel">
+ <bottomtray_button label="Exibir" name="camera_btn" tool_tip="Mostra/oculta os controles da câmera"/>
+ </layout_panel>
+ <layout_panel name="avatar_and_destinations_panel">
+ <radio_group name="avatar_and_destination_btns">
+ <radio_item name="destination_btn" value="0"/>
+ <radio_item name="avatar_btn" value="1"/>
+ </radio_group>
+ </layout_panel>
+ <layout_panel name="people_panel">
+ <bottomtray_button label="Pessoas" name="show_people_button" tool_tip="Exibe as pessoas"/>
+ </layout_panel>
+ <layout_panel name="profile_panel">
+ <bottomtray_button label="Perfil" name="show_profile_btn" tool_tip="Exibe o perfil"/>
+ </layout_panel>
+ <layout_panel name="howto_panel">
+ <bottomtray_button label="Como..." name="show_help_btn" tool_tip="Abrir &quot;Como...&quot; do Second Life"/>
+ </layout_panel>
+ <layout_panel name="im_well_panel">
+ <chiclet_im_well name="im_well">
+ <button name="Unread IM messages" tool_tip="Conversas"/>
+ </chiclet_im_well>
+ </layout_panel>
+ <layout_panel name="notification_well_panel">
+ <chiclet_notification name="notification_well">
+ <button name="Unread" tool_tip="Notificações"/>
+ </chiclet_notification>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_im_control_panel.xml b/indra/newview/skins/minimal/xui/pt/panel_im_control_panel.xml
new file mode 100644
index 0000000000..91b7d1b7cd
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/panel_im_control_panel.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_im_control_panel">
+ <layout_stack name="button_stack">
+ <layout_panel name="view_profile_btn_panel">
+ <button label="Perfil" name="view_profile_btn"/>
+ </layout_panel>
+ <layout_panel name="add_friend_btn_panel">
+ <button label="Adicionar amigo" name="add_friend_btn"/>
+ </layout_panel>
+ <layout_panel name="teleport_btn_panel">
+ <button label="Teletransportar" name="teleport_btn" tool_tip="Oferecer teletransporte"/>
+ </layout_panel>
+ <layout_panel name="share_btn_panel">
+ <button label="Compartilhar" name="share_btn"/>
+ </layout_panel>
+ <layout_panel name="pay_btn_panel">
+ <button label="Pagar" name="pay_btn"/>
+ </layout_panel>
+ <layout_panel name="call_btn_panel">
+ <button label="Ligar" name="call_btn"/>
+ </layout_panel>
+ <layout_panel name="end_call_btn_panel">
+ <button label="Encerrar ligação" name="end_call_btn"/>
+ </layout_panel>
+ <layout_panel name="voice_ctrls_btn_panel">
+ <button label="Controles de voz" name="voice_ctrls_btn"/>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_login.xml b/indra/newview/skins/minimal/xui/pt/panel_login.xml
new file mode 100644
index 0000000000..cd529b0b06
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/panel_login.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="panel_login">
+ <panel.string name="create_account_url">
+ http://join.secondlife.com/
+ </panel.string>
+ <panel.string name="forgot_password_url">
+ http://secondlife.com/account/request.php?lang=pt
+ </panel.string>
+ <layout_stack name="login_widgets">
+ <layout_panel name="login">
+ <text name="username_text">
+ Nome de usuário:
+ </text>
+ <combo_box name="username_combo" tool_tip="O nome de usuário que você escolheu ao fazer seu cadastro, como zecazc12 or Magia Solar"/>
+ <text name="password_text">
+ Senha:
+ </text>
+ <check_box label="Lembrar senha" name="remember_check"/>
+ <button label="conectar" name="connect_btn"/>
+ <text name="mode_selection_text">
+ Modo:
+ </text>
+ <combo_box name="mode_combo">
+ <combo_box.item label="Básico (padrão)" name="Basic"/>
+ <combo_box.item label="Avançado" name="Advanced"/>
+ </combo_box>
+ </layout_panel>
+ <layout_panel name="links">
+ <text name="create_new_account_text">
+ Cadastre-se
+ </text>
+ <text name="forgot_password_text">
+ Esqueceu seu nome ou senha?
+ </text>
+ <text name="login_help">
+ Precisa de ajuda ao conectar?
+ </text>
+ </layout_panel>
+ </layout_stack>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_navigation_bar.xml b/indra/newview/skins/minimal/xui/pt/panel_navigation_bar.xml
new file mode 100644
index 0000000000..01930bf3b3
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/panel_navigation_bar.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="navigation_bar">
+ <panel name="navigation_panel">
+ <pull_button name="back_btn" tool_tip="Voltar para região anterior"/>
+ <pull_button name="forward_btn" tool_tip="Avançar uma região"/>
+ <button name="home_btn" tool_tip="Teletransportar para meu início"/>
+ <location_input label="Onde" name="location_combo"/>
+ <search_combo_box label="Busca" name="search_combo_box" tool_tip="Busca">
+ <combo_editor label="Buscar no [SECOND_LIFE]" name="search_combo_editor"/>
+ </search_combo_box>
+ </panel>
+ <favorites_bar name="favorite" tool_tip="Arraste marcos para cá para acessar seus lugares preferidos do Second Life!">
+ <label name="favorites_bar_label" tool_tip="Arraste marcos para cá para acessar seus lugares preferidos do Second Life!">
+ Barra Destaques
+ </label>
+ <chevron_button name="&gt;&gt;" tool_tip="Mostrar mais favoritos"/>
+ </favorites_bar>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_people.xml b/indra/newview/skins/minimal/xui/pt/panel_people.xml
new file mode 100644
index 0000000000..935ade2177
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/panel_people.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<!-- Side tray panel -->
+<panel label="Pessoas" name="people_panel">
+ <string name="no_recent_people" value="Ninguém, recentemente. Em busca de alguém para conversar? Confira o botão Destinos abaixo."/>
+ <string name="no_filtered_recent_people" value="Não há ninguém com esse nome ultimamente."/>
+ <string name="no_one_near" value="Ninguém por perto Em busca de alguém para conversar? Confira o botão Destinos abaixo."/>
+ <string name="no_one_filtered_near" value="Não há ninguém com esse nome por perto."/>
+ <string name="no_friends_online" value="Nenhum amigo online"/>
+ <string name="no_friends" value="Nenhum amigo"/>
+ <string name="no_friends_msg">
+ Clique em um residente com o botão direito to mouse para adicioná-lo como amigo.
+Em busca de alguém para conversar? Confira o botão Destinos abaixo.
+ </string>
+ <string name="no_filtered_friends_msg">
+ Não encontrou o que procura? Confira o botão Destinos abaixo.
+ </string>
+ <string name="people_filter_label" value="Filtro de pessoas"/>
+ <string name="groups_filter_label" value="Filtro de grupos"/>
+ <string name="no_filtered_groups_msg" value="Não encontrou o que procura? Tente buscar no [secondlife:///app/search/groups/[SEARCH_TERM] Search]."/>
+ <string name="no_groups_msg" value="À procura de grupos interessantes? Tente fazer uma [secondlife:///app/search/groups Busca]."/>
+ <string name="MiniMapToolTipMsg" value="[REGION](Clique duplo para abrir o Mapa, botão Shift e arrastar para ver mais)"/>
+ <string name="AltMiniMapToolTipMsg" value="[REGION](Clique duplo para se teletransportar, botão Shift e arrastar para ver mais)"/>
+ <filter_editor label="Filtro" name="filter_input"/>
+ <tab_container name="tabs">
+ <panel label="PROXIMIDADE" name="nearby_panel">
+ <panel label="bottom_panel" name="bottom_panel"/>
+ </panel>
+ <panel label="MEUS AMIGOS" name="friends_panel">
+ <accordion name="friends_accordion">
+ <accordion_tab name="tab_online" title="Online"/>
+ <accordion_tab name="tab_all" title="Todos"/>
+ </accordion>
+ <panel label="bottom_panel" name="bottom_panel">
+ <layout_stack name="bottom_panel">
+ <layout_panel name="trash_btn_panel">
+ <dnd_button name="del_btn" tool_tip="Remover a pessoa selecionada da sua lista de amigos"/>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+ </panel>
+ <panel label="RECENTE" name="recent_panel">
+ <panel label="bottom_panel" name="bottom_panel">
+ <button name="add_friend_btn" tool_tip="Adicionar o residente selecionado para sua lista de amigos"/>
+ </panel>
+ </panel>
+ </tab_container>
+ <panel name="button_bar">
+ <layout_stack name="bottom_bar_ls">
+ <layout_panel name="view_profile_btn_lp">
+ <button label="Perfil" name="view_profile_btn" tool_tip="Exibir fotografia, grupos e outras informações dos residentes"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="MI" name="im_btn" tool_tip="Abrir sessão de mensagem instantânea"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="Teletransportar" name="teleport_btn" tool_tip="Oferecer teletransporte"/>
+ </layout_panel>
+ </layout_stack>
+ <layout_stack name="bottom_bar_ls1">
+ <layout_panel name="group_info_btn_lp">
+ <button label="Perfil do grupo" name="group_info_btn" tool_tip="Exibir dados do grupo"/>
+ </layout_panel>
+ <layout_panel name="chat_btn_lp">
+ <button label="Bate-papo de grupo" name="chat_btn" tool_tip="Nova sessão de bate-papo"/>
+ </layout_panel>
+ <layout_panel name="group_call_btn_lp">
+ <button label="Ligar para o grupo" name="group_call_btn" tool_tip="Ligar para este grupo"/>
+ </layout_panel>
+ </layout_stack>
+ </panel>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_side_tray_tab_caption.xml b/indra/newview/skins/minimal/xui/pt/panel_side_tray_tab_caption.xml
new file mode 100644
index 0000000000..09444a5535
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/panel_side_tray_tab_caption.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="sidetray_tab_panel">
+ <text name="sidetray_tab_title" value="Bandeja lateral"/>
+ <button name="undock" tool_tip="Soltar janela"/>
+ <button name="dock" tool_tip="Ancorar janela"/>
+ <button name="show_help" tool_tip="Mostrar ajuda"/>
+</panel>
diff --git a/indra/newview/skins/minimal/xui/pt/panel_status_bar.xml b/indra/newview/skins/minimal/xui/pt/panel_status_bar.xml
new file mode 100644
index 0000000000..f7890ae57d
--- /dev/null
+++ b/indra/newview/skins/minimal/xui/pt/panel_status_bar.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8" standalone="yes"?>
+<panel name="status">
+ <panel.string name="StatBarDaysOfWeek">
+ Domingo:Segunda-feira:Terça-feira:Quarta-feira:Quinta-feira:Sexta-feira:Sábado
+ </panel.string>
+ <panel.string name="StatBarMonthsOfYear">
+ Janeiro:Fevereiro:Março:Abril:Maio:Junho:Julho:Agosto:Setembro:Outubro:Novembro:Dezembro
+ </panel.string>
+ <panel.string name="packet_loss_tooltip">
+ Perda de pacote
+ </panel.string>
+ <panel.string name="bandwidth_tooltip">
+ Banda
+ </panel.string>
+ <panel.string name="time">
+ [hour12, datetime, slt]:[min, datetime, slt] [ampm, datetime, slt] [timezone,datetime, slt]
+ </panel.string>
+ <panel.string name="timeTooltip">
+ [weekday, datetime, slt], [day, datetime, slt] [month, datetime, slt] [year, datetime, slt]
+ </panel.string>
+ <panel.string name="buycurrencylabel">
+ L$ [AMT]
+ </panel.string>
+ <panel name="balance_bg">
+ <text name="balance" tool_tip="Atualizar saldo de L$" value="L$20"/>
+ <button label="Comprar L$" name="buyL" tool_tip="Comprar mais L$"/>
+ </panel>
+ <text name="TimeText" tool_tip="Hora atual (Pacífico)">
+ 24:00 AM PST
+ </text>
+ <button name="media_toggle_btn" tool_tip="Tocar/Pausar todas mídias (música, vídeo, páginas web)"/>
+ <button name="volume_btn" tool_tip="Volume geral"/>
+</panel>
diff --git a/indra/newview/viewer_manifest.py b/indra/newview/viewer_manifest.py
index 1722c84d34..483c9515db 100644
--- a/indra/newview/viewer_manifest.py
+++ b/indra/newview/viewer_manifest.py
@@ -1,975 +1,975 @@
-#!/usr/bin/env python
-"""\
-@file viewer_manifest.py
-@author Ryan Williams
-@brief Description of all installer viewer files, and methods for packaging
- them into installers for all supported platforms.
-
-$LicenseInfo:firstyear=2006&license=viewerlgpl$
-Second Life Viewer Source Code
-Copyright (C) 2006-2011, Linden Research, Inc.
-
-This library is free software; you can redistribute it and/or
-modify it under the terms of the GNU Lesser General Public
-License as published by the Free Software Foundation;
-version 2.1 of the License only.
-
-This library is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-Lesser General Public License for more details.
-
-You should have received a copy of the GNU Lesser General Public
-License along with this library; if not, write to the Free Software
-Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
-
-Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
-$/LicenseInfo$
-"""
-import sys
-import os.path
-import re
-import tarfile
-import time
-viewer_dir = os.path.dirname(__file__)
-# add llmanifest library to our path so we don't have to muck with PYTHONPATH
-sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util'))
-from llmanifest import LLManifest, main, proper_windows_path, path_ancestors
-
-class ViewerManifest(LLManifest):
- def is_packaging_viewer(self):
- # Some commands, files will only be included
- # if we are packaging the viewer on windows.
- # This manifest is also used to copy
- # files during the build (see copy_w_viewer_manifest
- # and copy_l_viewer_manifest targets)
- return 'package' in self.args['actions']
-
- def construct(self):
- super(ViewerManifest, self).construct()
- self.exclude("*.svn*")
- self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg")
- self.path(src="../../etc/message.xml", dst="app_settings/message.xml")
-
- if self.is_packaging_viewer():
- if self.prefix(src="app_settings"):
- self.exclude("logcontrol.xml")
- self.exclude("logcontrol-dev.xml")
- self.path("*.pem")
- self.path("*.ini")
- self.path("*.xml")
- self.path("*.db2")
-
- # include the entire shaders directory recursively
- self.path("shaders")
- # ... and the entire windlight directory
- self.path("windlight")
- self.end_prefix("app_settings")
-
- if self.prefix(src="character"):
- self.path("*.llm")
- self.path("*.xml")
- self.path("*.tga")
- self.end_prefix("character")
-
- # Include our fonts
- if self.prefix(src="fonts"):
- self.path("*.ttf")
- self.path("*.txt")
- self.end_prefix("fonts")
-
- # skins
- if self.prefix(src="skins"):
- self.path("paths.xml")
- # include the entire textures directory recursively
- if self.prefix(src="*/textures"):
- self.path("*/*.tga")
- self.path("*/*.j2c")
- self.path("*/*.jpg")
- self.path("*/*.png")
- self.path("*.tga")
- self.path("*.j2c")
- self.path("*.jpg")
- self.path("*.png")
- self.path("textures.xml")
- self.end_prefix("*/textures")
- self.path("*/xui/*/*.xml")
- self.path("*/xui/*/widgets/*.xml")
- self.path("*/*.xml")
-
- # Local HTML files (e.g. loading screen)
- if self.prefix(src="*/html"):
- self.path("*.png")
- self.path("*/*/*.html")
- self.path("*/*/*.gif")
- self.end_prefix("*/html")
- self.end_prefix("skins")
-
- # local_assets dir (for pre-cached textures)
- if self.prefix(src="local_assets"):
- self.path("*.j2c")
- self.path("*.tga")
- self.end_prefix("local_assets")
-
- # Files in the newview/ directory
- self.path("gpu_table.txt")
-
- def login_channel(self):
- """Channel reported for login and upgrade purposes ONLY;
- used for A/B testing"""
- # NOTE: Do not return the normal channel if login_channel
- # is not specified, as some code may branch depending on
- # whether or not this is present
- return self.args.get('login_channel')
-
- def grid(self):
- return self.args['grid']
- def channel(self):
- return self.args['channel']
- def channel_unique(self):
- return self.channel().replace("Second Life", "").strip()
- def channel_oneword(self):
- return "".join(self.channel_unique().split())
- def channel_lowerword(self):
- return self.channel_oneword().lower()
-
- def flags_list(self):
- """ Convenience function that returns the command-line flags
- for the grid"""
-
- # Set command line flags relating to the target grid
- grid_flags = ''
- if not self.default_grid():
- grid_flags = "--grid %(grid)s "\
- "--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\
- {'grid':self.grid()}
-
- # set command line flags for channel
- channel_flags = ''
- if self.login_channel() and self.login_channel() != self.channel():
- # Report a special channel during login, but use default
- channel_flags = '--channel "%s"' % (self.login_channel())
- elif not self.default_channel():
- channel_flags = '--channel "%s"' % self.channel()
-
- # Deal with settings
- setting_flags = ''
- if not self.default_channel() or not self.default_grid():
- if self.default_grid():
- setting_flags = '--settings settings_%s.xml'\
- % self.channel_lowerword()
- else:
- setting_flags = '--settings settings_%s_%s.xml'\
- % (self.grid(), self.channel_lowerword())
-
- return " ".join((channel_flags, grid_flags, setting_flags)).strip()
-
-
-class WindowsManifest(ViewerManifest):
- def final_exe(self):
- if self.default_channel():
- if self.default_grid():
- return "SecondLife.exe"
- else:
- return "SecondLifePreview.exe"
- else:
- return ''.join(self.channel().split()) + '.exe'
-
- def test_msvcrt_and_copy_action(self, src, dst):
- # This is used to test a dll manifest.
- # It is used as a temporary override during the construct method
- from test_win32_manifest import test_assembly_binding
- if src and (os.path.exists(src) or os.path.islink(src)):
- # ensure that destination path exists
- self.cmakedirs(os.path.dirname(dst))
- self.created_paths.append(dst)
- if not os.path.isdir(src):
- if(self.args['configuration'].lower() == 'debug'):
- test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "8.0.50727.4053")
- else:
- test_assembly_binding(src, "Microsoft.VC80.CRT", "8.0.50727.4053")
- self.ccopy(src,dst)
- else:
- raise Exception("Directories are not supported by test_CRT_and_copy_action()")
- else:
- print "Doesn't exist:", src
-
- def test_for_no_msvcrt_manifest_and_copy_action(self, src, dst):
- # This is used to test that no manifest for the msvcrt exists.
- # It is used as a temporary override during the construct method
- from test_win32_manifest import test_assembly_binding
- from test_win32_manifest import NoManifestException, NoMatchingAssemblyException
- if src and (os.path.exists(src) or os.path.islink(src)):
- # ensure that destination path exists
- self.cmakedirs(os.path.dirname(dst))
- self.created_paths.append(dst)
- if not os.path.isdir(src):
- try:
- if(self.args['configuration'].lower() == 'debug'):
- test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "")
- else:
- test_assembly_binding(src, "Microsoft.VC80.CRT", "")
- raise Exception("Unknown condition")
- except NoManifestException, err:
- pass
- except NoMatchingAssemblyException, err:
- pass
-
- self.ccopy(src,dst)
- else:
- raise Exception("Directories are not supported by test_CRT_and_copy_action()")
- else:
- print "Doesn't exist:", src
-
- def enable_crt_manifest_check(self):
- if self.is_packaging_viewer():
- WindowsManifest.copy_action = WindowsManifest.test_msvcrt_and_copy_action
-
- def enable_no_crt_manifest_check(self):
- if self.is_packaging_viewer():
- WindowsManifest.copy_action = WindowsManifest.test_for_no_msvcrt_manifest_and_copy_action
-
- def disable_manifest_check(self):
- if self.is_packaging_viewer():
- del WindowsManifest.copy_action
-
- def construct(self):
- super(WindowsManifest, self).construct()
-
- self.enable_crt_manifest_check()
-
- if self.is_packaging_viewer():
- # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe.
- self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe())
-
- # Plugin host application
- self.path(os.path.join(os.pardir,
- 'llplugin', 'slplugin', self.args['configuration'], "slplugin.exe"),
- "slplugin.exe")
-
- self.disable_manifest_check()
-
- self.path(src="../viewer_components/updater/scripts/windows/update_install.bat", dst="update_install.bat")
-
- # Get shared libs from the shared libs staging directory
- if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
- dst=""):
-
- self.enable_crt_manifest_check()
-
- # Get llcommon and deps. If missing assume static linkage and continue.
- try:
- self.path('llcommon.dll')
- self.path('libapr-1.dll')
- self.path('libaprutil-1.dll')
- self.path('libapriconv-1.dll')
- except RuntimeError, err:
- print err.message
- print "Skipping llcommon.dll (assuming llcommon was linked statically)"
-
- self.disable_manifest_check()
-
- # Get fmod dll, continue if missing
- try:
- self.path("fmod.dll")
- except:
- print "Skipping fmod.dll"
-
- # For textures
- if self.args['configuration'].lower() == 'debug':
- self.path("openjpegd.dll")
- else:
- self.path("openjpeg.dll")
-
- # These need to be installed as a SxS assembly, currently a 'private' assembly.
- # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx
- if self.args['configuration'].lower() == 'debug':
- self.path("msvcr80d.dll")
- self.path("msvcp80d.dll")
- self.path("Microsoft.VC80.DebugCRT.manifest")
- else:
- self.path("msvcr80.dll")
- self.path("msvcp80.dll")
- self.path("Microsoft.VC80.CRT.manifest")
-
- # Vivox runtimes
- self.path("SLVoice.exe")
- self.path("vivoxsdk.dll")
- self.path("ortp.dll")
- self.path("libsndfile-1.dll")
- self.path("zlib1.dll")
- self.path("vivoxplatform.dll")
- self.path("vivoxoal.dll")
-
- # For google-perftools tcmalloc allocator.
- try:
- if self.args['configuration'].lower() == 'debug':
- self.path('libtcmalloc_minimal-debug.dll')
- else:
- self.path('libtcmalloc_minimal.dll')
- except:
- print "Skipping libtcmalloc_minimal.dll"
-
- self.end_prefix()
-
- self.path(src="licenses-win32.txt", dst="licenses.txt")
- self.path("featuretable.txt")
- self.path("featuretable_xp.txt")
-
- # For use in crash reporting (generates minidumps)
- self.path("dbghelp.dll")
-
- self.enable_no_crt_manifest_check()
-
- # Media plugins - QuickTime
- if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"):
- self.path("media_plugin_quicktime.dll")
- self.end_prefix()
-
- # Media plugins - WebKit/Qt
- if self.prefix(src='../media_plugins/webkit/%s' % self.args['configuration'], dst="llplugin"):
- self.path("media_plugin_webkit.dll")
- self.end_prefix()
-
- # winmm.dll shim
- if self.prefix(src='../media_plugins/winmmshim/%s' % self.args['configuration'], dst="llplugin"):
- self.path("winmm.dll")
- self.end_prefix()
-
-
- if self.args['configuration'].lower() == 'debug':
- if self.prefix(src=os.path.join(os.pardir, os.pardir, 'libraries', 'i686-win32', 'lib', 'debug'),
- dst="llplugin"):
- self.path("libeay32.dll")
- self.path("qtcored4.dll")
- self.path("qtguid4.dll")
- self.path("qtnetworkd4.dll")
- self.path("qtopengld4.dll")
- self.path("qtwebkitd4.dll")
- self.path("qtxmlpatternsd4.dll")
- self.path("ssleay32.dll")
-
- # For WebKit/Qt plugin runtimes (image format plugins)
- if self.prefix(src="imageformats", dst="imageformats"):
- self.path("qgifd4.dll")
- self.path("qicod4.dll")
- self.path("qjpegd4.dll")
- self.path("qmngd4.dll")
- self.path("qsvgd4.dll")
- self.path("qtiffd4.dll")
- self.end_prefix()
-
- # For WebKit/Qt plugin runtimes (codec/character encoding plugins)
- if self.prefix(src="codecs", dst="codecs"):
- self.path("qcncodecsd4.dll")
- self.path("qjpcodecsd4.dll")
- self.path("qkrcodecsd4.dll")
- self.path("qtwcodecsd4.dll")
- self.end_prefix()
-
- self.end_prefix()
- else:
- if self.prefix(src=os.path.join(os.pardir, os.pardir, 'libraries', 'i686-win32', 'lib', 'release'),
- dst="llplugin"):
- self.path("libeay32.dll")
- self.path("qtcore4.dll")
- self.path("qtgui4.dll")
- self.path("qtnetwork4.dll")
- self.path("qtopengl4.dll")
- self.path("qtwebkit4.dll")
- self.path("qtxmlpatterns4.dll")
- self.path("ssleay32.dll")
-
- # For WebKit/Qt plugin runtimes (image format plugins)
- if self.prefix(src="imageformats", dst="imageformats"):
- self.path("qgif4.dll")
- self.path("qico4.dll")
- self.path("qjpeg4.dll")
- self.path("qmng4.dll")
- self.path("qsvg4.dll")
- self.path("qtiff4.dll")
- self.end_prefix()
-
- # For WebKit/Qt plugin runtimes (codec/character encoding plugins)
- if self.prefix(src="codecs", dst="codecs"):
- self.path("qcncodecs4.dll")
- self.path("qjpcodecs4.dll")
- self.path("qkrcodecs4.dll")
- self.path("qtwcodecs4.dll")
- self.end_prefix()
-
- self.end_prefix()
-
- self.disable_manifest_check()
-
- # pull in the crash logger and updater from other projects
- # tag:"crash-logger" here as a cue to the exporter
- self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
- dst="win_crash_logger.exe")
- self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'],
- dst="updater.exe")
-
- if not self.is_packaging_viewer():
- self.package_file = "copied_deps"
-
- def nsi_file_commands(self, install=True):
- def wpath(path):
- if path.endswith('/') or path.endswith(os.path.sep):
- path = path[:-1]
- path = path.replace('/', '\\')
- return path
-
- result = ""
- dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]
- # sort deepest hierarchy first
- dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
- dest_files.reverse()
- out_path = None
- for pkg_file in dest_files:
- rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,''))
- installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file)))
- pkg_file = wpath(os.path.normpath(pkg_file))
- if installed_dir != out_path:
- if install:
- out_path = installed_dir
- result += 'SetOutPath ' + out_path + '\n'
- if install:
- result += 'File ' + pkg_file + '\n'
- else:
- result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n'
- # at the end of a delete, just rmdir all the directories
- if not install:
- deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list]
- # find all ancestors so that we don't skip any dirs that happened to have no non-dir children
- deleted_dirs = []
- for d in deleted_file_dirs:
- deleted_dirs.extend(path_ancestors(d))
- # sort deepest hierarchy first
- deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
- deleted_dirs.reverse()
- prev = None
- for d in deleted_dirs:
- if d != prev: # skip duplicates
- result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n'
- prev = d
-
- return result
-
- def package_finish(self):
- # a standard map of strings for replacing in the templates
- substitution_strings = {
- 'version' : '.'.join(self.args['version']),
- 'version_short' : '.'.join(self.args['version'][:-1]),
- 'version_dashes' : '-'.join(self.args['version']),
- 'final_exe' : self.final_exe(),
- 'grid':self.args['grid'],
- 'grid_caps':self.args['grid'].upper(),
- # escape quotes becase NSIS doesn't handle them well
- 'flags':self.flags_list().replace('"', '$\\"'),
- 'channel':self.channel(),
- 'channel_oneword':self.channel_oneword(),
- 'channel_unique':self.channel_unique(),
- }
-
- version_vars = """
- !define INSTEXE "%(final_exe)s"
- !define VERSION "%(version_short)s"
- !define VERSION_LONG "%(version)s"
- !define VERSION_DASHES "%(version_dashes)s"
- """ % substitution_strings
- if self.default_channel():
- if self.default_grid():
- # release viewer
- installer_file = "Second_Life_%(version_dashes)s_Setup.exe"
- grid_vars_template = """
- OutFile "%(installer_file)s"
- !define INSTFLAGS "%(flags)s"
- !define INSTNAME "SecondLifeViewer2"
- !define SHORTCUT "Second Life Viewer 2"
- !define URLNAME "secondlife"
- Caption "Second Life ${VERSION}"
- """
- else:
- # beta grid viewer
- installer_file = "Second_Life_%(version_dashes)s_(%(grid_caps)s)_Setup.exe"
- grid_vars_template = """
- OutFile "%(installer_file)s"
- !define INSTFLAGS "%(flags)s"
- !define INSTNAME "SecondLife%(grid_caps)s"
- !define SHORTCUT "Second Life (%(grid_caps)s)"
- !define URLNAME "secondlife%(grid)s"
- !define UNINSTALL_SETTINGS 1
- Caption "Second Life %(grid)s ${VERSION}"
- """
- else:
- # some other channel on some grid
- installer_file = "Second_Life_%(version_dashes)s_%(channel_oneword)s_Setup.exe"
- grid_vars_template = """
- OutFile "%(installer_file)s"
- !define INSTFLAGS "%(flags)s"
- !define INSTNAME "SecondLife%(channel_oneword)s"
- !define SHORTCUT "%(channel)s"
- !define URLNAME "secondlife"
- !define UNINSTALL_SETTINGS 1
- Caption "%(channel)s ${VERSION}"
- """
- if 'installer_name' in self.args:
- installer_file = self.args['installer_name']
- else:
- installer_file = installer_file % substitution_strings
- substitution_strings['installer_file'] = installer_file
-
- tempfile = "secondlife_setup_tmp.nsi"
- # the following replaces strings in the nsi template
- # it also does python-style % substitution
- self.replace_in("installers/windows/installer_template.nsi", tempfile, {
- "%%VERSION%%":version_vars,
- "%%SOURCE%%":self.get_src_prefix(),
- "%%GRID_VARS%%":grid_vars_template % substitution_strings,
- "%%INSTALL_FILES%%":self.nsi_file_commands(True),
- "%%DELETE_FILES%%":self.nsi_file_commands(False)})
-
- # We use the Unicode version of NSIS, available from
- # http://www.scratchpaper.com/
- # Check two paths, one for Program Files, and one for Program Files (x86).
- # Yay 64bit windows.
- NSIS_path = os.path.expandvars('${ProgramFiles}\\NSIS\\Unicode\\makensis.exe')
- if not os.path.exists(NSIS_path):
- NSIS_path = os.path.expandvars('${ProgramFiles(x86)}\\NSIS\\Unicode\\makensis.exe')
- self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
- # self.remove(self.dst_path_of(tempfile))
- # If we're on a build machine, sign the code using our Authenticode certificate. JC
- sign_py = os.path.expandvars("${SIGN}")
- if not sign_py or sign_py == "${SIGN}":
- sign_py = 'C:\\buildscripts\\code-signing\\sign.py'
- else:
- sign_py = sign_py.replace('\\', '\\\\\\\\')
- python = os.path.expandvars("${PYTHON}")
- if not python or python == "${PYTHON}":
- python = 'python'
- if os.path.exists(sign_py):
- self.run_command("%s %s %s" % (python, sign_py, self.dst_path_of(installer_file).replace('\\', '\\\\\\\\')))
- else:
- print "Skipping code signing,", sign_py, "does not exist"
- self.created_path(self.dst_path_of(installer_file))
- self.package_file = installer_file
-
-
-class DarwinManifest(ViewerManifest):
- def is_packaging_viewer(self):
- # darwin requires full app bundle packaging even for debugging.
- return True
-
- def construct(self):
- # copy over the build result (this is a no-op if run within the xcode script)
- self.path(self.args['configuration'] + "/Second Life.app", dst="")
-
- if self.prefix(src="", dst="Contents"): # everything goes in Contents
- self.path("Info-SecondLife.plist", dst="Info.plist")
-
- # copy additional libs in <bundle>/Contents/MacOS/
- self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib")
-
- self.path("../viewer_components/updater/scripts/darwin/update_install", "MacOS/update_install")
-
- # most everything goes in the Resources directory
- if self.prefix(src="", dst="Resources"):
- super(DarwinManifest, self).construct()
-
- if self.prefix("cursors_mac"):
- self.path("*.tif")
- self.end_prefix("cursors_mac")
-
- self.path("licenses-mac.txt", dst="licenses.txt")
- self.path("featuretable_mac.txt")
- self.path("SecondLife.nib")
-
- # If we are not using the default channel, use the 'Firstlook
- # icon' to show that it isn't a stable release.
- if self.default_channel() and self.default_grid():
- self.path("secondlife.icns")
- else:
- self.path("secondlife_firstlook.icns", "secondlife.icns")
- self.path("SecondLife.nib")
-
- # Translations
- self.path("English.lproj")
- self.path("German.lproj")
- self.path("Japanese.lproj")
- self.path("Korean.lproj")
- self.path("da.lproj")
- self.path("es.lproj")
- self.path("fr.lproj")
- self.path("hu.lproj")
- self.path("it.lproj")
- self.path("nl.lproj")
- self.path("pl.lproj")
- self.path("pt.lproj")
- self.path("ru.lproj")
- self.path("tr.lproj")
- self.path("uk.lproj")
- self.path("zh-Hans.lproj")
-
- # SLVoice and vivox lols
- self.path("vivox-runtime/universal-darwin/libsndfile.dylib", "libsndfile.dylib")
- self.path("vivox-runtime/universal-darwin/libvivoxoal.dylib", "libvivoxoal.dylib")
- self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib")
- self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib")
- self.path("vivox-runtime/universal-darwin/libvivoxplatform.dylib", "libvivoxplatform.dylib")
- self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice")
-
- libdir = "../../libraries/universal-darwin/lib_release"
- dylibs = {}
-
- # Need to get the llcommon dll from any of the build directories as well
- lib = "llcommon"
- libfile = "lib%s.dylib" % lib
- try:
- self.path(self.find_existing_file(os.path.join(os.pardir,
- lib,
- self.args['configuration'],
- libfile),
- os.path.join(libdir, libfile)),
- dst=libfile)
- except RuntimeError:
- print "Skipping %s" % libfile
- dylibs[lib] = False
- else:
- dylibs[lib] = True
-
- if dylibs["llcommon"]:
- for libfile in ("libapr-1.0.3.7.dylib",
- "libaprutil-1.0.3.8.dylib",
- "libexpat.0.5.0.dylib",
- "libexception_handler.dylib",
- ):
- self.path(os.path.join(libdir, libfile), libfile)
-
- try:
- # FMOD for sound
- self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib")
- except:
- print "Skipping FMOD - not found"
-
- # our apps
- self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app")
- self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app")
-
- # plugin launcher
- self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app")
-
- # our apps dependencies on shared libs
- if dylibs["llcommon"]:
- mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources")
- mac_updater_res_path = self.dst_path_of("mac-updater.app/Contents/Resources")
- slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources")
- for libfile in ("libllcommon.dylib",
- "libapr-1.0.3.7.dylib",
- "libaprutil-1.0.3.8.dylib",
- "libexpat.0.5.0.dylib",
- "libexception_handler.dylib",
- ):
- target_lib = os.path.join('../../..', libfile)
- self.run_command("ln -sf %(target)r %(link)r" %
- {'target': target_lib,
- 'link' : os.path.join(mac_crash_logger_res_path, libfile)}
- )
- self.run_command("ln -sf %(target)r %(link)r" %
- {'target': target_lib,
- 'link' : os.path.join(mac_updater_res_path, libfile)}
- )
- self.run_command("ln -sf %(target)r %(link)r" %
- {'target': target_lib,
- 'link' : os.path.join(slplugin_res_path, libfile)}
- )
-
- # plugins
- if self.prefix(src="", dst="llplugin"):
- self.path("../media_plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib")
- self.path("../media_plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib")
- self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib")
-
- self.end_prefix("llplugin")
-
- # command line arguments for connecting to the proper grid
- self.put_in_file(self.flags_list(), 'arguments.txt')
-
- self.end_prefix("Resources")
-
- self.end_prefix("Contents")
-
- # NOTE: the -S argument to strip causes it to keep enough info for
- # annotated backtraces (i.e. function names in the crash log). 'strip' with no
- # arguments yields a slightly smaller binary but makes crash logs mostly useless.
- # This may be desirable for the final release. Or not.
- if ("package" in self.args['actions'] or
- "unpacked" in self.args['actions']):
- self.run_command('strip -S %(viewer_binary)r' %
- { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')})
-
- def copy_finish(self):
- # Force executable permissions to be set for scripts
- # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802
- for script in 'Contents/MacOS/update_install',:
- self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script))
-
- def package_finish(self):
- channel_standin = 'Second Life Viewer 2' # hah, our default channel is not usable on its own
- if not self.default_channel():
- channel_standin = self.channel()
-
- imagename="SecondLife_" + '_'.join(self.args['version'])
-
- # MBW -- If the mounted volume name changes, it breaks the .DS_Store's background image and icon positioning.
- # If we really need differently named volumes, we'll need to create multiple DS_Store file images, or use some other trick.
-
- volname="Second Life Installer" # DO NOT CHANGE without understanding comment above
-
- if self.default_channel():
- if not self.default_grid():
- # beta case
- imagename = imagename + '_' + self.args['grid'].upper()
- else:
- # first look, etc
- imagename = imagename + '_' + self.channel_oneword().upper()
-
- sparsename = imagename + ".sparseimage"
- finalname = imagename + ".dmg"
- # make sure we don't have stale files laying about
- self.remove(sparsename, finalname)
-
- self.run_command('hdiutil create %(sparse)r -volname %(vol)r -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % {
- 'sparse':sparsename,
- 'vol':volname})
-
- # mount the image and get the name of the mount point and device node
- hdi_output = self.run_command('hdiutil attach -private %r' % sparsename)
- try:
- devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
- volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
-
- if devfile != '/dev/disk1':
- # adding more debugging info based upon nat's hunches to the
- # logs to help track down 'SetFile -a V' failures -brad
- print "WARNING: 'SetFile -a V' command below is probably gonna fail"
-
- # Copy everything in to the mounted .dmg
-
- if self.default_channel() and not self.default_grid():
- app_name = "Second Life " + self.args['grid']
- else:
- app_name = channel_standin.strip()
-
- # Hack:
- # Because there is no easy way to coerce the Finder into positioning
- # the app bundle in the same place with different app names, we are
- # adding multiple .DS_Store files to svn. There is one for release,
- # one for release candidate and one for first look. Any other channels
- # will use the release .DS_Store, and will look broken.
- # - Ambroff 2008-08-20
- dmg_template = os.path.join(
- 'installers',
- 'darwin',
- '%s-dmg' % "".join(self.channel_unique().split()).lower())
-
- if not os.path.exists (self.src_path_of(dmg_template)):
- dmg_template = os.path.join ('installers', 'darwin', 'release-dmg')
-
- for s,d in {self.get_dst_prefix():app_name + ".app",
- os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns",
- os.path.join(dmg_template, "background.jpg"): "background.jpg",
- os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items():
- print "Copying to dmg", s, d
- self.copy_action(self.src_path_of(s), os.path.join(volpath, d))
-
- # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit)
- for f in ".VolumeIcon.icns", "background.jpg", ".DS_Store":
- pathname = os.path.join(volpath, f)
- # We've observed mysterious "no such file" failures of the SetFile
- # command, especially on the first file listed above -- yet
- # subsequent inspection of the target directory confirms it's
- # there. Timing problem with copy command? Try to handle.
- for x in xrange(3):
- if os.path.exists(pathname):
- print "Confirmed existence: %r" % pathname
- break
- print "Waiting for %s copy command to complete (%s)..." % (f, x+1)
- sys.stdout.flush()
- time.sleep(1)
- # If we fall out of the loop above without a successful break, oh
- # well, possibly we've mistaken the nature of the problem. In any
- # case, don't hang up the whole build looping indefinitely, let
- # the original problem manifest by executing the desired command.
- self.run_command('SetFile -a V %r' % pathname)
-
- # Create the alias file (which is a resource file) from the .r
- self.run_command('rez %r -o %r' %
- (self.src_path_of("installers/darwin/release-dmg/Applications-alias.r"),
- os.path.join(volpath, "Applications")))
-
- # Set the alias file's alias and custom icon bits
- self.run_command('SetFile -a AC %r' % os.path.join(volpath, "Applications"))
-
- # Set the disk image root's custom icon bit
- self.run_command('SetFile -a C %r' % volpath)
- finally:
- # Unmount the image even if exceptions from any of the above
- self.run_command('hdiutil detach -force %r' % devfile)
-
- print "Converting temp disk image to final disk image"
- self.run_command('hdiutil convert %(sparse)r -format UDZO -imagekey zlib-level=9 -o %(final)r' % {'sparse':sparsename, 'final':finalname})
- # get rid of the temp file
- self.package_file = finalname
- self.remove(sparsename)
-
-class LinuxManifest(ViewerManifest):
- def construct(self):
- super(LinuxManifest, self).construct()
- self.path("licenses-linux.txt","licenses.txt")
- self.path("res/ll_icon.png","secondlife_icon.png")
- if self.prefix("linux_tools", dst=""):
- self.path("client-readme.txt","README-linux.txt")
- self.path("client-readme-voice.txt","README-linux-voice.txt")
- self.path("client-readme-joystick.txt","README-linux-joystick.txt")
- self.path("wrapper.sh","secondlife")
- self.path("handle_secondlifeprotocol.sh", "etc/handle_secondlifeprotocol.sh")
- self.path("register_secondlifeprotocol.sh", "etc/register_secondlifeprotocol.sh")
- self.path("refresh_desktop_app_entry.sh", "etc/refresh_desktop_app_entry.sh")
- self.path("launch_url.sh","etc/launch_url.sh")
- self.path("install.sh")
- self.end_prefix("linux_tools")
-
- # Create an appropriate gridargs.dat for this package, denoting required grid.
- self.put_in_file(self.flags_list(), 'etc/gridargs.dat')
-
- self.path("secondlife-bin","bin/do-not-directly-run-secondlife-bin")
- self.path("../linux_crash_logger/linux-crash-logger","bin/linux-crash-logger.bin")
- self.path("../linux_updater/linux-updater", "bin/linux-updater.bin")
- self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin")
-
- if self.prefix("res-sdl"):
- self.path("*")
- # recurse
- self.end_prefix("res-sdl")
-
- self.path("../viewer_components/updater/scripts/linux/update_install", "bin/update_install")
-
- # plugins
- if self.prefix(src="", dst="bin/llplugin"):
- self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so")
- self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so")
- self.end_prefix("bin/llplugin")
-
- try:
- self.path("../llcommon/libllcommon.so", "lib/libllcommon.so")
- except:
- print "Skipping llcommon.so (assuming llcommon was linked statically)"
-
- self.path("featuretable_linux.txt")
-
- def copy_finish(self):
- # Force executable permissions to be set for scripts
- # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802
- for script in 'secondlife', 'bin/update_install':
- self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script))
-
- def package_finish(self):
- if 'installer_name' in self.args:
- installer_name = self.args['installer_name']
- else:
- installer_name_components = ['SecondLife_', self.args.get('arch')]
- installer_name_components.extend(self.args['version'])
- installer_name = "_".join(installer_name_components)
- if self.default_channel():
- if not self.default_grid():
- installer_name += '_' + self.args['grid'].upper()
- else:
- installer_name += '_' + self.channel_oneword().upper()
-
- if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer():
- print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
- self.run_command("find %(d)r/bin %(d)r/lib -type f \\! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
-
- # Fix access permissions
- self.run_command("""
- find %(dst)s -type d | xargs --no-run-if-empty chmod 755;
- find %(dst)s -type f -perm 0700 | xargs --no-run-if-empty chmod 0755;
- find %(dst)s -type f -perm 0500 | xargs --no-run-if-empty chmod 0555;
- find %(dst)s -type f -perm 0600 | xargs --no-run-if-empty chmod 0644;
- find %(dst)s -type f -perm 0400 | xargs --no-run-if-empty chmod 0444;
- true""" % {'dst':self.get_dst_prefix() })
- self.package_file = installer_name + '.tar.bz2'
-
- # temporarily move directory tree so that it has the right
- # name in the tarfile
- self.run_command("mv %(dst)s %(inst)s" % {
- 'dst': self.get_dst_prefix(),
- 'inst': self.build_path_of(installer_name)})
- try:
- # only create tarball if it's a release build.
- if self.args['buildtype'].lower() == 'release':
- # --numeric-owner hides the username of the builder for
- # security etc.
- self.run_command('tar -C %(dir)s --numeric-owner -cjf '
- '%(inst_path)s.tar.bz2 %(inst_name)s' % {
- 'dir': self.get_build_prefix(),
- 'inst_name': installer_name,
- 'inst_path':self.build_path_of(installer_name)})
- else:
- print "Skipping %s.tar.bz2 for non-Release build (%s)" % \
- (installer_name, self.args['buildtype'])
- finally:
- self.run_command("mv %(inst)s %(dst)s" % {
- 'dst': self.get_dst_prefix(),
- 'inst': self.build_path_of(installer_name)})
-
-class Linux_i686Manifest(LinuxManifest):
- def construct(self):
- super(Linux_i686Manifest, self).construct()
-
- if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"):
- self.path("libapr-1.so.0")
- self.path("libaprutil-1.so.0")
- self.path("libbreakpad_client.so.0.0.0", "libbreakpad_client.so.0")
- self.path("libdb-4.2.so")
- self.path("libcrypto.so.0.9.7")
- self.path("libexpat.so.1")
- self.path("libssl.so.0.9.7")
- self.path("libuuid.so.1")
- self.path("libSDL-1.2.so.0")
- self.path("libELFIO.so")
- self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3")
- self.path("libalut.so")
- self.path("libopenal.so", "libopenal.so.1")
- self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname
- try:
- self.path("libfmod-3.75.so")
- pass
- except:
- print "Skipping libfmod-3.75.so - not found"
- pass
- self.end_prefix("lib")
-
- # Vivox runtimes
- if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):
- self.path("SLVoice")
- self.end_prefix()
- if self.prefix(src="vivox-runtime/i686-linux", dst="lib"):
- self.path("libortp.so")
- self.path("libsndfile.so.1")
- #self.path("libvivoxoal.so.1") # no - we'll re-use the viewer's own OpenAL lib
- self.path("libvivoxsdk.so")
- self.path("libvivoxplatform.so")
- self.end_prefix("lib")
-
-class Linux_x86_64Manifest(LinuxManifest):
- def construct(self):
- super(Linux_x86_64Manifest, self).construct()
-
- # support file for valgrind debug tool
- self.path("secondlife-i686.supp")
-
-################################################################
-
-if __name__ == "__main__":
- main()
+#!/usr/bin/env python
+"""\
+@file viewer_manifest.py
+@author Ryan Williams
+@brief Description of all installer viewer files, and methods for packaging
+ them into installers for all supported platforms.
+
+$LicenseInfo:firstyear=2006&license=viewerlgpl$
+Second Life Viewer Source Code
+Copyright (C) 2006-2011, Linden Research, Inc.
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation;
+version 2.1 of the License only.
+
+This library is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
+$/LicenseInfo$
+"""
+import sys
+import os.path
+import re
+import tarfile
+import time
+viewer_dir = os.path.dirname(__file__)
+# add llmanifest library to our path so we don't have to muck with PYTHONPATH
+sys.path.append(os.path.join(viewer_dir, '../lib/python/indra/util'))
+from llmanifest import LLManifest, main, proper_windows_path, path_ancestors
+
+class ViewerManifest(LLManifest):
+ def is_packaging_viewer(self):
+ # Some commands, files will only be included
+ # if we are packaging the viewer on windows.
+ # This manifest is also used to copy
+ # files during the build (see copy_w_viewer_manifest
+ # and copy_l_viewer_manifest targets)
+ return 'package' in self.args['actions']
+
+ def construct(self):
+ super(ViewerManifest, self).construct()
+ self.exclude("*.svn*")
+ self.path(src="../../scripts/messages/message_template.msg", dst="app_settings/message_template.msg")
+ self.path(src="../../etc/message.xml", dst="app_settings/message.xml")
+
+ if self.is_packaging_viewer():
+ if self.prefix(src="app_settings"):
+ self.exclude("logcontrol.xml")
+ self.exclude("logcontrol-dev.xml")
+ self.path("*.pem")
+ self.path("*.ini")
+ self.path("*.xml")
+ self.path("*.db2")
+
+ # include the entire shaders directory recursively
+ self.path("shaders")
+ # ... and the entire windlight directory
+ self.path("windlight")
+ self.end_prefix("app_settings")
+
+ if self.prefix(src="character"):
+ self.path("*.llm")
+ self.path("*.xml")
+ self.path("*.tga")
+ self.end_prefix("character")
+
+ # Include our fonts
+ if self.prefix(src="fonts"):
+ self.path("*.ttf")
+ self.path("*.txt")
+ self.end_prefix("fonts")
+
+ # skins
+ if self.prefix(src="skins"):
+ self.path("paths.xml")
+ # include the entire textures directory recursively
+ if self.prefix(src="*/textures"):
+ self.path("*/*.tga")
+ self.path("*/*.j2c")
+ self.path("*/*.jpg")
+ self.path("*/*.png")
+ self.path("*.tga")
+ self.path("*.j2c")
+ self.path("*.jpg")
+ self.path("*.png")
+ self.path("textures.xml")
+ self.end_prefix("*/textures")
+ self.path("*/xui/*/*.xml")
+ self.path("*/xui/*/widgets/*.xml")
+ self.path("*/*.xml")
+
+ # Local HTML files (e.g. loading screen)
+ if self.prefix(src="*/html"):
+ self.path("*.png")
+ self.path("*/*/*.html")
+ self.path("*/*/*.gif")
+ self.end_prefix("*/html")
+ self.end_prefix("skins")
+
+ # local_assets dir (for pre-cached textures)
+ if self.prefix(src="local_assets"):
+ self.path("*.j2c")
+ self.path("*.tga")
+ self.end_prefix("local_assets")
+
+ # Files in the newview/ directory
+ self.path("gpu_table.txt")
+
+ def login_channel(self):
+ """Channel reported for login and upgrade purposes ONLY;
+ used for A/B testing"""
+ # NOTE: Do not return the normal channel if login_channel
+ # is not specified, as some code may branch depending on
+ # whether or not this is present
+ return self.args.get('login_channel')
+
+ def grid(self):
+ return self.args['grid']
+ def channel(self):
+ return self.args['channel']
+ def channel_unique(self):
+ return self.channel().replace("Second Life", "").strip()
+ def channel_oneword(self):
+ return "".join(self.channel_unique().split())
+ def channel_lowerword(self):
+ return self.channel_oneword().lower()
+
+ def flags_list(self):
+ """ Convenience function that returns the command-line flags
+ for the grid"""
+
+ # Set command line flags relating to the target grid
+ grid_flags = ''
+ if not self.default_grid():
+ grid_flags = "--grid %(grid)s "\
+ "--helperuri http://preview-%(grid)s.secondlife.com/helpers/" %\
+ {'grid':self.grid()}
+
+ # set command line flags for channel
+ channel_flags = ''
+ if self.login_channel() and self.login_channel() != self.channel():
+ # Report a special channel during login, but use default
+ channel_flags = '--channel "%s"' % (self.login_channel())
+ elif not self.default_channel():
+ channel_flags = '--channel "%s"' % self.channel()
+
+ # Deal with settings
+ setting_flags = ''
+ if not self.default_channel() or not self.default_grid():
+ if self.default_grid():
+ setting_flags = '--settings settings_%s.xml'\
+ % self.channel_lowerword()
+ else:
+ setting_flags = '--settings settings_%s_%s.xml'\
+ % (self.grid(), self.channel_lowerword())
+
+ return " ".join((channel_flags, grid_flags, setting_flags)).strip()
+
+
+class WindowsManifest(ViewerManifest):
+ def final_exe(self):
+ if self.default_channel():
+ if self.default_grid():
+ return "SecondLife.exe"
+ else:
+ return "SecondLifePreview.exe"
+ else:
+ return ''.join(self.channel().split()) + '.exe'
+
+ def test_msvcrt_and_copy_action(self, src, dst):
+ # This is used to test a dll manifest.
+ # It is used as a temporary override during the construct method
+ from test_win32_manifest import test_assembly_binding
+ if src and (os.path.exists(src) or os.path.islink(src)):
+ # ensure that destination path exists
+ self.cmakedirs(os.path.dirname(dst))
+ self.created_paths.append(dst)
+ if not os.path.isdir(src):
+ if(self.args['configuration'].lower() == 'debug'):
+ test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "8.0.50727.4053")
+ else:
+ test_assembly_binding(src, "Microsoft.VC80.CRT", "8.0.50727.4053")
+ self.ccopy(src,dst)
+ else:
+ raise Exception("Directories are not supported by test_CRT_and_copy_action()")
+ else:
+ print "Doesn't exist:", src
+
+ def test_for_no_msvcrt_manifest_and_copy_action(self, src, dst):
+ # This is used to test that no manifest for the msvcrt exists.
+ # It is used as a temporary override during the construct method
+ from test_win32_manifest import test_assembly_binding
+ from test_win32_manifest import NoManifestException, NoMatchingAssemblyException
+ if src and (os.path.exists(src) or os.path.islink(src)):
+ # ensure that destination path exists
+ self.cmakedirs(os.path.dirname(dst))
+ self.created_paths.append(dst)
+ if not os.path.isdir(src):
+ try:
+ if(self.args['configuration'].lower() == 'debug'):
+ test_assembly_binding(src, "Microsoft.VC80.DebugCRT", "")
+ else:
+ test_assembly_binding(src, "Microsoft.VC80.CRT", "")
+ raise Exception("Unknown condition")
+ except NoManifestException, err:
+ pass
+ except NoMatchingAssemblyException, err:
+ pass
+
+ self.ccopy(src,dst)
+ else:
+ raise Exception("Directories are not supported by test_CRT_and_copy_action()")
+ else:
+ print "Doesn't exist:", src
+
+ def enable_crt_manifest_check(self):
+ if self.is_packaging_viewer():
+ WindowsManifest.copy_action = WindowsManifest.test_msvcrt_and_copy_action
+
+ def enable_no_crt_manifest_check(self):
+ if self.is_packaging_viewer():
+ WindowsManifest.copy_action = WindowsManifest.test_for_no_msvcrt_manifest_and_copy_action
+
+ def disable_manifest_check(self):
+ if self.is_packaging_viewer():
+ del WindowsManifest.copy_action
+
+ def construct(self):
+ super(WindowsManifest, self).construct()
+
+ self.enable_crt_manifest_check()
+
+ if self.is_packaging_viewer():
+ # Find secondlife-bin.exe in the 'configuration' dir, then rename it to the result of final_exe.
+ self.path(src='%s/secondlife-bin.exe' % self.args['configuration'], dst=self.final_exe())
+
+ # Plugin host application
+ self.path(os.path.join(os.pardir,
+ 'llplugin', 'slplugin', self.args['configuration'], "slplugin.exe"),
+ "slplugin.exe")
+
+ self.disable_manifest_check()
+
+ self.path(src="../viewer_components/updater/scripts/windows/update_install.bat", dst="update_install.bat")
+
+ # Get shared libs from the shared libs staging directory
+ if self.prefix(src=os.path.join(os.pardir, 'sharedlibs', self.args['configuration']),
+ dst=""):
+
+ self.enable_crt_manifest_check()
+
+ # Get llcommon and deps. If missing assume static linkage and continue.
+ try:
+ self.path('llcommon.dll')
+ self.path('libapr-1.dll')
+ self.path('libaprutil-1.dll')
+ self.path('libapriconv-1.dll')
+ except RuntimeError, err:
+ print err.message
+ print "Skipping llcommon.dll (assuming llcommon was linked statically)"
+
+ self.disable_manifest_check()
+
+ # Get fmod dll, continue if missing
+ try:
+ self.path("fmod.dll")
+ except:
+ print "Skipping fmod.dll"
+
+ # For textures
+ if self.args['configuration'].lower() == 'debug':
+ self.path("openjpegd.dll")
+ else:
+ self.path("openjpeg.dll")
+
+ # These need to be installed as a SxS assembly, currently a 'private' assembly.
+ # See http://msdn.microsoft.com/en-us/library/ms235291(VS.80).aspx
+ if self.args['configuration'].lower() == 'debug':
+ self.path("msvcr80d.dll")
+ self.path("msvcp80d.dll")
+ self.path("Microsoft.VC80.DebugCRT.manifest")
+ else:
+ self.path("msvcr80.dll")
+ self.path("msvcp80.dll")
+ self.path("Microsoft.VC80.CRT.manifest")
+
+ # Vivox runtimes
+ self.path("SLVoice.exe")
+ self.path("vivoxsdk.dll")
+ self.path("ortp.dll")
+ self.path("libsndfile-1.dll")
+ self.path("zlib1.dll")
+ self.path("vivoxplatform.dll")
+ self.path("vivoxoal.dll")
+
+ # For google-perftools tcmalloc allocator.
+ try:
+ if self.args['configuration'].lower() == 'debug':
+ self.path('libtcmalloc_minimal-debug.dll')
+ else:
+ self.path('libtcmalloc_minimal.dll')
+ except:
+ print "Skipping libtcmalloc_minimal.dll"
+
+ self.end_prefix()
+
+ self.path(src="licenses-win32.txt", dst="licenses.txt")
+ self.path("featuretable.txt")
+ self.path("featuretable_xp.txt")
+
+ # For use in crash reporting (generates minidumps)
+ self.path("dbghelp.dll")
+
+ self.enable_no_crt_manifest_check()
+
+ # Media plugins - QuickTime
+ if self.prefix(src='../media_plugins/quicktime/%s' % self.args['configuration'], dst="llplugin"):
+ self.path("media_plugin_quicktime.dll")
+ self.end_prefix()
+
+ # Media plugins - WebKit/Qt
+ if self.prefix(src='../media_plugins/webkit/%s' % self.args['configuration'], dst="llplugin"):
+ self.path("media_plugin_webkit.dll")
+ self.end_prefix()
+
+ # winmm.dll shim
+ if self.prefix(src='../media_plugins/winmmshim/%s' % self.args['configuration'], dst=""):
+ self.path("winmm.dll")
+ self.end_prefix()
+
+
+ if self.args['configuration'].lower() == 'debug':
+ if self.prefix(src=os.path.join(os.pardir, os.pardir, 'libraries', 'i686-win32', 'lib', 'debug'),
+ dst="llplugin"):
+ self.path("libeay32.dll")
+ self.path("qtcored4.dll")
+ self.path("qtguid4.dll")
+ self.path("qtnetworkd4.dll")
+ self.path("qtopengld4.dll")
+ self.path("qtwebkitd4.dll")
+ self.path("qtxmlpatternsd4.dll")
+ self.path("ssleay32.dll")
+
+ # For WebKit/Qt plugin runtimes (image format plugins)
+ if self.prefix(src="imageformats", dst="imageformats"):
+ self.path("qgifd4.dll")
+ self.path("qicod4.dll")
+ self.path("qjpegd4.dll")
+ self.path("qmngd4.dll")
+ self.path("qsvgd4.dll")
+ self.path("qtiffd4.dll")
+ self.end_prefix()
+
+ # For WebKit/Qt plugin runtimes (codec/character encoding plugins)
+ if self.prefix(src="codecs", dst="codecs"):
+ self.path("qcncodecsd4.dll")
+ self.path("qjpcodecsd4.dll")
+ self.path("qkrcodecsd4.dll")
+ self.path("qtwcodecsd4.dll")
+ self.end_prefix()
+
+ self.end_prefix()
+ else:
+ if self.prefix(src=os.path.join(os.pardir, os.pardir, 'libraries', 'i686-win32', 'lib', 'release'),
+ dst="llplugin"):
+ self.path("libeay32.dll")
+ self.path("qtcore4.dll")
+ self.path("qtgui4.dll")
+ self.path("qtnetwork4.dll")
+ self.path("qtopengl4.dll")
+ self.path("qtwebkit4.dll")
+ self.path("qtxmlpatterns4.dll")
+ self.path("ssleay32.dll")
+
+ # For WebKit/Qt plugin runtimes (image format plugins)
+ if self.prefix(src="imageformats", dst="imageformats"):
+ self.path("qgif4.dll")
+ self.path("qico4.dll")
+ self.path("qjpeg4.dll")
+ self.path("qmng4.dll")
+ self.path("qsvg4.dll")
+ self.path("qtiff4.dll")
+ self.end_prefix()
+
+ # For WebKit/Qt plugin runtimes (codec/character encoding plugins)
+ if self.prefix(src="codecs", dst="codecs"):
+ self.path("qcncodecs4.dll")
+ self.path("qjpcodecs4.dll")
+ self.path("qkrcodecs4.dll")
+ self.path("qtwcodecs4.dll")
+ self.end_prefix()
+
+ self.end_prefix()
+
+ self.disable_manifest_check()
+
+ # pull in the crash logger and updater from other projects
+ # tag:"crash-logger" here as a cue to the exporter
+ self.path(src='../win_crash_logger/%s/windows-crash-logger.exe' % self.args['configuration'],
+ dst="win_crash_logger.exe")
+ self.path(src='../win_updater/%s/windows-updater.exe' % self.args['configuration'],
+ dst="updater.exe")
+
+ if not self.is_packaging_viewer():
+ self.package_file = "copied_deps"
+
+ def nsi_file_commands(self, install=True):
+ def wpath(path):
+ if path.endswith('/') or path.endswith(os.path.sep):
+ path = path[:-1]
+ path = path.replace('/', '\\')
+ return path
+
+ result = ""
+ dest_files = [pair[1] for pair in self.file_list if pair[0] and os.path.isfile(pair[1])]
+ # sort deepest hierarchy first
+ dest_files.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
+ dest_files.reverse()
+ out_path = None
+ for pkg_file in dest_files:
+ rel_file = os.path.normpath(pkg_file.replace(self.get_dst_prefix()+os.path.sep,''))
+ installed_dir = wpath(os.path.join('$INSTDIR', os.path.dirname(rel_file)))
+ pkg_file = wpath(os.path.normpath(pkg_file))
+ if installed_dir != out_path:
+ if install:
+ out_path = installed_dir
+ result += 'SetOutPath ' + out_path + '\n'
+ if install:
+ result += 'File ' + pkg_file + '\n'
+ else:
+ result += 'Delete ' + wpath(os.path.join('$INSTDIR', rel_file)) + '\n'
+ # at the end of a delete, just rmdir all the directories
+ if not install:
+ deleted_file_dirs = [os.path.dirname(pair[1].replace(self.get_dst_prefix()+os.path.sep,'')) for pair in self.file_list]
+ # find all ancestors so that we don't skip any dirs that happened to have no non-dir children
+ deleted_dirs = []
+ for d in deleted_file_dirs:
+ deleted_dirs.extend(path_ancestors(d))
+ # sort deepest hierarchy first
+ deleted_dirs.sort(lambda a,b: cmp(a.count(os.path.sep),b.count(os.path.sep)) or cmp(a,b))
+ deleted_dirs.reverse()
+ prev = None
+ for d in deleted_dirs:
+ if d != prev: # skip duplicates
+ result += 'RMDir ' + wpath(os.path.join('$INSTDIR', os.path.normpath(d))) + '\n'
+ prev = d
+
+ return result
+
+ def package_finish(self):
+ # a standard map of strings for replacing in the templates
+ substitution_strings = {
+ 'version' : '.'.join(self.args['version']),
+ 'version_short' : '.'.join(self.args['version'][:-1]),
+ 'version_dashes' : '-'.join(self.args['version']),
+ 'final_exe' : self.final_exe(),
+ 'grid':self.args['grid'],
+ 'grid_caps':self.args['grid'].upper(),
+ # escape quotes becase NSIS doesn't handle them well
+ 'flags':self.flags_list().replace('"', '$\\"'),
+ 'channel':self.channel(),
+ 'channel_oneword':self.channel_oneword(),
+ 'channel_unique':self.channel_unique(),
+ }
+
+ version_vars = """
+ !define INSTEXE "%(final_exe)s"
+ !define VERSION "%(version_short)s"
+ !define VERSION_LONG "%(version)s"
+ !define VERSION_DASHES "%(version_dashes)s"
+ """ % substitution_strings
+ if self.default_channel():
+ if self.default_grid():
+ # release viewer
+ installer_file = "Second_Life_%(version_dashes)s_Setup.exe"
+ grid_vars_template = """
+ OutFile "%(installer_file)s"
+ !define INSTFLAGS "%(flags)s"
+ !define INSTNAME "SecondLifeViewer2"
+ !define SHORTCUT "Second Life Viewer 2"
+ !define URLNAME "secondlife"
+ Caption "Second Life ${VERSION}"
+ """
+ else:
+ # beta grid viewer
+ installer_file = "Second_Life_%(version_dashes)s_(%(grid_caps)s)_Setup.exe"
+ grid_vars_template = """
+ OutFile "%(installer_file)s"
+ !define INSTFLAGS "%(flags)s"
+ !define INSTNAME "SecondLife%(grid_caps)s"
+ !define SHORTCUT "Second Life (%(grid_caps)s)"
+ !define URLNAME "secondlife%(grid)s"
+ !define UNINSTALL_SETTINGS 1
+ Caption "Second Life %(grid)s ${VERSION}"
+ """
+ else:
+ # some other channel on some grid
+ installer_file = "Second_Life_%(version_dashes)s_%(channel_oneword)s_Setup.exe"
+ grid_vars_template = """
+ OutFile "%(installer_file)s"
+ !define INSTFLAGS "%(flags)s"
+ !define INSTNAME "SecondLife%(channel_oneword)s"
+ !define SHORTCUT "%(channel)s"
+ !define URLNAME "secondlife"
+ !define UNINSTALL_SETTINGS 1
+ Caption "%(channel)s ${VERSION}"
+ """
+ if 'installer_name' in self.args:
+ installer_file = self.args['installer_name']
+ else:
+ installer_file = installer_file % substitution_strings
+ substitution_strings['installer_file'] = installer_file
+
+ tempfile = "secondlife_setup_tmp.nsi"
+ # the following replaces strings in the nsi template
+ # it also does python-style % substitution
+ self.replace_in("installers/windows/installer_template.nsi", tempfile, {
+ "%%VERSION%%":version_vars,
+ "%%SOURCE%%":self.get_src_prefix(),
+ "%%GRID_VARS%%":grid_vars_template % substitution_strings,
+ "%%INSTALL_FILES%%":self.nsi_file_commands(True),
+ "%%DELETE_FILES%%":self.nsi_file_commands(False)})
+
+ # We use the Unicode version of NSIS, available from
+ # http://www.scratchpaper.com/
+ # Check two paths, one for Program Files, and one for Program Files (x86).
+ # Yay 64bit windows.
+ NSIS_path = os.path.expandvars('${ProgramFiles}\\NSIS\\Unicode\\makensis.exe')
+ if not os.path.exists(NSIS_path):
+ NSIS_path = os.path.expandvars('${ProgramFiles(x86)}\\NSIS\\Unicode\\makensis.exe')
+ self.run_command('"' + proper_windows_path(NSIS_path) + '" ' + self.dst_path_of(tempfile))
+ # self.remove(self.dst_path_of(tempfile))
+ # If we're on a build machine, sign the code using our Authenticode certificate. JC
+ sign_py = os.path.expandvars("${SIGN}")
+ if not sign_py or sign_py == "${SIGN}":
+ sign_py = 'C:\\buildscripts\\code-signing\\sign.py'
+ else:
+ sign_py = sign_py.replace('\\', '\\\\\\\\')
+ python = os.path.expandvars("${PYTHON}")
+ if not python or python == "${PYTHON}":
+ python = 'python'
+ if os.path.exists(sign_py):
+ self.run_command("%s %s %s" % (python, sign_py, self.dst_path_of(installer_file).replace('\\', '\\\\\\\\')))
+ else:
+ print "Skipping code signing,", sign_py, "does not exist"
+ self.created_path(self.dst_path_of(installer_file))
+ self.package_file = installer_file
+
+
+class DarwinManifest(ViewerManifest):
+ def is_packaging_viewer(self):
+ # darwin requires full app bundle packaging even for debugging.
+ return True
+
+ def construct(self):
+ # copy over the build result (this is a no-op if run within the xcode script)
+ self.path(self.args['configuration'] + "/Second Life.app", dst="")
+
+ if self.prefix(src="", dst="Contents"): # everything goes in Contents
+ self.path("Info-SecondLife.plist", dst="Info.plist")
+
+ # copy additional libs in <bundle>/Contents/MacOS/
+ self.path("../../libraries/universal-darwin/lib_release/libndofdev.dylib", dst="MacOS/libndofdev.dylib")
+
+ self.path("../viewer_components/updater/scripts/darwin/update_install", "MacOS/update_install")
+
+ # most everything goes in the Resources directory
+ if self.prefix(src="", dst="Resources"):
+ super(DarwinManifest, self).construct()
+
+ if self.prefix("cursors_mac"):
+ self.path("*.tif")
+ self.end_prefix("cursors_mac")
+
+ self.path("licenses-mac.txt", dst="licenses.txt")
+ self.path("featuretable_mac.txt")
+ self.path("SecondLife.nib")
+
+ # If we are not using the default channel, use the 'Firstlook
+ # icon' to show that it isn't a stable release.
+ if self.default_channel() and self.default_grid():
+ self.path("secondlife.icns")
+ else:
+ self.path("secondlife_firstlook.icns", "secondlife.icns")
+ self.path("SecondLife.nib")
+
+ # Translations
+ self.path("English.lproj")
+ self.path("German.lproj")
+ self.path("Japanese.lproj")
+ self.path("Korean.lproj")
+ self.path("da.lproj")
+ self.path("es.lproj")
+ self.path("fr.lproj")
+ self.path("hu.lproj")
+ self.path("it.lproj")
+ self.path("nl.lproj")
+ self.path("pl.lproj")
+ self.path("pt.lproj")
+ self.path("ru.lproj")
+ self.path("tr.lproj")
+ self.path("uk.lproj")
+ self.path("zh-Hans.lproj")
+
+ # SLVoice and vivox lols
+ self.path("vivox-runtime/universal-darwin/libsndfile.dylib", "libsndfile.dylib")
+ self.path("vivox-runtime/universal-darwin/libvivoxoal.dylib", "libvivoxoal.dylib")
+ self.path("vivox-runtime/universal-darwin/libortp.dylib", "libortp.dylib")
+ self.path("vivox-runtime/universal-darwin/libvivoxsdk.dylib", "libvivoxsdk.dylib")
+ self.path("vivox-runtime/universal-darwin/libvivoxplatform.dylib", "libvivoxplatform.dylib")
+ self.path("vivox-runtime/universal-darwin/SLVoice", "SLVoice")
+
+ libdir = "../../libraries/universal-darwin/lib_release"
+ dylibs = {}
+
+ # Need to get the llcommon dll from any of the build directories as well
+ lib = "llcommon"
+ libfile = "lib%s.dylib" % lib
+ try:
+ self.path(self.find_existing_file(os.path.join(os.pardir,
+ lib,
+ self.args['configuration'],
+ libfile),
+ os.path.join(libdir, libfile)),
+ dst=libfile)
+ except RuntimeError:
+ print "Skipping %s" % libfile
+ dylibs[lib] = False
+ else:
+ dylibs[lib] = True
+
+ if dylibs["llcommon"]:
+ for libfile in ("libapr-1.0.3.7.dylib",
+ "libaprutil-1.0.3.8.dylib",
+ "libexpat.0.5.0.dylib",
+ "libexception_handler.dylib",
+ ):
+ self.path(os.path.join(libdir, libfile), libfile)
+
+ try:
+ # FMOD for sound
+ self.path(self.args['configuration'] + "/libfmodwrapper.dylib", "libfmodwrapper.dylib")
+ except:
+ print "Skipping FMOD - not found"
+
+ # our apps
+ self.path("../mac_crash_logger/" + self.args['configuration'] + "/mac-crash-logger.app", "mac-crash-logger.app")
+ self.path("../mac_updater/" + self.args['configuration'] + "/mac-updater.app", "mac-updater.app")
+
+ # plugin launcher
+ self.path("../llplugin/slplugin/" + self.args['configuration'] + "/SLPlugin.app", "SLPlugin.app")
+
+ # our apps dependencies on shared libs
+ if dylibs["llcommon"]:
+ mac_crash_logger_res_path = self.dst_path_of("mac-crash-logger.app/Contents/Resources")
+ mac_updater_res_path = self.dst_path_of("mac-updater.app/Contents/Resources")
+ slplugin_res_path = self.dst_path_of("SLPlugin.app/Contents/Resources")
+ for libfile in ("libllcommon.dylib",
+ "libapr-1.0.3.7.dylib",
+ "libaprutil-1.0.3.8.dylib",
+ "libexpat.0.5.0.dylib",
+ "libexception_handler.dylib",
+ ):
+ target_lib = os.path.join('../../..', libfile)
+ self.run_command("ln -sf %(target)r %(link)r" %
+ {'target': target_lib,
+ 'link' : os.path.join(mac_crash_logger_res_path, libfile)}
+ )
+ self.run_command("ln -sf %(target)r %(link)r" %
+ {'target': target_lib,
+ 'link' : os.path.join(mac_updater_res_path, libfile)}
+ )
+ self.run_command("ln -sf %(target)r %(link)r" %
+ {'target': target_lib,
+ 'link' : os.path.join(slplugin_res_path, libfile)}
+ )
+
+ # plugins
+ if self.prefix(src="", dst="llplugin"):
+ self.path("../media_plugins/quicktime/" + self.args['configuration'] + "/media_plugin_quicktime.dylib", "media_plugin_quicktime.dylib")
+ self.path("../media_plugins/webkit/" + self.args['configuration'] + "/media_plugin_webkit.dylib", "media_plugin_webkit.dylib")
+ self.path("../../libraries/universal-darwin/lib_release/libllqtwebkit.dylib", "libllqtwebkit.dylib")
+
+ self.end_prefix("llplugin")
+
+ # command line arguments for connecting to the proper grid
+ self.put_in_file(self.flags_list(), 'arguments.txt')
+
+ self.end_prefix("Resources")
+
+ self.end_prefix("Contents")
+
+ # NOTE: the -S argument to strip causes it to keep enough info for
+ # annotated backtraces (i.e. function names in the crash log). 'strip' with no
+ # arguments yields a slightly smaller binary but makes crash logs mostly useless.
+ # This may be desirable for the final release. Or not.
+ if ("package" in self.args['actions'] or
+ "unpacked" in self.args['actions']):
+ self.run_command('strip -S %(viewer_binary)r' %
+ { 'viewer_binary' : self.dst_path_of('Contents/MacOS/Second Life')})
+
+ def copy_finish(self):
+ # Force executable permissions to be set for scripts
+ # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802
+ for script in 'Contents/MacOS/update_install',:
+ self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script))
+
+ def package_finish(self):
+ channel_standin = 'Second Life Viewer 2' # hah, our default channel is not usable on its own
+ if not self.default_channel():
+ channel_standin = self.channel()
+
+ imagename="SecondLife_" + '_'.join(self.args['version'])
+
+ # MBW -- If the mounted volume name changes, it breaks the .DS_Store's background image and icon positioning.
+ # If we really need differently named volumes, we'll need to create multiple DS_Store file images, or use some other trick.
+
+ volname="Second Life Installer" # DO NOT CHANGE without understanding comment above
+
+ if self.default_channel():
+ if not self.default_grid():
+ # beta case
+ imagename = imagename + '_' + self.args['grid'].upper()
+ else:
+ # first look, etc
+ imagename = imagename + '_' + self.channel_oneword().upper()
+
+ sparsename = imagename + ".sparseimage"
+ finalname = imagename + ".dmg"
+ # make sure we don't have stale files laying about
+ self.remove(sparsename, finalname)
+
+ self.run_command('hdiutil create %(sparse)r -volname %(vol)r -fs HFS+ -type SPARSE -megabytes 700 -layout SPUD' % {
+ 'sparse':sparsename,
+ 'vol':volname})
+
+ # mount the image and get the name of the mount point and device node
+ hdi_output = self.run_command('hdiutil attach -private %r' % sparsename)
+ try:
+ devfile = re.search("/dev/disk([0-9]+)[^s]", hdi_output).group(0).strip()
+ volpath = re.search('HFS\s+(.+)', hdi_output).group(1).strip()
+
+ if devfile != '/dev/disk1':
+ # adding more debugging info based upon nat's hunches to the
+ # logs to help track down 'SetFile -a V' failures -brad
+ print "WARNING: 'SetFile -a V' command below is probably gonna fail"
+
+ # Copy everything in to the mounted .dmg
+
+ if self.default_channel() and not self.default_grid():
+ app_name = "Second Life " + self.args['grid']
+ else:
+ app_name = channel_standin.strip()
+
+ # Hack:
+ # Because there is no easy way to coerce the Finder into positioning
+ # the app bundle in the same place with different app names, we are
+ # adding multiple .DS_Store files to svn. There is one for release,
+ # one for release candidate and one for first look. Any other channels
+ # will use the release .DS_Store, and will look broken.
+ # - Ambroff 2008-08-20
+ dmg_template = os.path.join(
+ 'installers',
+ 'darwin',
+ '%s-dmg' % "".join(self.channel_unique().split()).lower())
+
+ if not os.path.exists (self.src_path_of(dmg_template)):
+ dmg_template = os.path.join ('installers', 'darwin', 'release-dmg')
+
+ for s,d in {self.get_dst_prefix():app_name + ".app",
+ os.path.join(dmg_template, "_VolumeIcon.icns"): ".VolumeIcon.icns",
+ os.path.join(dmg_template, "background.jpg"): "background.jpg",
+ os.path.join(dmg_template, "_DS_Store"): ".DS_Store"}.items():
+ print "Copying to dmg", s, d
+ self.copy_action(self.src_path_of(s), os.path.join(volpath, d))
+
+ # Hide the background image, DS_Store file, and volume icon file (set their "visible" bit)
+ for f in ".VolumeIcon.icns", "background.jpg", ".DS_Store":
+ pathname = os.path.join(volpath, f)
+ # We've observed mysterious "no such file" failures of the SetFile
+ # command, especially on the first file listed above -- yet
+ # subsequent inspection of the target directory confirms it's
+ # there. Timing problem with copy command? Try to handle.
+ for x in xrange(3):
+ if os.path.exists(pathname):
+ print "Confirmed existence: %r" % pathname
+ break
+ print "Waiting for %s copy command to complete (%s)..." % (f, x+1)
+ sys.stdout.flush()
+ time.sleep(1)
+ # If we fall out of the loop above without a successful break, oh
+ # well, possibly we've mistaken the nature of the problem. In any
+ # case, don't hang up the whole build looping indefinitely, let
+ # the original problem manifest by executing the desired command.
+ self.run_command('SetFile -a V %r' % pathname)
+
+ # Create the alias file (which is a resource file) from the .r
+ self.run_command('Rez %r -o %r' %
+ (self.src_path_of("installers/darwin/release-dmg/Applications-alias.r"),
+ os.path.join(volpath, "Applications")))
+
+ # Set the alias file's alias and custom icon bits
+ self.run_command('SetFile -a AC %r' % os.path.join(volpath, "Applications"))
+
+ # Set the disk image root's custom icon bit
+ self.run_command('SetFile -a C %r' % volpath)
+ finally:
+ # Unmount the image even if exceptions from any of the above
+ self.run_command('hdiutil detach -force %r' % devfile)
+
+ print "Converting temp disk image to final disk image"
+ self.run_command('hdiutil convert %(sparse)r -format UDZO -imagekey zlib-level=9 -o %(final)r' % {'sparse':sparsename, 'final':finalname})
+ # get rid of the temp file
+ self.package_file = finalname
+ self.remove(sparsename)
+
+class LinuxManifest(ViewerManifest):
+ def construct(self):
+ super(LinuxManifest, self).construct()
+ self.path("licenses-linux.txt","licenses.txt")
+ self.path("res/ll_icon.png","secondlife_icon.png")
+ if self.prefix("linux_tools", dst=""):
+ self.path("client-readme.txt","README-linux.txt")
+ self.path("client-readme-voice.txt","README-linux-voice.txt")
+ self.path("client-readme-joystick.txt","README-linux-joystick.txt")
+ self.path("wrapper.sh","secondlife")
+ self.path("handle_secondlifeprotocol.sh", "etc/handle_secondlifeprotocol.sh")
+ self.path("register_secondlifeprotocol.sh", "etc/register_secondlifeprotocol.sh")
+ self.path("refresh_desktop_app_entry.sh", "etc/refresh_desktop_app_entry.sh")
+ self.path("launch_url.sh","etc/launch_url.sh")
+ self.path("install.sh")
+ self.end_prefix("linux_tools")
+
+ # Create an appropriate gridargs.dat for this package, denoting required grid.
+ self.put_in_file(self.flags_list(), 'etc/gridargs.dat')
+
+ self.path("secondlife-bin","bin/do-not-directly-run-secondlife-bin")
+ self.path("../linux_crash_logger/linux-crash-logger","bin/linux-crash-logger.bin")
+ self.path("../linux_updater/linux-updater", "bin/linux-updater.bin")
+ self.path("../llplugin/slplugin/SLPlugin", "bin/SLPlugin")
+
+ if self.prefix("res-sdl"):
+ self.path("*")
+ # recurse
+ self.end_prefix("res-sdl")
+
+ self.path("../viewer_components/updater/scripts/linux/update_install", "bin/update_install")
+
+ # plugins
+ if self.prefix(src="", dst="bin/llplugin"):
+ self.path("../media_plugins/webkit/libmedia_plugin_webkit.so", "libmedia_plugin_webkit.so")
+ self.path("../media_plugins/gstreamer010/libmedia_plugin_gstreamer010.so", "libmedia_plugin_gstreamer.so")
+ self.end_prefix("bin/llplugin")
+
+ try:
+ self.path("../llcommon/libllcommon.so", "lib/libllcommon.so")
+ except:
+ print "Skipping llcommon.so (assuming llcommon was linked statically)"
+
+ self.path("featuretable_linux.txt")
+
+ def copy_finish(self):
+ # Force executable permissions to be set for scripts
+ # see CHOP-223 and http://mercurial.selenic.com/bts/issue1802
+ for script in 'secondlife', 'bin/update_install':
+ self.run_command("chmod +x %r" % os.path.join(self.get_dst_prefix(), script))
+
+ def package_finish(self):
+ if 'installer_name' in self.args:
+ installer_name = self.args['installer_name']
+ else:
+ installer_name_components = ['SecondLife_', self.args.get('arch')]
+ installer_name_components.extend(self.args['version'])
+ installer_name = "_".join(installer_name_components)
+ if self.default_channel():
+ if not self.default_grid():
+ installer_name += '_' + self.args['grid'].upper()
+ else:
+ installer_name += '_' + self.channel_oneword().upper()
+
+ if self.args['buildtype'].lower() == 'release' and self.is_packaging_viewer():
+ print "* Going strip-crazy on the packaged binaries, since this is a RELEASE build"
+ self.run_command("find %(d)r/bin %(d)r/lib -type f \\! -name update_install | xargs --no-run-if-empty strip -S" % {'d': self.get_dst_prefix()} ) # makes some small assumptions about our packaged dir structure
+
+ # Fix access permissions
+ self.run_command("""
+ find %(dst)s -type d | xargs --no-run-if-empty chmod 755;
+ find %(dst)s -type f -perm 0700 | xargs --no-run-if-empty chmod 0755;
+ find %(dst)s -type f -perm 0500 | xargs --no-run-if-empty chmod 0555;
+ find %(dst)s -type f -perm 0600 | xargs --no-run-if-empty chmod 0644;
+ find %(dst)s -type f -perm 0400 | xargs --no-run-if-empty chmod 0444;
+ true""" % {'dst':self.get_dst_prefix() })
+ self.package_file = installer_name + '.tar.bz2'
+
+ # temporarily move directory tree so that it has the right
+ # name in the tarfile
+ self.run_command("mv %(dst)s %(inst)s" % {
+ 'dst': self.get_dst_prefix(),
+ 'inst': self.build_path_of(installer_name)})
+ try:
+ # only create tarball if it's a release build.
+ if self.args['buildtype'].lower() == 'release':
+ # --numeric-owner hides the username of the builder for
+ # security etc.
+ self.run_command('tar -C %(dir)s --numeric-owner -cjf '
+ '%(inst_path)s.tar.bz2 %(inst_name)s' % {
+ 'dir': self.get_build_prefix(),
+ 'inst_name': installer_name,
+ 'inst_path':self.build_path_of(installer_name)})
+ else:
+ print "Skipping %s.tar.bz2 for non-Release build (%s)" % \
+ (installer_name, self.args['buildtype'])
+ finally:
+ self.run_command("mv %(inst)s %(dst)s" % {
+ 'dst': self.get_dst_prefix(),
+ 'inst': self.build_path_of(installer_name)})
+
+class Linux_i686Manifest(LinuxManifest):
+ def construct(self):
+ super(Linux_i686Manifest, self).construct()
+
+ if self.prefix("../../libraries/i686-linux/lib_release_client", dst="lib"):
+ self.path("libapr-1.so.0")
+ self.path("libaprutil-1.so.0")
+ self.path("libbreakpad_client.so.0.0.0", "libbreakpad_client.so.0")
+ self.path("libdb-4.2.so")
+ self.path("libcrypto.so.0.9.7")
+ self.path("libexpat.so.1")
+ self.path("libssl.so.0.9.7")
+ self.path("libuuid.so.1")
+ self.path("libSDL-1.2.so.0")
+ self.path("libELFIO.so")
+ self.path("libopenjpeg.so.1.3.0", "libopenjpeg.so.1.3")
+ self.path("libalut.so")
+ self.path("libopenal.so", "libopenal.so.1")
+ self.path("libopenal.so", "libvivoxoal.so.1") # vivox's sdk expects this soname
+ try:
+ self.path("libfmod-3.75.so")
+ pass
+ except:
+ print "Skipping libfmod-3.75.so - not found"
+ pass
+ self.end_prefix("lib")
+
+ # Vivox runtimes
+ if self.prefix(src="vivox-runtime/i686-linux", dst="bin"):
+ self.path("SLVoice")
+ self.end_prefix()
+ if self.prefix(src="vivox-runtime/i686-linux", dst="lib"):
+ self.path("libortp.so")
+ self.path("libsndfile.so.1")
+ #self.path("libvivoxoal.so.1") # no - we'll re-use the viewer's own OpenAL lib
+ self.path("libvivoxsdk.so")
+ self.path("libvivoxplatform.so")
+ self.end_prefix("lib")
+
+class Linux_x86_64Manifest(LinuxManifest):
+ def construct(self):
+ super(Linux_x86_64Manifest, self).construct()
+
+ # support file for valgrind debug tool
+ self.path("secondlife-i686.supp")
+
+################################################################
+
+if __name__ == "__main__":
+ main()