diff options
Diffstat (limited to 'indra/newview')
80 files changed, 1541 insertions, 414 deletions
| diff --git a/indra/newview/CMakeLists.txt b/indra/newview/CMakeLists.txt index ed29911a43..fff1597fd9 100644 --- a/indra/newview/CMakeLists.txt +++ b/indra/newview/CMakeLists.txt @@ -92,6 +92,7 @@ set(viewer_SOURCE_FILES      llagentwearables.cpp      llanimstatelabels.cpp      llappcorehttp.cpp +    llappearancelistener.cpp      llappearancemgr.cpp      llappviewer.cpp      llappviewerlistener.cpp @@ -761,6 +762,7 @@ set(viewer_HEADER_FILES      llanimstatelabels.h      llappcorehttp.h      llappearance.h +    llappearancelistener.h      llappearancemgr.h      llappviewer.h      llappviewerlistener.h diff --git a/indra/newview/app_settings/settings.xml b/indra/newview/app_settings/settings.xml index 60ae8ac691..1025c9299d 100644 --- a/indra/newview/app_settings/settings.xml +++ b/indra/newview/app_settings/settings.xml @@ -346,6 +346,17 @@        <key>Value</key>        <real>0.5</real>      </map> +    <key>AudioLevelWind</key> +    <map> +      <key>Comment</key> +      <string>Audio level of wind noise when standing still</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>F32</string> +      <key>Value</key> +      <real>0.5</real> +    </map>  	<key>AudioStreamingMedia</key>      <map>        <key>Comment</key> @@ -9562,6 +9573,17 @@        <key>Value</key>        <integer>0</integer>      </map> +    <key>RenderBalanceInSnapshot</key> +    <map> +      <key>Comment</key> +      <string>Display L$ balance in snapshot</string> +      <key>Persist</key> +      <integer>1</integer> +      <key>Type</key> +      <string>Boolean</string> +      <key>Value</key> +      <integer>1</integer> +    </map>      <key>RenderUIBuffer</key>      <map>        <key>Comment</key> diff --git a/indra/newview/groupchatlistener.cpp b/indra/newview/groupchatlistener.cpp index 43507f13e9..ed9e34d1bf 100644 --- a/indra/newview/groupchatlistener.cpp +++ b/indra/newview/groupchatlistener.cpp @@ -2,11 +2,11 @@   * @file   groupchatlistener.cpp   * @author Nat Goodspeed   * @date   2011-04-11 - * @brief  Implementation for groupchatlistener. + * @brief  Implementation for LLGroupChatListener.   * - * $LicenseInfo:firstyear=2011&license=viewerlgpl$ + * $LicenseInfo:firstyear=2024&license=viewerlgpl$   * Second Life Viewer Source Code - * Copyright (C) 2011, Linden Research, Inc. + * Copyright (C) 2024, 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 @@ -34,43 +34,69 @@  // std headers  // external library headers  // other Linden headers +#include "llchat.h"  #include "llgroupactions.h"  #include "llimview.h" +LLGroupChatListener::LLGroupChatListener(): +    LLEventAPI("GroupChat", +               "API to enter, leave, send and intercept group chat messages") +{ +    add("startGroupChat", +        "Enter a group chat in group with UUID [\"group_id\"]\n" +        "Assumes the logged-in agent is already a member of this group.", +        &LLGroupChatListener::startGroupChat, +        llsd::map("group_id", LLSD())); +    add("leaveGroupChat", +        "Leave a group chat in group with UUID [\"group_id\"]\n" +        "Assumes a prior successful startIM request.", +        &LLGroupChatListener::leaveGroupChat, +        llsd::map("group_id", LLSD())); +    add("sendGroupIM", +        "send a [\"message\"] to group with UUID [\"group_id\"]", +        &LLGroupChatListener::sendGroupIM, +        llsd::map("message", LLSD(), "group_id", LLSD())); +} -namespace { -    void startIm_wrapper(LLSD const & event) +bool is_in_group(LLEventAPI::Response &response, const LLSD &data) +{ +    if (!LLGroupActions::isInGroup(data["group_id"]))      { -        LLUUID session_id = LLGroupActions::startIM(event["id"].asUUID()); -        sendReply(LLSDMap("session_id", LLSD(session_id)), event); +        response.error(stringize("You are not the member of the group:", std::quoted(data["group_id"].asString()))); +        return false;      } +    return true; +} -    void send_message_wrapper(const std::string& text, const LLUUID& session_id, const LLUUID& group_id) +void LLGroupChatListener::startGroupChat(LLSD const &data) +{ +    Response response(LLSD(), data); +    if (!is_in_group(response, data)) +    { +        return; +    } +    if (LLGroupActions::startIM(data["group_id"]).isNull())      { -        LLIMModel::sendMessage(text, session_id, group_id, IM_SESSION_GROUP_START); +        return response.error(stringize("Failed to start group chat session ", std::quoted(data["group_id"].asString())));      }  } +void LLGroupChatListener::leaveGroupChat(LLSD const &data) +{ +    Response response(LLSD(), data); +    if (is_in_group(response, data)) +    { +        LLGroupActions::endIM(data["group_id"].asUUID()); +    } +} -GroupChatListener::GroupChatListener(): -    LLEventAPI("GroupChat", -               "API to enter, leave, send and intercept group chat messages") +void LLGroupChatListener::sendGroupIM(LLSD const &data)  { -    add("startIM", -        "Enter a group chat in group with UUID [\"id\"]\n" -        "Assumes the logged-in agent is already a member of this group.", -        &startIm_wrapper); -    add("endIM", -        "Leave a group chat in group with UUID [\"id\"]\n" -        "Assumes a prior successful startIM request.", -        &LLGroupActions::endIM, -        llsd::array("id")); -    add("sendIM", -        "send a groupchat IM", -        &send_message_wrapper, -        llsd::array("text", "session_id", "group_id")); +    Response response(LLSD(), data); +    if (!is_in_group(response, data)) +    { +        return; +    } +    LLUUID group_id(data["group_id"]); +    LLIMModel::sendMessage(data["message"], gIMMgr->computeSessionID(IM_SESSION_GROUP_START, group_id), group_id, IM_SESSION_SEND);  } -/* -    static void sendMessage(const std::string& utf8_text, const LLUUID& im_session_id, -                                const LLUUID& other_participant_id, EInstantMessage dialog); -*/ diff --git a/indra/newview/groupchatlistener.h b/indra/newview/groupchatlistener.h index 3819ac59b7..14cd7266a3 100644 --- a/indra/newview/groupchatlistener.h +++ b/indra/newview/groupchatlistener.h @@ -26,15 +26,20 @@   * $/LicenseInfo$   */ -#if ! defined(LL_GROUPCHATLISTENER_H) -#define LL_GROUPCHATLISTENER_H +#if ! defined(LL_LLGROUPCHATLISTENER_H) +#define LL_LLGROUPCHATLISTENER_H  #include "lleventapi.h" -class GroupChatListener: public LLEventAPI +class LLGroupChatListener: public LLEventAPI  {  public: -    GroupChatListener(); +    LLGroupChatListener(); + +private: +    void startGroupChat(LLSD const &data); +    void leaveGroupChat(LLSD const &data); +    void sendGroupIM(LLSD const &data);  }; -#endif /* ! defined(LL_GROUPCHATLISTENER_H) */ +#endif /* ! defined(LL_LLGROUPCHATLISTENER_H) */ diff --git a/indra/newview/llagentlistener.cpp b/indra/newview/llagentlistener.cpp index 0c120ae01d..5ddb87558a 100644 --- a/indra/newview/llagentlistener.cpp +++ b/indra/newview/llagentlistener.cpp @@ -31,19 +31,25 @@  #include "llagentlistener.h"  #include "llagent.h" +#include "llagentcamera.h" +#include "llavatarname.h" +#include "llavatarnamecache.h"  #include "llvoavatar.h"  #include "llcommandhandler.h" +#include "llinventorymodel.h"  #include "llslurl.h"  #include "llurldispatcher.h" +#include "llviewercontrol.h"  #include "llviewernetwork.h"  #include "llviewerobject.h"  #include "llviewerobjectlist.h"  #include "llviewerregion.h" +#include "llvoavatarself.h"  #include "llsdutil.h"  #include "llsdutil_math.h"  #include "lltoolgrab.h"  #include "llhudeffectlookat.h" -#include "llagentcamera.h" +#include "llviewercamera.h"  LLAgentListener::LLAgentListener(LLAgent &agent)    : LLEventAPI("LLAgent", @@ -69,13 +75,6 @@ LLAgentListener::LLAgentListener(LLAgent &agent)      add("resetAxes",          "Set the agent to a fixed orientation (optionally specify [\"lookat\"] = array of [x, y, z])",          &LLAgentListener::resetAxes); -    add("getAxes", -        "Obsolete - use getPosition instead\n" -        "Send information about the agent's orientation on [\"reply\"]:\n" -        "[\"euler\"]: map of {roll, pitch, yaw}\n" -        "[\"quat\"]:  array of [x, y, z, w] quaternion values", -        &LLAgentListener::getAxes, -        LLSDMap("reply", LLSD()));      add("getPosition",          "Send information about the agent's position and orientation on [\"reply\"]:\n"          "[\"region\"]: array of region {x, y, z} position\n" @@ -87,33 +86,34 @@ LLAgentListener::LLAgentListener(LLAgent &agent)      add("startAutoPilot",          "Start the autopilot system using the following parameters:\n"          "[\"target_global\"]: array of target global {x, y, z} position\n" -        "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]\n" +        "[\"stop_distance\"]: maximum stop distance from target [default: autopilot guess]\n"          "[\"target_rotation\"]: array of [x, y, z, w] quaternion values [default: no target]\n"          "[\"rotation_threshold\"]: target maximum angle from target facing rotation [default: 0.03 radians]\n" -        "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]" -        "[\"allow_flying\"]: allow flying during autopilot [default: True]", -        //"[\"callback_pump\"]: pump to send success/failure and callback data to [default: none]\n" -        //"[\"callback_data\"]: data to send back during a callback [default: none]", -        &LLAgentListener::startAutoPilot); +        "[\"behavior_name\"]: name of the autopilot behavior [default: \"\"]\n" +        "[\"allow_flying\"]: allow flying during autopilot [default: True]\n" +        "event with [\"success\"] flag is sent to 'LLAutopilot' event pump, when auto pilot is terminated", +        &LLAgentListener::startAutoPilot, +        llsd::map("target_global", LLSD()));      add("getAutoPilot",          "Send information about current state of the autopilot system to [\"reply\"]:\n"          "[\"enabled\"]: boolean indicating whether or not autopilot is enabled\n"          "[\"target_global\"]: array of target global {x, y, z} position\n"          "[\"leader_id\"]: uuid of target autopilot is following\n" -        "[\"stop_distance\"]: target maximum distance from target\n" +        "[\"stop_distance\"]: maximum stop distance from target\n"          "[\"target_distance\"]: last known distance from target\n"          "[\"use_rotation\"]: boolean indicating if autopilot has a target facing rotation\n"          "[\"target_facing\"]: array of {x, y} target direction to face\n"          "[\"rotation_threshold\"]: target maximum angle from target facing rotation\n"          "[\"behavior_name\"]: name of the autopilot behavior",          &LLAgentListener::getAutoPilot, -        LLSDMap("reply", LLSD())); +        llsd::map("reply", LLSD()));      add("startFollowPilot",          "[\"leader_id\"]: uuid of target to follow using the autopilot system (optional with avatar_name)\n"          "[\"avatar_name\"]: avatar name to follow using the autopilot system (optional with leader_id)\n"          "[\"allow_flying\"]: allow flying during autopilot [default: True]\n" -        "[\"stop_distance\"]: target maxiumum distance from target [default: autopilot guess]", -        &LLAgentListener::startFollowPilot); +        "[\"stop_distance\"]: maximum stop distance from target [default: autopilot guess]", +        &LLAgentListener::startFollowPilot, +        llsd::map("reply", LLSD()));      add("setAutoPilotTarget",          "Update target for currently running autopilot:\n"          "[\"target_global\"]: array of target global {x, y, z} position", @@ -138,6 +138,69 @@ LLAgentListener::LLAgentListener(LLAgent &agent)          "[\"contrib\"]: user's land contribution to this group\n",          &LLAgentListener::getGroups,          LLSDMap("reply", LLSD())); +    //camera params are similar to LSL, see https://wiki.secondlife.com/wiki/LlSetCameraParams +    add("setCameraParams", +        "Set Follow camera params, and then activate it:\n" +        "[\"camera_pos\"]: vector3, camera position in region coordinates\n" +        "[\"focus_pos\"]: vector3, what the camera is aimed at (in region coordinates)\n" +        "[\"focus_offset\"]: vector3, adjusts the camera focus position relative to the target, default is (1, 0, 0)\n" +        "[\"distance\"]: float (meters), distance the camera wants to be from its target, default is 3\n" +        "[\"focus_threshold\"]: float (meters), sets the radius of a sphere around the camera's target position within which its focus is not affected by target motion, default is 1\n" +        "[\"camera_threshold\"]: float (meters), sets the radius of a sphere around the camera's ideal position within which it is not affected by target motion, default is 1\n" +        "[\"focus_lag\"]: float (seconds), how much the camera lags as it tries to aim towards the target, default is 0.1\n" +        "[\"camera_lag\"]: float (seconds), how much the camera lags as it tries to move towards its 'ideal' position, default is 0.1\n" +        "[\"camera_pitch\"]: float (degrees), adjusts the angular amount that the camera aims straight ahead vs. straight down, maintaining the same distance, default is 0\n" +        "[\"behindness_angle\"]: float (degrees), sets the angle in degrees within which the camera is not constrained by changes in target rotation, default is 10\n" +        "[\"behindness_lag\"]: float (seconds), sets how strongly the camera is forced to stay behind the target if outside of behindness angle, default is 0\n" +        "[\"camera_locked\"]: bool, locks the camera position so it will not move\n" +        "[\"focus_locked\"]: bool, locks the camera focus so it will not move", +        &LLAgentListener::setFollowCamParams); +    add("setFollowCamActive", +        "Turns on or off scripted control of the camera using boolean [\"active\"]", +        &LLAgentListener::setFollowCamActive, +        llsd::map("active", LLSD())); +    add("removeCameraParams", +        "Reset Follow camera params", +        &LLAgentListener::removeFollowCamParams); + +    add("playAnimation", +        "Play [\"item_id\"] animation locally (by default) or [\"inworld\"] (when set to true)", +        &LLAgentListener::playAnimation, +        llsd::map("item_id", LLSD(), "reply", LLSD())); +    add("stopAnimation", +        "Stop playing [\"item_id\"] animation", +        &LLAgentListener::stopAnimation, +        llsd::map("item_id", LLSD(), "reply", LLSD())); +    add("getAnimationInfo", +        "Return information about [\"item_id\"] animation", +        &LLAgentListener::getAnimationInfo, +        llsd::map("item_id", LLSD(), "reply", LLSD())); + +    add("getID", +        "Return your own avatar ID", +        &LLAgentListener::getID, +        llsd::map("reply", LLSD())); + +    add("getNearbyAvatarsList", +        "Return result set key [\"result\"] for nearby avatars in a range of [\"dist\"]\n" +        "if [\"dist\"] is not specified, 'RenderFarClip' setting is used\n" +        "reply contains \"result\" table with \"id\", \"name\", \"global_pos\", \"region_pos\", \"region_id\" fields", +        &LLAgentListener::getNearbyAvatarsList, +        llsd::map("reply", LLSD())); + +    add("getNearbyObjectsList", +        "Return result set key [\"result\"] for nearby objects in a range of [\"dist\"]\n" +        "if [\"dist\"] is not specified, 'RenderFarClip' setting is used\n" +        "reply contains \"result\" table with \"id\", \"global_pos\", \"region_pos\", \"region_id\" fields", +        &LLAgentListener::getNearbyObjectsList, +        llsd::map("reply", LLSD())); + +    add("getAgentScreenPos", +        "Return screen position of the [\"avatar_id\"] avatar or own avatar if not specified\n" +        "reply contains \"x\", \"y\" coordinates and \"onscreen\" flag to indicate if it's actually in within the current window\n" +        "avatar render position is used as the point", +        &LLAgentListener::getAgentScreenPos, +        llsd::map("reply", LLSD()));  }  void LLAgentListener::requestTeleport(LLSD const & event_data) const @@ -168,7 +231,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const      //mAgent.getAvatarObject()->sitOnObject();      // shamelessly ripped from llviewermenu.cpp:handle_sit_or_stand()      // *TODO - find a permanent place to share this code properly. - +    Response response(LLSD(), event_data);      LLViewerObject *object = NULL;      if (event_data.has("obj_uuid"))      { @@ -177,7 +240,13 @@ void LLAgentListener::requestSit(LLSD const & event_data) const      else if (event_data.has("position"))      {          LLVector3 target_position = ll_vector3_from_sd(event_data["position"]); -        object = findObjectClosestTo(target_position); +        object = findObjectClosestTo(target_position, true); +    } +    else +    { +        //just sit on the ground +        mAgent.setControlFlags(AGENT_CONTROL_SIT_ON_GROUND); +        return;      }      if (object && object->getPCode() == LL_PCODE_VOLUME) @@ -194,8 +263,7 @@ void LLAgentListener::requestSit(LLSD const & event_data) const      }      else      { -        LL_WARNS() << "LLAgent requestSit could not find the sit target: " -            << event_data << LL_ENDL; +        response.error("requestSit could not find the sit target");      }  } @@ -205,7 +273,7 @@ void LLAgentListener::requestStand(LLSD const & event_data) const  } -LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & position ) const +LLViewerObject * LLAgentListener::findObjectClosestTo(const LLVector3 & position, bool sit_target) const  {      LLViewerObject *object = NULL; @@ -216,8 +284,13 @@ LLViewerObject * LLAgentListener::findObjectClosestTo( const LLVector3 & positio      while (cur_index < num_objects)      {          LLViewerObject * cur_object = gObjectList.getObject(cur_index++); -        if (cur_object) -        {   // Calculate distance from the target position +        if (cur_object && !cur_object->isAttachment()) +        { +            if(sit_target && (cur_object->getPCode() != LL_PCODE_VOLUME)) +            { +                continue; +            } +            // Calculate distance from the target position              LLVector3 target_diff = cur_object->getPositionRegion() - position;              F32 distance_to_target = target_diff.length();              if (distance_to_target < min_distance) @@ -296,22 +369,6 @@ void LLAgentListener::resetAxes(const LLSD& event_data) const      }  } -void LLAgentListener::getAxes(const LLSD& event_data) const -{ -    LLQuaternion quat(mAgent.getQuat()); -    F32 roll, pitch, yaw; -    quat.getEulerAngles(&roll, &pitch, &yaw); -    // The official query API for LLQuaternion's [x, y, z, w] values is its -    // public member mQ... -    LLSD reply = LLSD::emptyMap(); -    reply["quat"] = llsd_copy_array(boost::begin(quat.mQ), boost::end(quat.mQ)); -    reply["euler"] = LLSD::emptyMap(); -    reply["euler"]["roll"] = roll; -    reply["euler"]["pitch"] = pitch; -    reply["euler"]["yaw"] = yaw; -    sendReply(reply, event_data); -} -  void LLAgentListener::getPosition(const LLSD& event_data) const  {      F32 roll, pitch, yaw; @@ -333,14 +390,13 @@ void LLAgentListener::getPosition(const LLSD& event_data) const  void LLAgentListener::startAutoPilot(LLSD const & event_data)  { -    LLQuaternion target_rotation_value;      LLQuaternion* target_rotation = NULL;      if (event_data.has("target_rotation"))      { -        target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]); +        LLQuaternion target_rotation_value = ll_quaternion_from_sd(event_data["target_rotation"]);          target_rotation = &target_rotation_value;      } -    // *TODO: Use callback_pump and callback_data +      F32 rotation_threshold = 0.03f;      if (event_data.has("rotation_threshold"))      { @@ -360,13 +416,24 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data)          stop_distance = (F32)event_data["stop_distance"].asReal();      } +    std::string behavior_name = LLCoros::getName(); +    if (event_data.has("behavior_name")) +    { +        behavior_name = event_data["behavior_name"].asString(); +    } +      // Clear follow target, this is doing a path      mFollowTarget.setNull(); +    auto finish_cb = [](bool success, void*) +    { +        LLEventPumps::instance().obtain("LLAutopilot").post(llsd::map("success", success)); +    }; +      mAgent.startAutoPilotGlobal(ll_vector3d_from_sd(event_data["target_global"]), -                                event_data["behavior_name"], +                                behavior_name,                                  target_rotation, -                                NULL, NULL, +                                finish_cb, NULL,                                  stop_distance,                                  rotation_threshold,                                  allow_flying); @@ -374,7 +441,7 @@ void LLAgentListener::startAutoPilot(LLSD const & event_data)  void LLAgentListener::getAutoPilot(const LLSD& event_data) const  { -    LLSD reply = LLSD::emptyMap(); +    Response reply(LLSD(), event_data);      LLSD::Boolean enabled = mAgent.getAutoPilot();      reply["enabled"] = enabled; @@ -403,12 +470,11 @@ void LLAgentListener::getAutoPilot(const LLSD& event_data) const      reply["rotation_threshold"] = mAgent.getAutoPilotRotationThreshold();      reply["behavior_name"] = mAgent.getAutoPilotBehaviorName();      reply["fly"] = (LLSD::Boolean) mAgent.getFlying(); - -    sendReply(reply, event_data);  }  void LLAgentListener::startFollowPilot(LLSD const & event_data)  { +    Response response(LLSD(), event_data);      LLUUID target_id;      bool allow_flying = true; @@ -442,6 +508,10 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data)              }          }      } +    else +    { +        return response.error("'leader_id' or 'avatar_name' should be specified"); +    }      F32 stop_distance = 0.f;      if (event_data.has("stop_distance")) @@ -449,13 +519,16 @@ void LLAgentListener::startFollowPilot(LLSD const & event_data)          stop_distance = (F32)event_data["stop_distance"].asReal();      } -    if (target_id.notNull()) +    if (!gObjectList.findObject(target_id))      { -        mAgent.setFlying(allow_flying); -        mFollowTarget = target_id;  // Save follow target so we can report distance later - -        mAgent.startFollowPilot(target_id, allow_flying, stop_distance); +        std::string target_info = event_data.has("leader_id") ? event_data["leader_id"] : event_data["avatar_name"]; +        return response.error(stringize("Target ", std::quoted(target_info), " was not found"));      } + +    mAgent.setFlying(allow_flying); +    mFollowTarget = target_id;  // Save follow target so we can report distance later + +    mAgent.startFollowPilot(target_id, allow_flying, stop_distance);  }  void LLAgentListener::setAutoPilotTarget(LLSD const & event_data) const @@ -519,3 +592,209 @@ void LLAgentListener::getGroups(const LLSD& event) const      }      sendReply(LLSDMap("groups", reply), event);  } + +/*----------------------------- camera control -----------------------------*/ +// specialize LLSDParam to support (const LLVector3&) arguments -- this +// wouldn't even be necessary except that the relevant LLVector3 constructor +// is explicitly explicit +template <> +class LLSDParam<const LLVector3&>: public LLSDParamBase +{ +public: +    LLSDParam(const LLSD& value): value(LLVector3(value)) {} + +    operator const LLVector3&() const { return value; } + +private: +    LLVector3 value; +}; + +// accept any of a number of similar LLFollowCamMgr methods with different +// argument types, and return a wrapper lambda that accepts LLSD and converts +// to the target argument type +template <typename T> +auto wrap(void (LLFollowCamMgr::*method)(const LLUUID& source, T arg)) +{ +    return [method](LLFollowCamMgr& followcam, const LLUUID& source, const LLSD& arg) +    { (followcam.*method)(source, LLSDParam<T>(arg)); }; +} + +// table of supported LLFollowCamMgr methods, +// with the corresponding setFollowCamParams() argument keys +static std::pair<std::string, std::function<void(LLFollowCamMgr&, const LLUUID&, const LLSD&)>> +cam_params[] = +{ +    { "camera_pos",       wrap(&LLFollowCamMgr::setPosition) }, +    { "focus_pos",        wrap(&LLFollowCamMgr::setFocus) }, +    { "focus_offset",     wrap(&LLFollowCamMgr::setFocusOffset) }, +    { "camera_locked",    wrap(&LLFollowCamMgr::setPositionLocked) }, +    { "focus_locked",     wrap(&LLFollowCamMgr::setFocusLocked) }, +    { "distance",         wrap(&LLFollowCamMgr::setDistance) }, +    { "focus_threshold",  wrap(&LLFollowCamMgr::setFocusThreshold) }, +    { "camera_threshold", wrap(&LLFollowCamMgr::setPositionThreshold) }, +    { "focus_lag",        wrap(&LLFollowCamMgr::setFocusLag) }, +    { "camera_lag",       wrap(&LLFollowCamMgr::setPositionLag) }, +    { "camera_pitch",     wrap(&LLFollowCamMgr::setPitch) }, +    { "behindness_lag",   wrap(&LLFollowCamMgr::setBehindnessLag) }, +    { "behindness_angle", wrap(&LLFollowCamMgr::setBehindnessAngle) }, +}; + +void LLAgentListener::setFollowCamParams(const LLSD& event) const +{ +    auto& followcam{ LLFollowCamMgr::instance() }; +    for (const auto& pair : cam_params) +    { +        if (event.has(pair.first)) +        { +            pair.second(followcam, gAgentID, event[pair.first]); +        } +    } +    followcam.setCameraActive(gAgentID, true); +} + +void LLAgentListener::setFollowCamActive(LLSD const & event) const +{ +    LLFollowCamMgr::getInstance()->setCameraActive(gAgentID, event["active"]); +} + +void LLAgentListener::removeFollowCamParams(LLSD const & event) const +{ +    LLFollowCamMgr::getInstance()->removeFollowCamParams(gAgentID); +} + +LLViewerInventoryItem* get_anim_item(LLEventAPI::Response &response, const LLSD &event_data) +{ +    LLViewerInventoryItem* item = gInventory.getItem(event_data["item_id"].asUUID()); +    if (!item || (item->getInventoryType() != LLInventoryType::IT_ANIMATION)) +    { +        response.error(stringize("Animation item ", std::quoted(event_data["item_id"].asString()), " was not found")); +        return NULL; +    } +    return item; +} + +void LLAgentListener::playAnimation(LLSD const &event_data) +{ +    Response response(LLSD(), event_data); +    if (LLViewerInventoryItem* item = get_anim_item(response, event_data)) +    { +        if (event_data["inworld"].asBoolean()) +        { +            mAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_START); +        } +        else +        { +            gAgentAvatarp->startMotion(item->getAssetUUID()); +        } +    } +} + +void LLAgentListener::stopAnimation(LLSD const &event_data) +{ +    Response response(LLSD(), event_data); +    if (LLViewerInventoryItem* item = get_anim_item(response, event_data)) +    { +        gAgentAvatarp->stopMotion(item->getAssetUUID()); +        mAgent.sendAnimationRequest(item->getAssetUUID(), ANIM_REQUEST_STOP); +    } +} + +void LLAgentListener::getAnimationInfo(LLSD const &event_data) +{ +    Response response(LLSD(), event_data); +    if (LLViewerInventoryItem* item = get_anim_item(response, event_data)) +    { +        // if motion exists, will return existing one +        LLMotion* motion = gAgentAvatarp->createMotion(item->getAssetUUID()); +        response["anim_info"] = llsd::map("duration", motion->getDuration(), +                                               "is_loop", motion->getLoop(), +                                               "num_joints", motion->getNumJointMotions(), +                                               "asset_id", item->getAssetUUID(), +                                               "priority", motion->getPriority()); +    } +} + +void LLAgentListener::getID(LLSD const& event_data) +{ +    Response response(llsd::map("id", gAgentID), event_data); +} + +F32 get_search_radius(LLSD const& event_data) +{ +    static LLCachedControl<F32> render_far_clip(gSavedSettings, "RenderFarClip", 64); +    F32 dist = render_far_clip; +    if (event_data.has("dist")) +    { +        dist = llclamp((F32)event_data["dist"].asReal(), 1, 512); +    } +   return dist * dist; +} + +void LLAgentListener::getNearbyAvatarsList(LLSD const& event_data) +{ +    Response response(LLSD(), event_data); +    F32 radius = get_search_radius(event_data); +    LLVector3d agent_pos = gAgent.getPositionGlobal(); +    for (LLCharacter* character : LLCharacter::sInstances) +    { +        LLVOAvatar* avatar = (LLVOAvatar*)character; +        if (avatar && !avatar->isDead() && !avatar->isControlAvatar() && !avatar->isSelf()) +        { +            if ((dist_vec_squared(avatar->getPositionGlobal(), agent_pos) <= radius)) +            { +                LLAvatarName av_name; +                LLAvatarNameCache::get(avatar->getID(), &av_name); +                LLVector3 region_pos = avatar->getCharacterPosition(); +                response["result"].append(llsd::map("id", avatar->getID(), "global_pos", ll_sd_from_vector3d(avatar->getPosGlobalFromAgent(region_pos)), +                                                    "region_pos", ll_sd_from_vector3(region_pos), "name", av_name.getUserName(), "region_id", avatar->getRegion()->getRegionID())); +            } +        } +    } +} + +void LLAgentListener::getNearbyObjectsList(LLSD const& event_data) +{ +    Response response(LLSD(), event_data); +    F32 radius = get_search_radius(event_data); +    S32 num_objects = gObjectList.getNumObjects(); +    LLVector3d agent_pos = gAgent.getPositionGlobal(); +    for (S32 i = 0; i < num_objects; ++i) +    { +        LLViewerObject* object = gObjectList.getObject(i); +        if (object && object->getVolume() && !object->isAttachment()) +        { +            if ((dist_vec_squared(object->getPositionGlobal(), agent_pos) <= radius)) +            { +                response["result"].append(llsd::map("id", object->getID(), "global_pos", ll_sd_from_vector3d(object->getPositionGlobal()), "region_pos", +                          ll_sd_from_vector3(object->getPositionRegion()), "region_id", object->getRegion()->getRegionID())); +            } +        } +    } +} + +void LLAgentListener::getAgentScreenPos(LLSD const& event_data) +{ +    Response response(LLSD(), event_data); +    LLVector3 render_pos; +    if (event_data.has("avatar_id") && (event_data["avatar_id"].asUUID() != gAgentID)) +    { +        LLUUID avatar_id(event_data["avatar_id"]); +        for (LLCharacter* character : LLCharacter::sInstances) +        { +            LLVOAvatar* avatar = (LLVOAvatar*)character; +            if (!avatar->isDead() && (avatar->getID() == avatar_id)) +            { +                render_pos = avatar->getRenderPosition(); +                break; +            } +        } +    } +    else if (gAgentAvatarp.notNull() && gAgentAvatarp->isValid()) +    { +        render_pos = gAgentAvatarp->getRenderPosition(); +    } +    LLCoordGL screen_pos; +    response["onscreen"] = LLViewerCamera::getInstance()->projectPosAgentToScreen(render_pos, screen_pos, false); +    response["x"] = screen_pos.mX; +    response["y"] = screen_pos.mY; +} diff --git a/indra/newview/llagentlistener.h b/indra/newview/llagentlistener.h index c544d089ce..b5bea8c0bd 100644 --- a/indra/newview/llagentlistener.h +++ b/indra/newview/llagentlistener.h @@ -48,7 +48,6 @@ private:      void requestStand(LLSD const & event_data) const;      void requestTouch(LLSD const & event_data) const;      void resetAxes(const LLSD& event_data) const; -    void getAxes(const LLSD& event_data) const;      void getGroups(const LLSD& event) const;      void getPosition(const LLSD& event_data) const;      void startAutoPilot(const LLSD& event_data); @@ -58,7 +57,20 @@ private:      void stopAutoPilot(const LLSD& event_data) const;      void lookAt(LLSD const & event_data) const; -    LLViewerObject * findObjectClosestTo( const LLVector3 & position ) const; +    void setFollowCamParams(LLSD const & event_data) const; +    void setFollowCamActive(LLSD const & event_data) const; +    void removeFollowCamParams(LLSD const & event_data) const; + +    void playAnimation(LLSD const &event_data); +    void stopAnimation(LLSD const &event_data); +    void getAnimationInfo(LLSD const &event_data); + +    void getID(LLSD const& event_data); +    void getNearbyAvatarsList(LLSD const& event_data); +    void getNearbyObjectsList(LLSD const& event_data); +    void getAgentScreenPos(LLSD const& event_data); + +    LLViewerObject * findObjectClosestTo( const LLVector3 & position, bool sit_target = false ) const;  private:      LLAgent &   mAgent; diff --git a/indra/newview/llappearancelistener.cpp b/indra/newview/llappearancelistener.cpp new file mode 100644 index 0000000000..dc7bbc3236 --- /dev/null +++ b/indra/newview/llappearancelistener.cpp @@ -0,0 +1,158 @@ +/** + * @file llappearancelistener.cpp + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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 "llappearancelistener.h" + +#include "llappearancemgr.h" +#include "llinventoryfunctions.h" +#include "lltransutil.h" +#include "llwearableitemslist.h" +#include "stringize.h" + +LLAppearanceListener::LLAppearanceListener() +  : LLEventAPI("LLAppearance", +               "API to wear a specified outfit and wear/remove individual items") +{ +    add("wearOutfit", +        "Wear outfit by folder id: [\"folder_id\"] OR by folder name: [\"folder_name\"]\n" +        "When [\"append\"] is true, outfit will be added to COF\n" +        "otherwise it will replace current oufit", +        &LLAppearanceListener::wearOutfit); + +    add("wearItems", +        "Wear items by id: [items_id]", +        &LLAppearanceListener::wearItems, +        llsd::map("items_id", LLSD(), "replace", LLSD())); + +    add("detachItems", +        "Detach items by id: [items_id]", +        &LLAppearanceListener::detachItems, +        llsd::map("items_id", LLSD())); + +    add("getOutfitsList", +        "Return the table with Outfits info(id and name)", +         &LLAppearanceListener::getOutfitsList); + +    add("getOutfitItems", +        "Return the table of items with info(id : name, wearable_type, is_worn) inside specified outfit folder", +         &LLAppearanceListener::getOutfitItems); +} + + +void LLAppearanceListener::wearOutfit(LLSD const &data) +{ +    Response response(LLSD(), data); +    if (!data.has("folder_id") && !data.has("folder_name")) +    { +        return response.error("Either [folder_id] or [folder_name] is required"); +    } + +    bool append = data.has("append") ? data["append"].asBoolean() : false; +    if (!LLAppearanceMgr::instance().wearOutfit(data, append)) +    { +        response.error("Failed to wear outfit"); +    } +} + +void LLAppearanceListener::wearItems(LLSD const &data) +{ +    const LLSD& items_id{ data["items_id"] }; +    uuid_vec_t  ids; +    if (!items_id.isArray()) +    { +        ids.push_back(items_id.asUUID()); +    } +    else // array +    { +        for (const auto& id : llsd::inArray(items_id)) +        { +            ids.push_back(id); +        } +    } +    LLAppearanceMgr::instance().wearItemsOnAvatar(ids, true, data["replace"].asBoolean()); +} + +void LLAppearanceListener::detachItems(LLSD const &data) +{ +    const LLSD& items_id{ data["items_id"] }; +    uuid_vec_t  ids; +    if (!items_id.isArray()) +    { +        ids.push_back(items_id.asUUID()); +    } +    else // array +    { +        for (const auto& id : llsd::inArray(items_id)) +        { +            ids.push_back(id); +        } +    } +    LLAppearanceMgr::instance().removeItemsFromAvatar(ids); +} + +void LLAppearanceListener::getOutfitsList(LLSD const &data) +{ +    Response response(LLSD(), data); +    const LLUUID outfits_id = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); + +    LLInventoryModel::cat_array_t cat_array; +    LLInventoryModel::item_array_t item_array; + +    LLIsFolderType is_category(LLFolderType::FT_OUTFIT); +    gInventory.collectDescendentsIf(outfits_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, is_category); + +    response["outfits"] = llsd::toMap(cat_array, +        [](const LLPointer<LLViewerInventoryCategory> &cat) +        { return std::make_pair(cat->getUUID().asString(), cat->getName()); }); +} + +void LLAppearanceListener::getOutfitItems(LLSD const &data) +{ +    Response response(LLSD(), data); +    LLUUID outfit_id(data["outfit_id"].asUUID()); +    LLViewerInventoryCategory *cat = gInventory.getCategory(outfit_id); +    if (!cat || cat->getPreferredType() != LLFolderType::FT_OUTFIT) +    { +        return response.error(stringize("Couldn't find outfit ", outfit_id.asString())); +    } +    LLInventoryModel::cat_array_t  cat_array; +    LLInventoryModel::item_array_t item_array; + +    LLFindOutfitItems collector = LLFindOutfitItems(); +    gInventory.collectDescendentsIf(outfit_id, cat_array, item_array, LLInventoryModel::EXCLUDE_TRASH, collector); + +    response["items"] = llsd::toMap(item_array, +        [](const LLPointer<LLViewerInventoryItem> &it) +        { +            return std::make_pair( +                it->getUUID().asString(), +                llsd::map( +                    "name", it->getName(), +                    "wearable_type", LLWearableType::getInstance()->getTypeName(it->isWearableType() ? it->getWearableType() : LLWearableType::WT_NONE), +                    "is_worn", get_is_item_worn(it))); +        }); +} diff --git a/indra/newview/llappearancelistener.h b/indra/newview/llappearancelistener.h new file mode 100644 index 0000000000..04c5eac2eb --- /dev/null +++ b/indra/newview/llappearancelistener.h @@ -0,0 +1,46 @@ +/** + * @file llappearancelistener.h + * + * $LicenseInfo:firstyear=2024&license=viewerlgpl$ + * Second Life Viewer Source Code + * Copyright (C) 2024, 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_LLAPPEARANCELISTENER_H +#define LL_LLAPPEARANCELISTENER_H + +#include "lleventapi.h" + +class LLAppearanceListener : public LLEventAPI +{ +public: +    LLAppearanceListener(); + +private: +    void wearOutfit(LLSD const &data); +    void wearItems(LLSD const &data); +    void detachItems(LLSD const &data); +    void getOutfitsList(LLSD const &data); +    void getOutfitItems(LLSD const &data); +}; + +#endif // LL_LLAPPEARANCELISTENER_H + diff --git a/indra/newview/llappearancemgr.cpp b/indra/newview/llappearancemgr.cpp index 101aca3823..e9d455ae53 100644 --- a/indra/newview/llappearancemgr.cpp +++ b/indra/newview/llappearancemgr.cpp @@ -31,6 +31,7 @@  #include "llagent.h"  #include "llagentcamera.h"  #include "llagentwearables.h" +#include "llappearancelistener.h"  #include "llappearancemgr.h"  #include "llattachmentsmgr.h"  #include "llcommandhandler.h" @@ -66,6 +67,8 @@  #include "llavatarpropertiesprocessor.h" +LLAppearanceListener sAppearanceListener; +  namespace  {      const S32   BAKE_RETRY_MAX_COUNT = 5; @@ -4762,6 +4765,11 @@ bool wear_category(const LLSD& query_map, bool append)      return false;  } +bool LLAppearanceMgr::wearOutfit(const LLSD& query_map, bool append) +{ +    return wear_category(query_map, append); +} +  class LLWearFolderHandler : public LLCommandHandler  {  public: diff --git a/indra/newview/llappearancemgr.h b/indra/newview/llappearancemgr.h index 6c45a32856..bc7dc9506b 100644 --- a/indra/newview/llappearancemgr.h +++ b/indra/newview/llappearancemgr.h @@ -60,6 +60,7 @@ public:      void wearInventoryCategoryOnAvatar(LLInventoryCategory* category, bool append);      void wearCategoryFinal(const LLUUID& cat_id, bool copy_items, bool append);      void wearOutfitByName(const std::string& name); +    bool wearOutfit(const LLSD& query_map, bool append = false);      void changeOutfit(bool proceed, const LLUUID& category, bool append);      void replaceCurrentOutfit(const LLUUID& new_outfit);      void renameOutfit(const LLUUID& outfit_id); diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp index 7653b5ee8e..edc70030b4 100644 --- a/indra/newview/llappviewer.cpp +++ b/indra/newview/llappviewer.cpp @@ -4540,6 +4540,7 @@ void LLAppViewer::saveFinalSnapshot()                                      false,                                      gSavedSettings.getBOOL("RenderHUDInSnapshot"),                                      true, +                                    false,                                      LLSnapshotModel::SNAPSHOT_TYPE_COLOR,                                      LLSnapshotModel::SNAPSHOT_FORMAT_PNG);          mSavedFinalSnapshot = true; @@ -5254,6 +5255,8 @@ void LLAppViewer::sendLogoutRequest()          msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());          gAgent.sendReliableMessage(); +        LL_INFOS("Agent") << "Logging out as agent: " << gAgent.getID() << " Session: " << gAgent.getSessionID() << LL_ENDL; +          gLogoutTimer.reset();          gLogoutMaxTime = LOGOUT_REQUEST_TIME;          mLogoutRequestSent = true; diff --git a/indra/newview/llappviewerwin32.cpp b/indra/newview/llappviewerwin32.cpp index aaf2a7ea3e..4f5fa53312 100644 --- a/indra/newview/llappviewerwin32.cpp +++ b/indra/newview/llappviewerwin32.cpp @@ -842,69 +842,11 @@ void write_debug_dx(const std::string& str)  bool LLAppViewerWin32::initHardwareTest()  { -    // -    // Do driver verification and initialization based on DirectX -    // hardware polling and driver versions -    // -    if (true == gSavedSettings.getBOOL("ProbeHardwareOnStartup") && false == gSavedSettings.getBOOL("NoHardwareProbe")) -    { -        // per DEV-11631 - disable hardware probing for everything -        // but vram. -        bool vram_only = true; - -        LLSplashScreen::update(LLTrans::getString("StartupDetectingHardware")); - -        LL_DEBUGS("AppInit") << "Attempting to poll DirectX for hardware info" << LL_ENDL; -        gDXHardware.setWriteDebugFunc(write_debug_dx); -        bool probe_ok = gDXHardware.getInfo(vram_only); - -        if (!probe_ok -            && gWarningSettings.getBOOL("AboutDirectX9")) -        { -            LL_WARNS("AppInit") << "DirectX probe failed, alerting user." << LL_ENDL; - -            // Warn them that runnin without DirectX 9 will -            // not allow us to tell them about driver issues -            std::ostringstream msg; -            msg << LLTrans::getString ("MBNoDirectX"); -            S32 button = OSMessageBox( -                msg.str(), -                LLTrans::getString("MBWarning"), -                OSMB_YESNO); -            if (OSBTN_NO== button) -            { -                LL_INFOS("AppInit") << "User quitting after failed DirectX 9 detection" << LL_ENDL; -                LLWeb::loadURLExternal("http://secondlife.com/support/", false); -                return false; -            } -            gWarningSettings.setBOOL("AboutDirectX9", false); -        } -        LL_DEBUGS("AppInit") << "Done polling DirectX for hardware info" << LL_ENDL; - -        // Only probe once after installation -        gSavedSettings.setBOOL("ProbeHardwareOnStartup", false); - -        // Disable so debugger can work -        std::string splash_msg; -        LLStringUtil::format_map_t args; -        args["[APP_NAME]"] = LLAppViewer::instance()->getSecondLifeTitle(); -        splash_msg = LLTrans::getString("StartupLoading", args); - -        LLSplashScreen::update(splash_msg); -    } -      if (!restoreErrorTrap())      { -        LL_WARNS("AppInit") << " Someone took over my exception handler (post hardware probe)!" << LL_ENDL; +        LL_WARNS("AppInit") << " Someone took over my exception handler!" << LL_ENDL;      } -    if (gGLManager.mVRAM == 0) -    { -        gGLManager.mVRAM = gDXHardware.getVRAM(); -    } - -    LL_INFOS("AppInit") << "Detected VRAM: " << gGLManager.mVRAM << LL_ENDL; -      return true;  } diff --git a/indra/newview/lldrawpoolavatar.cpp b/indra/newview/lldrawpoolavatar.cpp index 95f96e85d6..90ee95d424 100644 --- a/indra/newview/lldrawpoolavatar.cpp +++ b/indra/newview/lldrawpoolavatar.cpp @@ -491,7 +491,6 @@ void LLDrawPoolAvatar::beginImpostor()      if (!LLPipeline::sReflectionRender)      { -        LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);          LLVOAvatar::sNumVisibleAvatars = 0;      } @@ -547,7 +546,6 @@ void LLDrawPoolAvatar::beginDeferredImpostor()      if (!LLPipeline::sReflectionRender)      { -        LLVOAvatar::sRenderDistance = llclamp(LLVOAvatar::sRenderDistance, 16.f, 256.f);          LLVOAvatar::sNumVisibleAvatars = 0;      } diff --git a/indra/newview/lldrawpoolterrain.h b/indra/newview/lldrawpoolterrain.h index 5380463d01..23cf253b6a 100644 --- a/indra/newview/lldrawpoolterrain.h +++ b/indra/newview/lldrawpoolterrain.h @@ -38,6 +38,7 @@ public:          VERTEX_DATA_MASK = LLVertexBuffer::MAP_VERTEX |                      LLVertexBuffer::MAP_NORMAL |                      LLVertexBuffer::MAP_TANGENT | // Only PBR terrain uses this currently +                    LLVertexBuffer::MAP_TEXCOORD0 | // Ownership overlay                      LLVertexBuffer::MAP_TEXCOORD1      }; diff --git a/indra/newview/llenvironment.cpp b/indra/newview/llenvironment.cpp index 0017a724ea..875dac103c 100644 --- a/indra/newview/llenvironment.cpp +++ b/indra/newview/llenvironment.cpp @@ -2563,7 +2563,6 @@ void LLEnvironment::setSharedEnvironment()  {      clearEnvironment(LLEnvironment::ENV_LOCAL);      setSelectedEnvironment(LLEnvironment::ENV_LOCAL); -    updateEnvironment();  }  void LLEnvironment::setExperienceEnvironment(LLUUID experience_id, LLUUID asset_id, F32 transition_time) diff --git a/indra/newview/llfloatereditextdaycycle.cpp b/indra/newview/llfloatereditextdaycycle.cpp index 42307dd3f8..0a8b8d321d 100644 --- a/indra/newview/llfloatereditextdaycycle.cpp +++ b/indra/newview/llfloatereditextdaycycle.cpp @@ -495,7 +495,6 @@ void LLFloaterEditExtDayCycle::setEditDayCycle(const LLSettingsDay::ptr_t &pday)      updateEditEnvironment();      LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_EDIT, LLEnvironment::TRANSITION_INSTANT); -    LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT);      synchronizeTabs();      updateTabs();      refresh(); @@ -824,7 +823,6 @@ void LLFloaterEditExtDayCycle::onClearTrack()      updateEditEnvironment();      LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_EDIT, LLEnvironment::TRANSITION_INSTANT); -    LLEnvironment::instance().updateEnvironment(LLEnvironment::TRANSITION_INSTANT);      synchronizeTabs();      updateTabs();      refresh(); diff --git a/indra/newview/llfloaterenvironmentadjust.cpp b/indra/newview/llfloaterenvironmentadjust.cpp index 58616995d3..4825cbf7fb 100644 --- a/indra/newview/llfloaterenvironmentadjust.cpp +++ b/indra/newview/llfloaterenvironmentadjust.cpp @@ -242,9 +242,7 @@ void LLFloaterEnvironmentAdjust::captureCurrentEnvironment()          environment.setEnvironment(LLEnvironment::ENV_LOCAL, mLiveSky, FLOATER_ENVIRONMENT_UPDATE);          environment.setEnvironment(LLEnvironment::ENV_LOCAL, mLiveWater, FLOATER_ENVIRONMENT_UPDATE);      } -    environment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL); -    environment.updateEnvironment(LLEnvironment::TRANSITION_INSTANT); - +    environment.setSelectedEnvironment(LLEnvironment::ENV_LOCAL, LLEnvironment::TRANSITION_INSTANT);  }  void LLFloaterEnvironmentAdjust::onButtonReset() @@ -258,7 +256,6 @@ void LLFloaterEnvironmentAdjust::onButtonReset()              this->closeFloater();              LLEnvironment::instance().clearEnvironment(LLEnvironment::ENV_LOCAL);              LLEnvironment::instance().setSelectedEnvironment(LLEnvironment::ENV_LOCAL); -            LLEnvironment::instance().updateEnvironment();          }      }); diff --git a/indra/newview/llfloaterimnearbychat.cpp b/indra/newview/llfloaterimnearbychat.cpp index 28c651f0cd..db6f9ac22a 100644 --- a/indra/newview/llfloaterimnearbychat.cpp +++ b/indra/newview/llfloaterimnearbychat.cpp @@ -52,6 +52,7 @@  #include "llfirstuse.h"  #include "llfloaterimnearbychat.h" +#include "llfloaterimnearbychatlistener.h"  #include "llagent.h" // gAgent  #include "llgesturemgr.h"  #include "llmultigesture.h" @@ -71,6 +72,8 @@  S32 LLFloaterIMNearbyChat::sLastSpecialChatChannel = 0; +static LLFloaterIMNearbyChatListener sChatListener; +  constexpr S32 EXPANDED_HEIGHT = 266;  constexpr S32 COLLAPSED_HEIGHT = 60;  constexpr S32 EXPANDED_MIN_HEIGHT = 150; diff --git a/indra/newview/llfloaterimnearbychatlistener.cpp b/indra/newview/llfloaterimnearbychatlistener.cpp index 43173d3680..b15a32ce40 100644 --- a/indra/newview/llfloaterimnearbychatlistener.cpp +++ b/indra/newview/llfloaterimnearbychatlistener.cpp @@ -34,12 +34,12 @@  #include "llagent.h"  #include "llchat.h"  #include "llviewercontrol.h" +#include "stringize.h" +static const F32 CHAT_THROTTLE_PERIOD = 1.f; -LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar) -  : LLEventAPI("LLChatBar", -               "LLChatBar listener to (e.g.) sendChat, etc."), -    mChatbar(chatbar) +LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener() : +    LLEventAPI("LLChatBar", "LLChatBar listener to (e.g.) sendChat, etc.")  {      add("sendChat",          "Send chat to the simulator:\n" @@ -49,10 +49,18 @@ LLFloaterIMNearbyChatListener::LLFloaterIMNearbyChatListener(LLFloaterIMNearbyCh          &LLFloaterIMNearbyChatListener::sendChat);  } -  // "sendChat" command -void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const +void LLFloaterIMNearbyChatListener::sendChat(LLSD const& chat_data)  { +    F64 cur_time = LLTimer::getElapsedSeconds(); + +    if (cur_time < mLastThrottleTime + CHAT_THROTTLE_PERIOD) +    { +        LL_WARNS("LLFloaterIMNearbyChatListener") << "'sendChat' was  throttled" << LL_ENDL; +        return; +    } +    mLastThrottleTime = cur_time; +      // Extract the data      std::string chat_text = chat_data["message"].asString(); @@ -81,20 +89,12 @@ void LLFloaterIMNearbyChatListener::sendChat(LLSD const & chat_data) const      }      // Have to prepend /42 style channel numbers -    std::string chat_to_send; -    if (channel == 0) -    { -        chat_to_send = chat_text; -    } -    else +    if (channel)      { -        chat_to_send += "/"; -        chat_to_send += chat_data["channel"].asString(); -        chat_to_send += " "; -        chat_to_send += chat_text; +        chat_text = stringize("/", chat_data["channel"].asString(), " ", chat_text);      }      // Send it as if it was typed in -    mChatbar.sendChatFromViewer(chat_to_send, type_o_chat, ((bool)(channel == 0)) && gSavedSettings.getBOOL("PlayChatAnim")); +    LLFloaterIMNearbyChat::sendChatFromViewer(chat_text, type_o_chat, (channel == 0) && gSavedSettings.getBOOL("PlayChatAnim"));  } diff --git a/indra/newview/llfloaterimnearbychatlistener.h b/indra/newview/llfloaterimnearbychatlistener.h index 96184d95b3..71eba53a9a 100644 --- a/indra/newview/llfloaterimnearbychatlistener.h +++ b/indra/newview/llfloaterimnearbychatlistener.h @@ -38,12 +38,12 @@ class LLFloaterIMNearbyChat;  class LLFloaterIMNearbyChatListener : public LLEventAPI  {  public: -    LLFloaterIMNearbyChatListener(LLFloaterIMNearbyChat & chatbar); +    LLFloaterIMNearbyChatListener();  private: -    void sendChat(LLSD const & chat_data) const; +    void sendChat(LLSD const & chat_data); -    LLFloaterIMNearbyChat & mChatbar; +    F64 mLastThrottleTime{0};  };  #endif // LL_LLFLOATERIMNEARBYCHATLISTENER_H diff --git a/indra/newview/llfloaterimsessiontab.cpp b/indra/newview/llfloaterimsessiontab.cpp index 655674357f..50e765c236 100644 --- a/indra/newview/llfloaterimsessiontab.cpp +++ b/indra/newview/llfloaterimsessiontab.cpp @@ -39,6 +39,7 @@  #include "llchicletbar.h"  #include "lldraghandle.h"  #include "llemojidictionary.h" +#include "llemojihelper.h"  #include "llfloaterreg.h"  #include "llfloateremojipicker.h"  #include "llfloaterimsession.h" @@ -300,6 +301,8 @@ bool LLFloaterIMSessionTab::postBuild()      mEmojiPickerShowBtn = getChild<LLButton>("emoji_picker_show_btn");      mEmojiPickerShowBtn->setClickedCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerShowBtnClicked(); }); +    mEmojiPickerShowBtn->setMouseDownCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerShowBtnDown(); }); +    mEmojiCloseConn = LLEmojiHelper::instance().setCloseCallback([this](LLUICtrl*, const LLSD&) { onEmojiPickerClosed(); });      mGearBtn = getChild<LLButton>("gear_btn");      mAddBtn = getChild<LLButton>("add_btn"); @@ -532,8 +535,43 @@ void LLFloaterIMSessionTab::onEmojiRecentPanelToggleBtnClicked()  void LLFloaterIMSessionTab::onEmojiPickerShowBtnClicked()  { -    mInputEditor->setFocus(true); -    mInputEditor->showEmojiHelper(); +    if (!mEmojiPickerShowBtn->getToggleState()) +    { +        mInputEditor->hideEmojiHelper(); +        mInputEditor->setFocus(true); +        mInputEditor->showEmojiHelper(); +        mEmojiPickerShowBtn->setToggleState(true); // in case hideEmojiHelper closed a visible instance +    } +    else +    { +        mInputEditor->hideEmojiHelper(); +        mEmojiPickerShowBtn->setToggleState(false); +    } +} + +void LLFloaterIMSessionTab::onEmojiPickerShowBtnDown() +{ +    if (mEmojiHelperLastCallbackFrame == LLFrameTimer::getFrameCount()) +    { +        // Helper gets closed by focus lost event on Down before before onEmojiPickerShowBtnDown +        // triggers. +        // If this condition is true, user pressed button and it was 'toggled' during press, +        // restore 'toggled' state so that button will not reopen helper. +        mEmojiPickerShowBtn->setToggleState(true); +    } +} + +void LLFloaterIMSessionTab::onEmojiPickerClosed() +{ +    if (mEmojiPickerShowBtn->getToggleState()) +    { +        mEmojiPickerShowBtn->setToggleState(false); +        // Helper gets closed by focus lost event on Down before onEmojiPickerShowBtnDown +        // triggers. If mEmojiHelperLastCallbackFrame is set and matches Down, means close +        // was triggered by user's press. +        // A bit hacky, but I can't think of a better way to handle this without rewriting helper. +        mEmojiHelperLastCallbackFrame = LLFrameTimer::getFrameCount(); +    }  }  void LLFloaterIMSessionTab::initEmojiRecentPanel() diff --git a/indra/newview/llfloaterimsessiontab.h b/indra/newview/llfloaterimsessiontab.h index 367d988f26..6d04d622e1 100644 --- a/indra/newview/llfloaterimsessiontab.h +++ b/indra/newview/llfloaterimsessiontab.h @@ -235,6 +235,8 @@ private:      void onEmojiRecentPanelToggleBtnClicked();      void onEmojiPickerShowBtnClicked(); +    void onEmojiPickerShowBtnDown(); +    void onEmojiPickerClosed();      void initEmojiRecentPanel();      void onEmojiRecentPanelFocusReceived();      void onEmojiRecentPanelFocusLost(); @@ -249,6 +251,9 @@ private:      S32 mInputEditorPad;      S32 mChatLayoutPanelHeight;      S32 mFloaterHeight; + +    boost::signals2::connection mEmojiCloseConn; +    U32 mEmojiHelperLastCallbackFrame = { 0 };  }; diff --git a/indra/newview/llfloatersnapshot.cpp b/indra/newview/llfloatersnapshot.cpp index 68b9e758a1..faf7ed0d8c 100644 --- a/indra/newview/llfloatersnapshot.cpp +++ b/indra/newview/llfloatersnapshot.cpp @@ -60,12 +60,13 @@ LLPanelSnapshot* LLFloaterSnapshot::Impl::getActivePanel(LLFloaterSnapshotBase*  {      LLSideTrayPanelContainer* panel_container = floater->getChild<LLSideTrayPanelContainer>("panel_container");      LLPanelSnapshot* active_panel = dynamic_cast<LLPanelSnapshot*>(panel_container->getCurrentPanel()); -    if (!active_panel) -    { -        LL_WARNS() << "No snapshot active panel, current panel index: " << panel_container->getCurrentPanelIndex() << LL_ENDL; -    } +      if (!ok_if_not_found)      { +        if (!active_panel) +        { +            LL_WARNS() << "No snapshot active panel, current panel index: " << panel_container->getCurrentPanelIndex() << LL_ENDL; +        }          llassert_always(active_panel != NULL);      }      return active_panel; @@ -516,34 +517,13 @@ void LLFloaterSnapshotBase::ImplBase::onClickFilter(LLUICtrl *ctrl, void* data)  }  // static -void LLFloaterSnapshotBase::ImplBase::onClickUICheck(LLUICtrl *ctrl, void* data) +void LLFloaterSnapshotBase::ImplBase::onClickDisplaySetting(LLUICtrl* ctrl, void* data)  { -    LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl; -    gSavedSettings.setBOOL( "RenderUIInSnapshot", check->get() ); - -    LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; +    LLFloaterSnapshot* view = (LLFloaterSnapshot*)data;      if (view)      {          LLSnapshotLivePreview* previewp = view->getPreviewView(); -        if(previewp) -        { -            previewp->updateSnapshot(true, true); -        } -        view->impl->updateControls(view); -    } -} - -// static -void LLFloaterSnapshotBase::ImplBase::onClickHUDCheck(LLUICtrl *ctrl, void* data) -{ -    LLCheckBoxCtrl *check = (LLCheckBoxCtrl *)ctrl; -    gSavedSettings.setBOOL( "RenderHUDInSnapshot", check->get() ); - -    LLFloaterSnapshot *view = (LLFloaterSnapshot *)data; -    if (view) -    { -        LLSnapshotLivePreview* previewp = view->getPreviewView(); -        if(previewp) +        if (previewp)          {              previewp->updateSnapshot(true, true);          } @@ -1002,11 +982,9 @@ bool LLFloaterSnapshot::postBuild()      mSucceessLblPanel = getChild<LLUICtrl>("succeeded_panel");      mFailureLblPanel = getChild<LLUICtrl>("failed_panel"); -    childSetCommitCallback("ui_check", ImplBase::onClickUICheck, this); -    getChild<LLUICtrl>("ui_check")->setValue(gSavedSettings.getBOOL("RenderUIInSnapshot")); - -    childSetCommitCallback("hud_check", ImplBase::onClickHUDCheck, this); -    getChild<LLUICtrl>("hud_check")->setValue(gSavedSettings.getBOOL("RenderHUDInSnapshot")); +    childSetCommitCallback("ui_check", ImplBase::onClickDisplaySetting, this); +    childSetCommitCallback("balance_check", ImplBase::onClickDisplaySetting, this); +    childSetCommitCallback("hud_check", ImplBase::onClickDisplaySetting, this);      ((Impl*)impl)->setAspectRatioCheckboxValue(this, gSavedSettings.getBOOL("KeepAspectForSnapshot")); diff --git a/indra/newview/llfloatersnapshot.h b/indra/newview/llfloatersnapshot.h index 6df851b839..186d9c41cf 100644 --- a/indra/newview/llfloatersnapshot.h +++ b/indra/newview/llfloatersnapshot.h @@ -103,8 +103,7 @@ public:      static void onClickAutoSnap(LLUICtrl *ctrl, void* data);      static void onClickNoPost(LLUICtrl *ctrl, void* data);      static void onClickFilter(LLUICtrl *ctrl, void* data); -    static void onClickUICheck(LLUICtrl *ctrl, void* data); -    static void onClickHUDCheck(LLUICtrl *ctrl, void* data); +    static void onClickDisplaySetting(LLUICtrl *ctrl, void* data);      static void onCommitFreezeFrame(LLUICtrl* ctrl, void* data);      virtual LLPanelSnapshot* getActivePanel(LLFloaterSnapshotBase* floater, bool ok_if_not_found = true) = 0; diff --git a/indra/newview/llgroupactions.cpp b/indra/newview/llgroupactions.cpp index ba9c9fa13f..34d96aa024 100644 --- a/indra/newview/llgroupactions.cpp +++ b/indra/newview/llgroupactions.cpp @@ -46,7 +46,7 @@  //  // Globals  // -static GroupChatListener sGroupChatListener; +static LLGroupChatListener sGroupChatListener;  class LLGroupHandler : public LLCommandHandler  { diff --git a/indra/newview/llinventorybridge.cpp b/indra/newview/llinventorybridge.cpp index ce91f9a1f3..4018a89c5a 100644 --- a/indra/newview/llinventorybridge.cpp +++ b/indra/newview/llinventorybridge.cpp @@ -104,7 +104,6 @@ static bool check_item(const LLUUID& item_id,                         LLInventoryFilter* filter);  // Helper functions -  bool isAddAction(const std::string& action)  {      return ("wear" == action || "attach" == action || "activate" == action); @@ -2697,7 +2696,12 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,          U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit");          if (is_movable && move_is_into_outfit)          { -            if (mUUID == my_outifts_id) +            if ((inv_cat->getPreferredType() != LLFolderType::FT_NONE) && (inv_cat->getPreferredType() != LLFolderType::FT_OUTFIT)) +            { +                tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); +                is_movable = false; +            } +            else if (mUUID == my_outifts_id)              {                  if (source != LLToolDragAndDrop::SOURCE_AGENT || move_is_from_marketplacelistings)                  { @@ -2714,13 +2718,39 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,                      is_movable = false;                  }              } -            else if(getCategory() && getCategory()->getPreferredType() == LLFolderType::FT_NONE) +            else if (!getCategory())              { -                is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT)); +                is_movable = false; +                tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit");              }              else              { -                is_movable = false; +                EMyOutfitsSubfolderType dest_res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id); +                EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); +                if ((dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT) && inv_res == MY_OUTFITS_OUTFIT) +                { +                    is_movable = false; +                    tooltip_msg = LLTrans::getString("TooltipCantMoveOutfitIntoOutfit"); +                } +                else if (dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT) +                { +                    is_movable = false; +                    tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); +                } +                else if (dest_res == MY_OUTFITS_SUBFOLDER && inv_res == MY_OUTFITS_SUBOUTFIT) +                { +                    is_movable = false; +                    tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); +                } +                else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) +                { +                    is_movable = true; +                } +                else +                { +                    is_movable = false; +                    tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); +                }              }          }          if (is_movable && move_is_into_current_outfit && is_link) @@ -2912,9 +2942,77 @@ bool LLFolderBridge::dragCategoryIntoFolder(LLInventoryCategory* inv_cat,              if (mUUID == my_outifts_id)              { -                // Category can contains objects, -                // create a new folder and populate it with links to original objects -                dropToMyOutfits(inv_cat, cb); +                EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); +                if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT) +                { +                    LLInvFVBridge::changeCategoryParent( +                        model, +                        (LLViewerInventoryCategory*)inv_cat, +                        mUUID, +                        false); +                    if (cb) cb->fire(inv_cat->getUUID()); +                } +                else +                { +                    // Moving from inventory +                    // create a new folder and populate it with links to original objects +                    dropToMyOutfits(inv_cat, cb); +                } +            } +            else if (move_is_into_my_outfits) +            { +                EMyOutfitsSubfolderType dest_res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id); +                EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); +                switch (inv_res) +                { +                case MY_OUTFITS_NO: +                    // Moning from outside outfits into outfits +                    if (dest_res == MY_OUTFITS_SUBFOLDER) +                    { +                        // turn it into outfit +                        dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_OUTFIT, cb); +                    } +                    else +                    { +                        // or link it? +                        dropToMyOutfitsSubfolder(inv_cat, mUUID, LLFolderType::FT_NONE, cb); +                    } +                    break; +                case MY_OUTFITS_SUBFOLDER: +                case MY_OUTFITS_OUTFIT: +                    // only permit moving subfodlers and outfits into other subfolders +                    if (dest_res == MY_OUTFITS_SUBFOLDER) +                    { +                        LLInvFVBridge::changeCategoryParent( +                            model, +                            (LLViewerInventoryCategory*)inv_cat, +                            mUUID, +                            false); +                        if (cb) cb->fire(inv_cat->getUUID()); +                    } +                    else +                    { +                        assert(false); // mot permitted, shouldn't have accepted +                    } +                    break; +                case MY_OUTFITS_SUBOUTFIT: +                    if (dest_res == MY_OUTFITS_SUBOUTFIT || dest_res == MY_OUTFITS_OUTFIT) +                    { +                        LLInvFVBridge::changeCategoryParent( +                            model, +                            (LLViewerInventoryCategory*)inv_cat, +                            mUUID, +                            false); +                        if (cb) cb->fire(inv_cat->getUUID()); +                    } +                    else +                    { +                        assert(false); // mot permitted, shouldn't have accepted +                    } +                    break; +                default: +                    break; +                }              }              // if target is current outfit folder we use link              else if (move_is_into_current_outfit && @@ -4008,6 +4106,7 @@ void LLFolderBridge::perform_pasteFromClipboard()                  {                      if (!move_is_into_my_outfits && item && can_move_to_outfit(item, move_is_into_current_outfit))                      { +                        // todo: this is going to create dupplicate folders?                          dropToOutfit(item, move_is_into_current_outfit, cb);                      }                      else if (move_is_into_my_outfits && LLAssetType::AT_CATEGORY == obj->getType()) @@ -4016,7 +4115,23 @@ void LLFolderBridge::perform_pasteFromClipboard()                          U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit");                          if (cat && can_move_to_my_outfits(model, cat, max_items_to_wear))                          { -                            dropToMyOutfits(cat, cb); +                            if (mUUID == my_outifts_id) +                            { +                                dropToMyOutfits(cat, cb); +                            } +                            else if (move_is_into_my_outfits) +                            { +                                EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id); +                                if (res == MY_OUTFITS_SUBFOLDER) +                                { +                                    // turn it into outfit +                                    dropToMyOutfitsSubfolder(cat, mUUID, LLFolderType::FT_OUTFIT, cb); +                                } +                                else +                                { +                                    dropToMyOutfitsSubfolder(cat, mUUID, LLFolderType::FT_NONE, cb); +                                } +                            }                          }                          else                          { @@ -4256,6 +4371,7 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items      if (outfits_id == mUUID)      { +        items.push_back(std::string("New Outfit Folder"));          items.push_back(std::string("New Outfit"));      } @@ -4349,63 +4465,83 @@ void LLFolderBridge::buildContextMenuOptions(U32 flags, menuentry_vec_t&   items      else if(isAgentInventory()) // do not allow creating in library      {          LLViewerInventoryCategory *cat = getCategory(); -        // BAP removed protected check to re-enable standard ops in untyped folders. -        // Not sure what the right thing is to do here. -        if (!isCOFFolder() && cat && (cat->getPreferredType() != LLFolderType::FT_OUTFIT)) -        { -            if (!isInboxFolder() // don't allow creation in inbox -                && outfits_id != mUUID) -            { -                bool menu_items_added = false; -                // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. -                if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) -                { -                    items.push_back(std::string("New Folder")); -                    menu_items_added = true; -                } -                if (!isMarketplaceListingsFolder()) -                { -                    items.push_back(std::string("upload_def")); -                    items.push_back(std::string("create_new")); -                    items.push_back(std::string("New Script")); -                    items.push_back(std::string("New Note")); -                    items.push_back(std::string("New Gesture")); -                    items.push_back(std::string("New Material")); -                    items.push_back(std::string("New Clothes")); -                    items.push_back(std::string("New Body Parts")); -                    items.push_back(std::string("New Settings")); -                    if (!LLEnvironment::instance().isInventoryEnabled()) -                    { -                        disabled_items.push_back("New Settings"); -                    } -                } -                else -                { -                    items.push_back(std::string("New Listing Folder")); -                } -                if (menu_items_added) -                { -                    items.push_back(std::string("Create Separator")); -                } -            } -            getClipboardEntries(false, items, disabled_items, flags); -        } -        else + +        if (cat)          { -            // Want some but not all of the items from getClipboardEntries for outfits. -            if (cat && (cat->getPreferredType() == LLFolderType::FT_OUTFIT)) +            if (cat->getPreferredType() == LLFolderType::FT_OUTFIT)              { +                // Want some but not all of the items from getClipboardEntries for outfits.                  items.push_back(std::string("Rename"));                  items.push_back(std::string("thumbnail"));                  addDeleteContextMenuOptions(items, disabled_items);                  // EXT-4030: disallow deletion of currently worn outfit -                const LLViewerInventoryItem *base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink(); +                const LLViewerInventoryItem* base_outfit_link = LLAppearanceMgr::instance().getBaseOutfitLink();                  if (base_outfit_link && (cat == base_outfit_link->getLinkedCategory()))                  {                      disabled_items.push_back(std::string("Delete"));                  }              } +            else if (outfits_id == mUUID) +            { +                getClipboardEntries(false, items, disabled_items, flags); +            } +            else if (!isCOFFolder()) +            { +                EMyOutfitsSubfolderType in_my_outfits = myoutfit_object_subfolder_type(model, mUUID, outfits_id); +                if (in_my_outfits != MY_OUTFITS_NO) +                { +                    if (in_my_outfits == MY_OUTFITS_SUBFOLDER) +                    { +                        // Not inside an outfit, but inside 'my outfits' +                        items.push_back(std::string("New Outfit")); +                        items.push_back(std::string("New Outfit Folder")); +                    } +                    items.push_back(std::string("Rename")); +                    items.push_back(std::string("thumbnail")); + +                    addDeleteContextMenuOptions(items, disabled_items); +                } +                else +                { +                    if (!isInboxFolder() // don't allow creation in inbox +                        && outfits_id != mUUID) +                    { +                        bool menu_items_added = false; +                        // Do not allow to create 2-level subfolder in the Calling Card/Friends folder. EXT-694. +                        if (!LLFriendCardsManager::instance().isCategoryInFriendFolder(cat)) +                        { +                            items.push_back(std::string("New Folder")); +                            menu_items_added = true; +                        } +                        if (!isMarketplaceListingsFolder()) +                        { +                            items.push_back(std::string("upload_def")); +                            items.push_back(std::string("create_new")); +                            items.push_back(std::string("New Script")); +                            items.push_back(std::string("New Note")); +                            items.push_back(std::string("New Gesture")); +                            items.push_back(std::string("New Material")); +                            items.push_back(std::string("New Clothes")); +                            items.push_back(std::string("New Body Parts")); +                            items.push_back(std::string("New Settings")); +                            if (!LLEnvironment::instance().isInventoryEnabled()) +                            { +                                disabled_items.push_back("New Settings"); +                            } +                        } +                        else +                        { +                            items.push_back(std::string("New Listing Folder")); +                        } +                        if (menu_items_added) +                        { +                            items.push_back(std::string("Create Separator")); +                        } +                    } +                    getClipboardEntries(false, items, disabled_items, flags); +                } +            }          }          if (model->findCategoryUUIDForType(LLFolderType::FT_CURRENT_OUTFIT) == mUUID) @@ -4558,7 +4694,11 @@ void LLFolderBridge::buildContextMenuFolderOptions(U32 flags,   menuentry_vec_t&          if (((flags & ITEM_IN_MULTI_SELECTION) == 0) && hasChildren() && (type != LLFolderType::FT_OUTFIT))          { -            items.push_back(std::string("Ungroup folder items")); +            const LLUUID my_outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); +            if (!gInventory.isObjectDescendentOf(mUUID, my_outfits)) +            { +                items.push_back(std::string("Ungroup folder items")); +            }          }      }      else @@ -5331,13 +5471,24 @@ void LLFolderBridge::dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLI      // Note: creation will take time, so passing folder id to callback is slightly unreliable,      // but so is collecting and passing descendants' ids      inventory_func_type func = boost::bind(outfitFolderCreatedCallback, inv_cat->getUUID(), _1, cb, mInventoryPanel); -    gInventory.createNewCategory(dest_id, +    getInventoryModel()->createNewCategory(dest_id,                                   LLFolderType::FT_OUTFIT,                                   inv_cat->getName(),                                   func,                                   inv_cat->getThumbnailUUID());  } +void LLFolderBridge::dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLFolderType::EType preferred_type, LLPointer<LLInventoryCallback> cb) +{ +    const LLUUID outfits_id = getInventoryModel()->findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); +    inventory_func_type func = boost::bind(outfitFolderCreatedCallback, inv_cat->getUUID(), _1, cb, mInventoryPanel); +    getInventoryModel()->createNewCategory(dest_id, +        preferred_type, +        inv_cat->getName(), +        func, +        inv_cat->getThumbnailUUID()); +} +  void LLFolderBridge::outfitFolderCreatedCallback(LLUUID cat_source_id,                                                   LLUUID cat_dest_id,                                                   LLPointer<LLInventoryCallback> cb, @@ -5511,7 +5662,9 @@ bool LLFolderBridge::dragItemIntoFolder(LLInventoryItem* inv_item,          }          else if (user_confirm && (move_is_into_current_outfit || move_is_into_outfit))          { -            accept = can_move_to_outfit(inv_item, move_is_into_current_outfit); +            EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(model, mUUID, my_outifts_id); +            // don't allow items in my outfits' subfodlers, only in outfits and outfit's subfolders +            accept = res != MY_OUTFITS_SUBFOLDER && can_move_to_outfit(inv_item, move_is_into_current_outfit);          }          else if (user_confirm && (move_is_into_favorites || move_is_into_landmarks))          { diff --git a/indra/newview/llinventorybridge.h b/indra/newview/llinventorybridge.h index 3e7f74384b..a101c7368a 100644 --- a/indra/newview/llinventorybridge.h +++ b/indra/newview/llinventorybridge.h @@ -369,6 +369,7 @@ protected:      void dropToFavorites(LLInventoryItem* inv_item, LLPointer<LLInventoryCallback> cb = NULL);      void dropToOutfit(LLInventoryItem* inv_item, bool move_is_into_current_outfit, LLPointer<LLInventoryCallback> cb = NULL);      void dropToMyOutfits(LLInventoryCategory* inv_cat, LLPointer<LLInventoryCallback> cb = NULL); +    void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest, LLFolderType::EType preferred_type, LLPointer<LLInventoryCallback> cb = NULL);      //--------------------------------------------------------------------      // Messy hacks for handling folder options diff --git a/indra/newview/llinventoryfunctions.cpp b/indra/newview/llinventoryfunctions.cpp index 1ccefa3212..7fff88fba7 100644 --- a/indra/newview/llinventoryfunctions.cpp +++ b/indra/newview/llinventoryfunctions.cpp @@ -2493,6 +2493,40 @@ bool can_share_item(const LLUUID& item_id)      return can_share;  } + +EMyOutfitsSubfolderType myoutfit_object_subfolder_type( +    LLInventoryModel* model, +    const LLUUID& obj_id, +    const LLUUID& my_outfits_id) +{ +    if (obj_id == my_outfits_id) return MY_OUTFITS_NO; + +    const LLViewerInventoryCategory* test_cat = model->getCategory(obj_id); +    if (test_cat->getPreferredType() == LLFolderType::FT_OUTFIT) +    { +        return MY_OUTFITS_OUTFIT; +    } +    while (test_cat) +    { +        if (test_cat->getPreferredType() == LLFolderType::FT_OUTFIT) +        { +            return MY_OUTFITS_SUBOUTFIT; +        } + +        const LLUUID& parent_id = test_cat->getParentUUID(); +        if (parent_id.isNull()) +        { +            return MY_OUTFITS_NO; +        } +        if (parent_id == my_outfits_id) +        { +            return MY_OUTFITS_SUBFOLDER; +        } +        test_cat = model->getCategory(parent_id); +    } + +    return MY_OUTFITS_NO; +}  ///----------------------------------------------------------------------------  /// LLMarketplaceValidator implementations  ///---------------------------------------------------------------------------- @@ -2621,6 +2655,11 @@ bool LLInventoryCollectFunctor::itemTransferCommonlyAllowed(const LLInventoryIte      return false;  } +bool LLIsFolderType::operator()(LLInventoryCategory* cat, LLInventoryItem* item) +{ +    return cat && cat->getPreferredType() == mType; +} +  bool LLIsType::operator()(LLInventoryCategory* cat, LLInventoryItem* item)  {      if(mType == LLAssetType::AT_CATEGORY) diff --git a/indra/newview/llinventoryfunctions.h b/indra/newview/llinventoryfunctions.h index 13a64f21dc..0ab045f2a0 100644 --- a/indra/newview/llinventoryfunctions.h +++ b/indra/newview/llinventoryfunctions.h @@ -121,6 +121,18 @@ std::string get_searchable_creator_name(LLInventoryModel* model, const LLUUID& i  std::string get_searchable_UUID(LLInventoryModel* model, const LLUUID& item_id);  bool can_share_item(const LLUUID& item_id); +enum EMyOutfitsSubfolderType +{ +    MY_OUTFITS_NO, +    MY_OUTFITS_SUBFOLDER, +    MY_OUTFITS_OUTFIT, +    MY_OUTFITS_SUBOUTFIT, +}; +EMyOutfitsSubfolderType myoutfit_object_subfolder_type( +    LLInventoryModel* model, +    const LLUUID& obj_id, +    const LLUUID& my_outfits_id); +  /**                    Miscellaneous global functions   **                                                                            **   *******************************************************************************/ @@ -234,6 +246,24 @@ protected:  // the type is the type passed in during construction.  //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +class LLIsFolderType : public LLInventoryCollectFunctor +{ +public: +    LLIsFolderType(LLFolderType::EType type) : mType(type) {} +    virtual ~LLIsFolderType() {} +    virtual bool operator()(LLInventoryCategory* cat, +        LLInventoryItem* item); +protected: +    LLFolderType::EType mType; +}; + +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// Class LLIsType +// +// Implementation of a LLInventoryCollectFunctor which returns true if +// the type is the type passed in during construction. +//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +  class LLIsType : public LLInventoryCollectFunctor  {  public: diff --git a/indra/newview/llinventorygallery.cpp b/indra/newview/llinventorygallery.cpp index c4f93cee98..eb47af85fd 100644 --- a/indra/newview/llinventorygallery.cpp +++ b/indra/newview/llinventorygallery.cpp @@ -60,10 +60,12 @@ static LLPanelInjector<LLInventoryGallery> t_inventory_gallery("inventory_galler  const S32 GALLERY_ITEMS_PER_ROW_MIN = 2;  const S32 FAST_LOAD_THUMBNAIL_TRSHOLD = 50; // load folders below this value immediately +  // Helper dnd functions  bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat, bool drop, std::string& tooltip_msg, bool is_link);  bool dragItemIntoFolder(LLUUID folder_id, LLInventoryItem* inv_item, bool drop, std::string& tooltip_msg, bool user_confirm);  void dropToMyOutfits(LLInventoryCategory* inv_cat); +void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID& dest_id, LLFolderType::EType preferred_type);  class LLGalleryPanel: public LLPanel  { @@ -3745,7 +3747,12 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,          U32 max_items_to_wear = gSavedSettings.getU32("WearFolderLimit");          if (is_movable && move_is_into_outfit)          { -            if (dest_id == my_outifts_id) +            if ((inv_cat->getPreferredType() != LLFolderType::FT_NONE) && (inv_cat->getPreferredType() != LLFolderType::FT_OUTFIT)) +            { +                tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); +                is_movable = false; +            } +            else if (dest_id == my_outifts_id)              {                  if (source != LLToolDragAndDrop::SOURCE_AGENT || move_is_from_marketplacelistings)                  { @@ -3762,13 +3769,39 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,                      is_movable = false;                  }              } -            else if (dest_cat && dest_cat->getPreferredType() == LLFolderType::FT_NONE) +            else if (!dest_cat)              { -                is_movable = ((inv_cat->getPreferredType() == LLFolderType::FT_NONE) || (inv_cat->getPreferredType() == LLFolderType::FT_OUTFIT)); +                is_movable = false; +                tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit");              }              else              { -                is_movable = false; +                EMyOutfitsSubfolderType dest_res = myoutfit_object_subfolder_type(model, dest_id, my_outifts_id); +                EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); +                if ((dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT) && inv_res == MY_OUTFITS_OUTFIT) +                { +                    is_movable = false; +                    tooltip_msg = LLTrans::getString("TooltipCantMoveOutfitIntoOutfit"); +                } +                else if (dest_res == MY_OUTFITS_OUTFIT || dest_res == MY_OUTFITS_SUBOUTFIT) +                { +                    is_movable = false; +                    tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); +                } +                else if (dest_res == MY_OUTFITS_SUBFOLDER && inv_res == MY_OUTFITS_SUBOUTFIT) +                { +                    is_movable = false; +                    tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); +                } +                else if (can_move_to_my_outfits(model, inv_cat, max_items_to_wear)) +                { +                    is_movable = true; +                } +                else +                { +                    is_movable = false; +                    tooltip_msg = LLTrans::getString("TooltipCantCreateOutfit"); +                }              }          }          if (is_movable && move_is_into_current_outfit && is_link) @@ -3894,9 +3927,70 @@ bool dragCategoryIntoFolder(LLUUID dest_id, LLInventoryCategory* inv_cat,              if (dest_id == my_outifts_id)              { -                // Category can contains objects, -                // create a new folder and populate it with links to original objects -                dropToMyOutfits(inv_cat); +                EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); +                if (inv_res == MY_OUTFITS_SUBFOLDER || inv_res == MY_OUTFITS_OUTFIT) +                { +                    gInventory.changeCategoryParent( +                        (LLViewerInventoryCategory*)inv_cat, +                        dest_id, +                        move_is_into_trash); +                } +                else +                { +                    // Category can contains objects, +                    // create a new folder and populate it with links to original objects +                    dropToMyOutfits(inv_cat); +                } +            } +            else if (move_is_into_my_outfits) +            { +                EMyOutfitsSubfolderType dest_res = myoutfit_object_subfolder_type(model, dest_id, my_outifts_id); +                EMyOutfitsSubfolderType inv_res = myoutfit_object_subfolder_type(model, cat_id, my_outifts_id); +                switch (inv_res) +                { +                case MY_OUTFITS_NO: +                    // Moning from outside outfits into outfits +                    if (dest_res == MY_OUTFITS_SUBFOLDER) +                    { +                        // turn it into outfit +                        dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_OUTFIT); +                    } +                    else +                    { +                        dropToMyOutfitsSubfolder(inv_cat, dest_id, LLFolderType::FT_NONE); +                    } +                    break; +                case MY_OUTFITS_SUBFOLDER: +                case MY_OUTFITS_OUTFIT: +                    // only permit moving subfodlers and outfits into other subfolders +                    if (dest_res == MY_OUTFITS_SUBFOLDER) +                    { +                        gInventory.changeCategoryParent( +                            (LLViewerInventoryCategory*)inv_cat, +                            dest_id, +                            move_is_into_trash); +                    } +                    else +                    { +                        assert(false); // mot permitted, shouldn't have accepted +                    } +                    break; +                case MY_OUTFITS_SUBOUTFIT: +                    if (dest_res == MY_OUTFITS_SUBOUTFIT || dest_res == MY_OUTFITS_OUTFIT) +                    { +                        gInventory.changeCategoryParent( +                            (LLViewerInventoryCategory*)inv_cat, +                            dest_id, +                            move_is_into_trash); +                    } +                    else +                    { +                        assert(false); // mot permitted, shouldn't have accepted +                    } +                    break; +                default: +                    break; +                }              }              // if target is current outfit folder we use link              else if (move_is_into_current_outfit && @@ -4041,3 +4135,11 @@ void dropToMyOutfits(LLInventoryCategory* inv_cat)      inventory_func_type func = boost::bind(&outfitFolderCreatedCallback, inv_cat->getUUID(), _1);      gInventory.createNewCategory(dest_id, LLFolderType::FT_OUTFIT, inv_cat->getName(), func, inv_cat->getThumbnailUUID());  } + +void dropToMyOutfitsSubfolder(LLInventoryCategory* inv_cat, const LLUUID &dest_id, LLFolderType::EType preferred_type) +{ +    // Note: creation will take time, so passing folder id to callback is slightly unreliable, +    // but so is collecting and passing descendants' ids +    inventory_func_type func = boost::bind(&outfitFolderCreatedCallback, inv_cat->getUUID(), _1); +    gInventory.createNewCategory(dest_id, preferred_type, inv_cat->getName(), func, inv_cat->getThumbnailUUID()); +} diff --git a/indra/newview/llinventorygallerymenu.cpp b/indra/newview/llinventorygallerymenu.cpp index dbf4821ca1..ec3e03ee2d 100644 --- a/indra/newview/llinventorygallerymenu.cpp +++ b/indra/newview/llinventorygallerymenu.cpp @@ -586,7 +586,9 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men      bool is_trash = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH));      bool is_in_trash = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_TRASH));      bool is_lost_and_found = (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_LOST_AND_FOUND)); -    bool is_outfits= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS)); +    const LLUUID my_outfits = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); +    bool is_outfits= (selected_id == my_outfits); +    bool is_in_outfits = is_outfits || gInventory.isObjectDescendentOf(selected_id, my_outfits);      bool is_in_favorites = gInventory.isObjectDescendentOf(selected_id, gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE));      //bool is_favorites= (selected_id == gInventory.findCategoryUUIDForType(LLFolderType::FT_FAVORITE)); @@ -725,7 +727,7 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men      }      else      { -        if (is_agent_inventory && !is_inbox && !is_cof && !is_in_favorites && !is_outfits) +        if (is_agent_inventory && !is_inbox && !is_cof && !is_in_favorites && !is_outfits && !is_in_outfits)          {              LLViewerInventoryCategory* category = gInventory.getCategory(selected_id);              if (!category || !LLFriendCardsManager::instance().isCategoryInFriendFolder(category)) @@ -769,15 +771,26 @@ void LLInventoryGalleryContextMenu::updateMenuItemsVisibility(LLContextMenu* men                  items.push_back(std::string("upload_def"));              } -            if(is_outfits && !isRootFolder()) +            if(is_outfits)              { -                items.push_back(std::string("New Outfit")); +                EMyOutfitsSubfolderType res = myoutfit_object_subfolder_type(&gInventory, selected_id, my_outfits); +                if (res != MY_OUTFITS_OUTFIT && res != MY_OUTFITS_SUBOUTFIT) +                { +                    items.push_back(std::string("New Outfit")); +                    items.push_back(std::string("New Outfit Folder")); +                } +                items.push_back(std::string("Delete")); +                items.push_back(std::string("Rename")); +                if (!get_is_category_and_children_removable(&gInventory, selected_id, false)) +                { +                    disabled_items.push_back(std::string("Delete")); +                }              }              items.push_back(std::string("Subfolder Separator")); -            if (!is_system_folder && !isRootFolder()) +            if (!is_system_folder && !isRootFolder() && !is_outfits)              { -                if(has_children && (folder_type != LLFolderType::FT_OUTFIT)) +                if(has_children && (folder_type != LLFolderType::FT_OUTFIT) && !is_in_outfits)                  {                      items.push_back(std::string("Ungroup folder items"));                  } diff --git a/indra/newview/llinventorymodel.cpp b/indra/newview/llinventorymodel.cpp index 9fffe6378e..0a2d938bd0 100644 --- a/indra/newview/llinventorymodel.cpp +++ b/indra/newview/llinventorymodel.cpp @@ -1007,7 +1007,8 @@ void LLInventoryModel::createNewCategory(const LLUUID& parent_id,          return;      } -    if (preferred_type != LLFolderType::FT_NONE) +    if (preferred_type != LLFolderType::FT_NONE +        && preferred_type != LLFolderType::FT_OUTFIT)      {          // Ultimately this should only be done for non-singleton          // types. Requires back-end changes to guarantee that others @@ -3525,7 +3526,7 @@ bool LLInventoryModel::saveToFile(const std::string& filename,          fileXML.close(); -        LL_INFOS(LOG_INV) << "Inventory saved: " << cat_count << " categories, " << it_count << " items." << LL_ENDL; +        LL_INFOS(LOG_INV) << "Inventory saved: " << (S32)cat_count << " categories, " << (S32)it_count << " items." << LL_ENDL;      }      catch (...)      { diff --git a/indra/newview/lllocalbitmaps.cpp b/indra/newview/lllocalbitmaps.cpp index 101ee215cb..e31fbb188a 100644 --- a/indra/newview/lllocalbitmaps.cpp +++ b/indra/newview/lllocalbitmaps.cpp @@ -38,6 +38,7 @@  /* image compression headers. */  #include "llimagebmp.h"  #include "llimagetga.h" +#include "llimagej2c.h"  #include "llimagejpeg.h"  #include "llimagepng.h" @@ -106,6 +107,10 @@ LLLocalBitmap::LLLocalBitmap(std::string filename)      {          mExtension = ET_IMG_JPG;      } +    else if (temp_exten == "j2c" || temp_exten == "jp2") +    { +        mExtension = ET_IMG_J2C; +    }      else if (temp_exten == "png")      {          mExtension = ET_IMG_PNG; @@ -354,6 +359,21 @@ bool LLLocalBitmap::decodeBitmap(LLPointer<LLImageRaw> rawimg)              break;          } +        case ET_IMG_J2C: +        { +            LLPointer<LLImageJ2C> jpeg_image = new LLImageJ2C; +            if (jpeg_image->load(mFilename)) +            { +                jpeg_image->setDiscardLevel(0); +                if (jpeg_image->decode(rawimg, 0.0f)) +                { +                    rawimg->biasedScaleToPowerOfTwo(LLViewerFetchedTexture::MAX_IMAGE_SIZE_DEFAULT); +                    decode_successful = true; +                } +            } +            break; +        } +          case ET_IMG_PNG:          {              LLPointer<LLImagePNG> png_image = new LLImagePNG; diff --git a/indra/newview/lllocalbitmaps.h b/indra/newview/lllocalbitmaps.h index de2dcb3467..6c9d65e3b6 100644 --- a/indra/newview/lllocalbitmaps.h +++ b/indra/newview/lllocalbitmaps.h @@ -89,6 +89,7 @@ class LLLocalBitmap              ET_IMG_BMP,              ET_IMG_TGA,              ET_IMG_JPG, +            ET_IMG_J2C,              ET_IMG_PNG          }; diff --git a/indra/newview/llmeshrepository.cpp b/indra/newview/llmeshrepository.cpp index a8c6f69425..48c80842b9 100644 --- a/indra/newview/llmeshrepository.cpp +++ b/indra/newview/llmeshrepository.cpp @@ -1210,6 +1210,12 @@ void LLMeshRepoThread::run()          LL_WARNS(LOG_MESH) << "Convex decomposition unable to be quit." << LL_ENDL;      }  } +void LLMeshRepoThread::cleanup() +{ +    mShuttingDown = true; +    mSignal->broadcast(); +    mMeshThreadPool->close(); +}  // Mutex:  LLMeshRepoThread::mMutex must be held on entry  void LLMeshRepoThread::loadMeshSkinInfo(const LLUUID& mesh_id) @@ -1493,6 +1499,11 @@ bool LLMeshRepoThread::fetchMeshSkinInfo(const LLUUID& mesh_id)                          [mesh_id, buffer, size]                          ()                      { +                        if (gMeshRepo.mThread->isShuttingDown()) +                        { +                            delete[] buffer; +                            return; +                        }                          if (!gMeshRepo.mThread->skinInfoReceived(mesh_id, buffer, size))                          {                              // either header is faulty or something else overwrote the cache @@ -1993,6 +2004,11 @@ bool LLMeshRepoThread::fetchMeshLOD(const LLVolumeParams& mesh_params, S32 lod)                          [params, mesh_id, lod, buffer, size]                          ()                      { +                        if (gMeshRepo.mThread->isShuttingDown()) +                        { +                            delete[] buffer; +                            return; +                        }                          if (gMeshRepo.mThread->lodReceived(params, lod, buffer, size) == MESH_OK)                          {                              LL_DEBUGS(LOG_MESH) << "Mesh/Cache: Mesh body for ID " << mesh_id << " - was retrieved from the cache." << LL_ENDL; @@ -3792,6 +3808,11 @@ void LLMeshLODHandler::processData(LLCore::BufferArray * /* body */, S32 /* body              [shrd_handler, data, data_size]              ()          { +            if (gMeshRepo.mThread->isShuttingDown()) +            { +                delete[] data; +                return; +            }              LLMeshLODHandler* handler = (LLMeshLODHandler * )shrd_handler.get();              handler->processLod(data, data_size);              delete[] data; @@ -3905,6 +3926,11 @@ void LLMeshSkinInfoHandler::processData(LLCore::BufferArray * /* body */, S32 /*              [shrd_handler, data, data_size]              ()          { +            if (gMeshRepo.mThread->isShuttingDown()) +            { +                delete[] data; +                return; +            }              LLMeshSkinInfoHandler* handler = (LLMeshSkinInfoHandler*)shrd_handler.get();              handler->processSkin(data, data_size);              delete[] data; @@ -4127,8 +4153,7 @@ void LLMeshRepository::shutdown()          mUploads[i]->discard() ; //discard the uploading requests.      } -    mThread->mSignal->broadcast(); -    mThread->mMeshThreadPool->close(); +    mThread->cleanup();      while (!mThread->isStopped())      { diff --git a/indra/newview/llmeshrepository.h b/indra/newview/llmeshrepository.h index 0d9da32e27..b9acb3573f 100644 --- a/indra/newview/llmeshrepository.h +++ b/indra/newview/llmeshrepository.h @@ -515,6 +515,8 @@ public:      ~LLMeshRepoThread();      virtual void run(); +    void cleanup(); +    bool isShuttingDown() { return mShuttingDown; }      void lockAndLoadMeshLOD(const LLVolumeParams& mesh_params, S32 lod);      void loadMeshLOD(const LLVolumeParams& mesh_params, S32 lod); @@ -583,6 +585,7 @@ private:      U8* getDiskCacheBuffer(S32 size);      S32 mDiskCacheBufferSize = 0;      U8* mDiskCacheBuffer = nullptr; +    bool mShuttingDown = false;  }; diff --git a/indra/newview/llmodelpreview.cpp b/indra/newview/llmodelpreview.cpp index 29ab4e38c0..5a8fd299bf 100644 --- a/indra/newview/llmodelpreview.cpp +++ b/indra/newview/llmodelpreview.cpp @@ -132,20 +132,21 @@ std::string getLodSuffix(S32 lod)      return suffix;  } -void FindModel(LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut) +static bool FindModel(const LLModelLoader::scene& scene, const std::string& name_to_match, LLModel*& baseModelOut, LLMatrix4& matOut)  { -    for (auto scene_iter = scene.begin(); scene_iter != scene.end(); scene_iter++) +    for (const auto& scene_pair : scene)      { -        for (auto model_iter = scene_iter->second.begin(); model_iter != scene_iter->second.end(); model_iter++) +        for (const auto& model_iter : scene_pair.second)          { -            if (model_iter->mModel && (model_iter->mModel->mLabel == name_to_match)) +            if (model_iter.mModel && (model_iter.mModel->mLabel == name_to_match))              { -                baseModelOut = model_iter->mModel; -                matOut = scene_iter->first; -                return; +                baseModelOut = model_iter.mModel; +                matOut = scene_pair.first; +                return true;              }          }      } +    return false;  }  //----------------------------------------------------------------------------- @@ -319,10 +320,8 @@ void LLModelPreview::rebuildUploadData()          mat *= scale_mat; -        for (auto model_iter = iter->second.begin(); model_iter != iter->second.end(); ++model_iter) -        { // for each instance with said transform applied -            LLModelInstance instance = *model_iter; - +        for (LLModelInstance& instance : iter->second) +        { //for each instance with said transform applied              LLModel* base_model = instance.mModel;              if (base_model && !requested_name.empty()) @@ -354,7 +353,7 @@ void LLModelPreview::rebuildUploadData()                      }                      else                      { -                        //Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for +                        // Physics can be inherited from other LODs or loaded, so we need to adjust what extension we are searching for                          extensionLOD = mPhysicsSearchLOD;                      } @@ -365,9 +364,9 @@ void LLModelPreview::rebuildUploadData()                          name_to_match += toAdd;                      } -                    FindModel(mScene[i], name_to_match, lod_model, transform); +                    bool found = FindModel(mScene[i], name_to_match, lod_model, transform); -                    if (!lod_model && i != LLModel::LOD_PHYSICS) +                    if (!found && i != LLModel::LOD_PHYSICS)                      {                          if (mImporterDebug)                          { @@ -380,7 +379,7 @@ void LLModelPreview::rebuildUploadData()                          }                          int searchLOD = (i > LLModel::LOD_HIGH) ? LLModel::LOD_HIGH : i; -                        while ((searchLOD <= LLModel::LOD_HIGH) && !lod_model) +                        for (; searchLOD <= LLModel::LOD_HIGH; ++searchLOD)                          {                              std::string name_to_match = instance.mLabel;                              llassert(!name_to_match.empty()); @@ -394,8 +393,8 @@ void LLModelPreview::rebuildUploadData()                              // See if we can find an appropriately named model in LOD 'searchLOD'                              // -                            FindModel(mScene[searchLOD], name_to_match, lod_model, transform); -                            searchLOD++; +                            if (FindModel(mScene[searchLOD], name_to_match, lod_model, transform)) +                                break;                          }                      }                  } @@ -1174,8 +1173,7 @@ void LLModelPreview::loadModelCallback(S32 loaded_lod)                          LLModel* found_model = NULL;                          LLMatrix4 transform; -                        FindModel(mBaseScene, loaded_name, found_model, transform); -                        if (found_model) +                        if (FindModel(mBaseScene, loaded_name, found_model, transform))                          { // don't rename correctly named models (even if they are placed in a wrong order)                              name_based = true;                          } diff --git a/indra/newview/lloutfitslist.cpp b/indra/newview/lloutfitslist.cpp index 6e666b8a4b..9d8493549d 100644 --- a/indra/newview/lloutfitslist.cpp +++ b/indra/newview/lloutfitslist.cpp @@ -819,6 +819,50 @@ void LLOutfitListBase::observerCallback(const LLUUID& category_id)      refreshList(category_id);  } +class LLIsOutfitListFolder : public LLInventoryCollectFunctor +{ +public: +    LLIsOutfitListFolder() +    { +        mOutfitsId = gInventory.findCategoryUUIDForType(LLFolderType::FT_MY_OUTFITS); +    } +    virtual ~LLIsOutfitListFolder() {} + +    bool operator()(LLInventoryCategory* cat, LLInventoryItem* item) override +    { +        if (cat) +        { +            if (cat->getPreferredType() == LLFolderType::FT_OUTFIT) +            { +                return true; +            } +            if (cat->getPreferredType() == LLFolderType::FT_NONE +                && cat->getParentUUID() == mOutfitsId) +            { +                LLViewerInventoryCategory* inv_cat = dynamic_cast<LLViewerInventoryCategory*>(cat); +                if (inv_cat && inv_cat->getDescendentCount() > 3) +                { +                    LLInventoryModel::cat_array_t* cats; +                    LLInventoryModel::item_array_t* items; +                    gInventory.getDirectDescendentsOf(inv_cat->getUUID(), cats, items); +                    if (cats->empty() // protection against outfits inside +                        && items->size() > 3) // eyes, skin, hair and shape are required +                    { +                        // For now assume this to be an old style outfit, not a subfolder +                        // but ideally no such 'outfits' should be left in My Outfits +                        // Todo: stop counting FT_NONE as outfits, +                        // convert obvious outfits into FT_OUTFIT +                        return true; +                    } +                } +            } +        } +        return false; +    } +protected: +    LLUUID mOutfitsId; +}; +  void LLOutfitListBase::refreshList(const LLUUID& category_id)  {      bool wasNull = mRefreshListState.CategoryUUID.isNull(); @@ -828,13 +872,13 @@ void LLOutfitListBase::refreshList(const LLUUID& category_id)      LLInventoryModel::item_array_t item_array;      // Collect all sub-categories of a given category. -    LLIsType is_category(LLAssetType::AT_CATEGORY); +    LLIsOutfitListFolder is_outfit;      gInventory.collectDescendentsIf(          category_id,          cat_array,          item_array,          LLInventoryModel::EXCLUDE_TRASH, -        is_category); +        is_outfit);      // Memorize item names for each UUID      std::map<LLUUID, std::string> names; diff --git a/indra/newview/llpanelvolume.cpp b/indra/newview/llpanelvolume.cpp index 951dc45a78..2fbdbeaf59 100644 --- a/indra/newview/llpanelvolume.cpp +++ b/indra/newview/llpanelvolume.cpp @@ -576,32 +576,48 @@ void LLPanelVolume::getState( )              return object->getMaterial();          }      } func; -    bool material_same = LLSelectMgr::getInstance()->getSelection()->getSelectedTEValue( &func, material_code ); +    LLObjectSelectionHandle selection = LLSelectMgr::getInstance()->getSelection(); +    bool material_same = selection->getSelectedTEValue( &func, material_code );      std::string LEGACY_FULLBRIGHT_DESC = LLTrans::getString("Fullbright"); -    if (editable && single_volume && material_same) + +    bool enable_material = editable && single_volume && material_same; +    LLCachedControl<bool> edit_linked(gSavedSettings, "EditLinkedParts", false); +    if (!enable_material && !edit_linked())      { -        mComboMaterial->setEnabled( true ); -        if (material_code == LL_MCODE_LIGHT) +        LLViewerObject* root = selection->getPrimaryObject(); +        while (root && !root->isAvatar() && root->getParent())          { -            if (mComboMaterial->getItemCount() == mComboMaterialItemCount) +            LLViewerObject* parent = (LLViewerObject*)root->getParent(); +            if (parent->isAvatar())              { -                mComboMaterial->add(LEGACY_FULLBRIGHT_DESC); +                break;              } -            mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC); +            root = parent;          } -        else +        if (root)          { -            if (mComboMaterial->getItemCount() != mComboMaterialItemCount) -            { -                mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); -            } +            material_code = root->getMaterial(); +        } +    } -            mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code))); +    mComboMaterial->setEnabled(enable_material); + +    if (material_code == LL_MCODE_LIGHT) +    { +        if (mComboMaterial->getItemCount() == mComboMaterialItemCount) +        { +            mComboMaterial->add(LEGACY_FULLBRIGHT_DESC);          } +        mComboMaterial->setSimple(LEGACY_FULLBRIGHT_DESC);      }      else      { -        mComboMaterial->setEnabled( false ); +        if (mComboMaterial->getItemCount() != mComboMaterialItemCount) +        { +            mComboMaterial->remove(LEGACY_FULLBRIGHT_DESC); +        } + +        mComboMaterial->setSimple(std::string(LLMaterialTable::basic.getName(material_code)));      }      // Physics properties diff --git a/indra/newview/llselectmgr.cpp b/indra/newview/llselectmgr.cpp index fbf5aa84d8..be1e64ce54 100644 --- a/indra/newview/llselectmgr.cpp +++ b/indra/newview/llselectmgr.cpp @@ -3139,6 +3139,8 @@ void LLSelectMgr::adjustTexturesByScale(bool send_to_sim, bool stretch)                      F32 scale_x = 1;                      F32 scale_y = 1; +                    F32 offset_x = 0; +                    F32 offset_y = 0;                      for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)                      { @@ -3155,6 +3157,21 @@ void LLSelectMgr::adjustTexturesByScale(bool send_to_sim, bool stretch)                              scale_y = scale_ratio.mV[t_axis] * object_scale.mV[t_axis];                          }                          material->mTextureTransform[i].mScale.set(scale_x, scale_y); + +                        LLVector2 scales = selectNode->mGLTFScales[te_num][i]; +                        LLVector2 offsets = selectNode->mGLTFOffsets[te_num][i]; +                        F64 int_part = 0; +                        offset_x = (F32)modf((offsets[VX] + (scales[VX] - scale_x)) / 2, &int_part); +                        if (offset_x < 0) +                        { +                            offset_x++; +                        } +                        offset_y = (F32)modf((offsets[VY] + (scales[VY] - scale_y)) / 2, &int_part); +                        if (offset_y < 0) +                        { +                            offset_y++; +                        } +                        material->mTextureTransform[i].mOffset.set(offset_x, offset_y);                      }                      const LLGLTFMaterial* base_material = tep->getGLTFMaterial(); @@ -6905,6 +6922,8 @@ void LLSelectNode::saveTextureScaleRatios(LLRender::eTexIndex index_to_query)  {      mTextureScaleRatios.clear();      mGLTFScaleRatios.clear(); +    mGLTFScales.clear(); +    mGLTFOffsets.clear();      if (mObject.notNull())      { @@ -6945,6 +6964,8 @@ void LLSelectNode::saveTextureScaleRatios(LLRender::eTexIndex index_to_query)              F32 scale_x = 1;              F32 scale_y = 1;              std::vector<LLVector3> material_v_vec; +            std::vector<LLVector2> material_scales_vec; +            std::vector<LLVector2> material_offset_vec;              for (U32 i = 0; i < LLGLTFMaterial::GLTF_TEXTURE_INFO_COUNT; ++i)              {                  if (material) @@ -6952,12 +6973,16 @@ void LLSelectNode::saveTextureScaleRatios(LLRender::eTexIndex index_to_query)                      LLGLTFMaterial::TextureTransform& transform = material->mTextureTransform[i];                      scale_x = transform.mScale[VX];                      scale_y = transform.mScale[VY]; +                    material_scales_vec.push_back(transform.mScale); +                    material_offset_vec.push_back(transform.mOffset);                  }                  else                  {                      // Not having an override doesn't mean that there is no material                      scale_x = 1;                      scale_y = 1; +                    material_scales_vec.emplace_back(scale_x, scale_y); +                    material_offset_vec.emplace_back(0.f, 0.f);                  }                  if (tep->getTexGen() == LLTextureEntry::TEX_GEN_PLANAR) @@ -6973,6 +6998,8 @@ void LLSelectNode::saveTextureScaleRatios(LLRender::eTexIndex index_to_query)                  material_v_vec.push_back(material_v);              }              mGLTFScaleRatios.push_back(material_v_vec); +            mGLTFScales.push_back(material_scales_vec); +            mGLTFOffsets.push_back(material_offset_vec);          }      }  } diff --git a/indra/newview/llselectmgr.h b/indra/newview/llselectmgr.h index 0dbdc133e3..792a37297f 100644 --- a/indra/newview/llselectmgr.h +++ b/indra/newview/llselectmgr.h @@ -242,6 +242,8 @@ public:      gltf_materials_vec_t mSavedGLTFOverrideMaterials;      std::vector<LLVector3>  mTextureScaleRatios;      std::vector< std::vector<LLVector3> >  mGLTFScaleRatios; +    std::vector< std::vector<LLVector2> >  mGLTFScales; +    std::vector< std::vector<LLVector2> >  mGLTFOffsets;      std::vector<LLVector3>  mSilhouetteVertices;    // array of vertices to render silhouette of object      std::vector<LLVector3>  mSilhouetteNormals; // array of normals to render silhouette of object      bool                    mSilhouetteExists;  // need to generate silhouette? diff --git a/indra/newview/llsnapshotlivepreview.cpp b/indra/newview/llsnapshotlivepreview.cpp index ea95d71b27..68b4ab381a 100644 --- a/indra/newview/llsnapshotlivepreview.cpp +++ b/indra/newview/llsnapshotlivepreview.cpp @@ -694,6 +694,7 @@ bool LLSnapshotLivePreview::onIdle( void* snapshot_preview )      static LLCachedControl<bool> freeze_time(gSavedSettings, "FreezeTime", false);      static LLCachedControl<bool> use_freeze_frame(gSavedSettings, "UseFreezeFrame", false);      static LLCachedControl<bool> render_ui(gSavedSettings, "RenderUIInSnapshot", false); +    static LLCachedControl<bool> render_balance(gSavedSettings, "RenderBalanceInSnapshot", false);      static LLCachedControl<bool> render_hud(gSavedSettings, "RenderHUDInSnapshot", false);      static LLCachedControl<bool> render_no_post(gSavedSettings, "RenderSnapshotNoPost", false); @@ -750,6 +751,7 @@ bool LLSnapshotLivePreview::onIdle( void* snapshot_preview )                  render_hud,                  false,                  render_no_post, +                render_balance,                  previewp->mSnapshotBufferType,                  previewp->getMaxImageSize()))          { diff --git a/indra/newview/llstatusbar.cpp b/indra/newview/llstatusbar.cpp index ecbbc4b2c5..8aa2058ae1 100644 --- a/indra/newview/llstatusbar.cpp +++ b/indra/newview/llstatusbar.cpp @@ -738,6 +738,10 @@ void LLStatusBar::updateBalancePanelPosition()      balance_bg_view->setShape(balance_bg_rect);  } +void LLStatusBar::setBalanceVisible(bool visible) +{ +    mBoxBalance->setVisible(visible); +}  // Implements secondlife:///app/balance/request to request a L$ balance  // update via UDP message system. JC diff --git a/indra/newview/llstatusbar.h b/indra/newview/llstatusbar.h index 4c9d3e0c08..45cbda0ef1 100644 --- a/indra/newview/llstatusbar.h +++ b/indra/newview/llstatusbar.h @@ -93,6 +93,8 @@ public:      S32 getSquareMetersCommitted() const;      S32 getSquareMetersLeft() const; +    void setBalanceVisible(bool visible); +      LLPanelNearByMedia* getNearbyMediaPanel() { return mPanelNearByMedia; }  private: diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp index 4315c4c6b0..6f99da5957 100644 --- a/indra/newview/llsurfacepatch.cpp +++ b/indra/newview/llsurfacepatch.cpp @@ -201,7 +201,7 @@ LLVector2 LLSurfacePatch::getTexCoords(const U32 x, const U32 y) const  void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3 *vertex, LLVector3 *normal, -                          LLVector2 *tex1) const +                          LLVector2* tex0, LLVector2 *tex1) const  {      if (!mSurfacep || !mSurfacep->getRegion() || !mSurfacep->getGridsPerEdge() || !mVObjp)      { @@ -210,6 +210,7 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3      llassert_always(vertex && normal && tex1);      U32 surface_stride = mSurfacep->getGridsPerEdge(); +    U32 texture_stride = mSurfacep->getGridsPerEdge() - 1;      U32 point_offset = x + y*surface_stride;      *normal = getNormal(x, y); @@ -220,6 +221,12 @@ void LLSurfacePatch::eval(const U32 x, const U32 y, const U32 stride, LLVector3      pos_agent.mV[VZ]  = *(mDataZ + point_offset);      *vertex     = pos_agent-mVObjp->getRegion()->getOriginAgent(); +    // tex0 is used for ownership overlay +    LLVector3 rel_pos = pos_agent - mSurfacep->getOriginAgent(); +    LLVector3 tex_pos = rel_pos * (1.f / (texture_stride * mSurfacep->getMetersPerGrid())); +    tex0->mV[0] = tex_pos.mV[0]; +    tex0->mV[1] = tex_pos.mV[1]; +      tex1->mV[0] = mSurfacep->getRegion()->getCompositionXY(llfloor(mOriginRegion.mV[0])+x, llfloor(mOriginRegion.mV[1])+y);      const F32 xyScale = 4.9215f*7.f; //0.93284f; diff --git a/indra/newview/llsurfacepatch.h b/indra/newview/llsurfacepatch.h index f4831487c1..505fc8c24c 100644 --- a/indra/newview/llsurfacepatch.h +++ b/indra/newview/llsurfacepatch.h @@ -116,7 +116,7 @@ public:      void calcNormalFlat(LLVector3& normal_out, const U32 x, const U32 y, const U32 index /* 0 or 1 */);      void eval(const U32 x, const U32 y, const U32 stride, -                LLVector3 *vertex, LLVector3 *normal, LLVector2 *tex1) const; +                LLVector3 *vertex, LLVector3 *normal, LLVector2* tex0, LLVector2 *tex1) const; diff --git a/indra/newview/llterrainpaintmap.cpp b/indra/newview/llterrainpaintmap.cpp index 8ccde74c93..c7a82013e4 100644 --- a/indra/newview/llterrainpaintmap.cpp +++ b/indra/newview/llterrainpaintmap.cpp @@ -204,8 +204,9 @@ bool LLTerrainPaintMap::bakeHeightNoiseIntoPBRPaintMapRGB(const LLViewerRegion&                      {                          LLVector3 scratch3;                          LLVector3 pos3; +                        LLVector2 tex0_temp;                          LLVector2 tex1_temp; -                        patch->eval(i, j, stride, &pos3, &scratch3, &tex1_temp); +                        patch->eval(i, j, stride, &pos3, &scratch3, &tex0_temp, &tex1_temp);                          (*pos++).set(pos3.mV[VX], pos3.mV[VY], pos3.mV[VZ]);                          *tex1++ = tex1_temp;                          vertex_total++; diff --git a/indra/newview/lltexturecache.cpp b/indra/newview/lltexturecache.cpp index be7653c011..442c627d07 100644 --- a/indra/newview/lltexturecache.cpp +++ b/indra/newview/lltexturecache.cpp @@ -1347,27 +1347,39 @@ U32 LLTextureCache::openAndReadEntries(std::vector<Entry>& entries)      }      for (U32 idx=0; idx<num_entries; idx++)      { -        Entry entry; -        S32 bytes_read = aprfile->read((void*)(&entry), (S32)sizeof(Entry)); -        if (bytes_read < sizeof(Entry)) +        try +        { +            Entry entry; +            S32 bytes_read = aprfile->read((void*)(&entry), (S32)sizeof(Entry)); +            if (bytes_read < sizeof(Entry)) +            { +                LL_WARNS() << "Corrupted header entries, failed at " << idx << " / " << num_entries << LL_ENDL; +                return 0; +            } +            entries.push_back(entry); +            //      LL_INFOS() << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << LL_ENDL; +            if (entry.mImageSize > entry.mBodySize) +            { +                mHeaderIDMap[entry.mID] = idx; +                mTexturesSizeMap[entry.mID] = entry.mBodySize; +                mTexturesSizeTotal += entry.mBodySize; +            } +            else +            { +                mFreeList.insert(idx); +            } +        } +        catch (std::bad_alloc&)          { -            LL_WARNS() << "Corrupted header entries, failed at " << idx << " / " << num_entries << LL_ENDL; +            // Too little ram yet very large cache? +            // Should this actually crash viewer? +            entries.clear(); +            LL_WARNS() << "Bad alloc trying to read texture entries from cache, mFreeList: " << (S32)mFreeList.size() +                << ", added entries: " << idx << ", total entries: " << num_entries << LL_ENDL;              closeHeaderEntriesFile();              purgeAllTextures(false);              return 0;          } -        entries.push_back(entry); -//      LL_INFOS() << "ENTRY: " << entry.mTime << " TEX: " << entry.mID << " IDX: " << idx << " Size: " << entry.mImageSize << LL_ENDL; -        if(entry.mImageSize > entry.mBodySize) -        { -            mHeaderIDMap[entry.mID] = idx; -            mTexturesSizeMap[entry.mID] = entry.mBodySize; -            mTexturesSizeTotal += entry.mBodySize; -        } -        else -        { -            mFreeList.insert(idx); -        }      }      closeHeaderEntriesFile();      return num_entries; diff --git a/indra/newview/llvieweraudio.cpp b/indra/newview/llvieweraudio.cpp index b3b4f43e57..404297c58f 100644 --- a/indra/newview/llvieweraudio.cpp +++ b/indra/newview/llvieweraudio.cpp @@ -541,8 +541,8 @@ void audio_update_wind(bool force_update)          // whereas steady-state avatar walk velocity is only 3.2 m/s.          // Without this the world feels desolate on first login when you are          // standing still. -        const F32 WIND_LEVEL = 0.5f; -        LLVector3 scaled_wind_vec = gWindVec * WIND_LEVEL; +        static LLUICachedControl<F32> wind_level("AudioLevelWind", 0.5f); +        LLVector3 scaled_wind_vec = gWindVec * wind_level;          // Mix in the avatar's motion, subtract because when you walk north,          // the apparent wind moves south. diff --git a/indra/newview/llviewerdisplay.cpp b/indra/newview/llviewerdisplay.cpp index 32019f860d..27718782ee 100644 --- a/indra/newview/llviewerdisplay.cpp +++ b/indra/newview/llviewerdisplay.cpp @@ -215,11 +215,15 @@ void display_update_camera()          final_far = gSavedSettings.getF32("RenderReflectionProbeDrawDistance");      }      else if (CAMERA_MODE_CUSTOMIZE_AVATAR == gAgentCamera.getCameraMode()) -      {          final_far *= 0.5f;      } +    else if (LLViewerTexture::sDesiredDiscardBias > 2.f) +    { +        final_far = llmax(32.f, final_far / (LLViewerTexture::sDesiredDiscardBias - 1.f)); +    }      LLViewerCamera::getInstance()->setFar(final_far); +    LLVOAvatar::sRenderDistance = llclamp(final_far, 16.f, 256.f);      gViewerWindow->setup3DRender();      if (!gCubeSnapshot) diff --git a/indra/newview/llviewermenufile.cpp b/indra/newview/llviewermenufile.cpp index ce66dbc03f..9743ec0c59 100644 --- a/indra/newview/llviewermenufile.cpp +++ b/indra/newview/llviewermenufile.cpp @@ -932,6 +932,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t          bool render_ui = gSavedSettings.getBOOL("RenderUIInSnapshot");          bool render_hud = gSavedSettings.getBOOL("RenderHUDInSnapshot");          bool render_no_post = gSavedSettings.getBOOL("RenderSnapshotNoPost"); +        bool render_balance = gSavedSettings.getBOOL("RenderBalanceInSnapshot");          bool high_res = gSavedSettings.getBOOL("HighResSnapshot");          if (high_res) @@ -952,6 +953,7 @@ class LLFileTakeSnapshotToDisk : public view_listener_t                                         render_hud,                                         false,                                         render_no_post, +                                       render_balance,                                         LLSnapshotModel::SNAPSHOT_TYPE_COLOR,                                         high_res ? S32_MAX : MAX_SNAPSHOT_IMAGE_SIZE)) //per side          { diff --git a/indra/newview/llviewermessage.cpp b/indra/newview/llviewermessage.cpp index 3b16708091..bdcfec34f6 100644 --- a/indra/newview/llviewermessage.cpp +++ b/indra/newview/llviewermessage.cpp @@ -5055,6 +5055,7 @@ bool attempt_standard_notification(LLMessageSystem* msgsystem)                                          false, //UI                                          gSavedSettings.getBOOL("RenderHUDInSnapshot"),                                          false, +                                        false,                                          LLSnapshotModel::SNAPSHOT_TYPE_COLOR,                                          LLSnapshotModel::SNAPSHOT_FORMAT_PNG);          } @@ -5160,6 +5161,7 @@ static void process_special_alert_messages(const std::string & message)                                      false,                                      gSavedSettings.getBOOL("RenderHUDInSnapshot"),                                      false, +                                    false,                                      LLSnapshotModel::SNAPSHOT_TYPE_COLOR,                                      LLSnapshotModel::SNAPSHOT_FORMAT_PNG);      } diff --git a/indra/newview/llviewerparcelmgr.cpp b/indra/newview/llviewerparcelmgr.cpp index 1a5c40064a..432da2e990 100644 --- a/indra/newview/llviewerparcelmgr.cpp +++ b/indra/newview/llviewerparcelmgr.cpp @@ -42,6 +42,7 @@  // Viewer includes  #include "llagent.h"  #include "llagentaccess.h" +#include "llcallbacklist.h"  #include "llviewerparcelaskplay.h"  #include "llviewerwindow.h"  #include "llviewercontrol.h" @@ -1756,6 +1757,8 @@ void LLViewerParcelMgr::processParcelProperties(LLMessageSystem *msg, void **use                  {                      instance->mTeleportFinishedSignal(instance->mTeleportInProgressPosition, false);                  } +                instance->postTeleportFinished(instance->mTeleportWithinRegion); +                instance->mTeleportWithinRegion = false;              }              parcel->setParcelEnvironmentVersion(parcel_environment_version);              LL_DEBUGS("ENVIRONMENT") << "Parcel environment version is " << parcel->getParcelEnvironmentVersion() << LL_ENDL; @@ -2725,6 +2728,8 @@ void LLViewerParcelMgr::onTeleportFinished(bool local, const LLVector3d& new_pos          // Local teleport. We already have the agent parcel data.          // Emit the signal immediately.          getInstance()->mTeleportFinishedSignal(new_pos, local); + +        postTeleportFinished(true);      }      else      { @@ -2733,12 +2738,14 @@ void LLViewerParcelMgr::onTeleportFinished(bool local, const LLVector3d& new_pos          // Let's wait for the update and then emit the signal.          mTeleportInProgressPosition = new_pos;          mTeleportInProgress = true; +        mTeleportWithinRegion = local;      }  }  void LLViewerParcelMgr::onTeleportFailed()  {      mTeleportFailedSignal(); +    LLEventPumps::instance().obtain("LLTeleport").post(llsd::map("success", false));  }  bool  LLViewerParcelMgr::getTeleportInProgress() @@ -2746,3 +2753,20 @@ bool  LLViewerParcelMgr::getTeleportInProgress()      return mTeleportInProgress // case where parcel data arrives after teleport          || gAgent.getTeleportState() > LLAgent::TELEPORT_NONE; // For LOCAL, no mTeleportInProgress  } + +void LLViewerParcelMgr::postTeleportFinished(bool local) +{ +    auto post = []() +    { +        LLEventPumps::instance().obtain("LLTeleport").post(llsd::map("success", true)); +    }; +    if (local) +    { +        static LLCachedControl<F32> teleport_local_delay(gSavedSettings, "TeleportLocalDelay"); +        doAfterInterval(post, teleport_local_delay + 0.5f); +    } +    else +    { +        post(); +    } +} diff --git a/indra/newview/llviewerparcelmgr.h b/indra/newview/llviewerparcelmgr.h index 086bca4878..1925cd23ed 100644 --- a/indra/newview/llviewerparcelmgr.h +++ b/indra/newview/llviewerparcelmgr.h @@ -295,6 +295,8 @@ public:      void onTeleportFailed();      bool getTeleportInProgress(); +    void postTeleportFinished(bool local); +      static bool isParcelOwnedByAgent(const LLParcel* parcelp, U64 group_proxy_power);      static bool isParcelModifiableByAgent(const LLParcel* parcelp, U64 group_proxy_power); @@ -344,7 +346,9 @@ private:      std::vector<LLParcelObserver*> mObservers; +    // Used to communicate between onTeleportFinished() and processParcelProperties()      bool                        mTeleportInProgress; +    bool                        mTeleportWithinRegion{ false };      LLVector3d                  mTeleportInProgressPosition;      teleport_finished_signal_t  mTeleportFinishedSignal;      teleport_failed_signal_t    mTeleportFailedSignal; diff --git a/indra/newview/llviewertexturelist.cpp b/indra/newview/llviewertexturelist.cpp index 63d5a2d778..0d02dc034e 100644 --- a/indra/newview/llviewertexturelist.cpp +++ b/indra/newview/llviewertexturelist.cpp @@ -1437,6 +1437,15 @@ bool LLViewerTextureList::createUploadFile(const std::string& filename,          image->setLastError("Couldn't load the image to be uploaded.");          return false;      } + +    // calcDataSizeJ2C assumes maximum size is 2048 and for bigger images can +    // assign discard to bring imige to needed size, but upload does the scaling +    // as needed, so just reset discard. +    // Assume file is full and has 'discard' 0 data. +    // Todo: probably a better idea to have some setMaxDimentions in J2C +    // called when loading from a local file +    image->setDiscardLevel(0); +      // Decompress or expand it in a raw image structure      LLPointer<LLImageRaw> raw_image = new LLImageRaw;      if (!image->decode(raw_image, 0.0f)) diff --git a/indra/newview/llviewerwindow.cpp b/indra/newview/llviewerwindow.cpp index 93ff175967..d2685bcc48 100644 --- a/indra/newview/llviewerwindow.cpp +++ b/indra/newview/llviewerwindow.cpp @@ -4860,12 +4860,12 @@ void LLViewerWindow::movieSize(S32 new_width, S32 new_height)      }  } -bool LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width, S32 image_height, bool show_ui, bool show_hud, bool do_rebuild, LLSnapshotModel::ESnapshotLayerType type, LLSnapshotModel::ESnapshotFormat format) +bool LLViewerWindow::saveSnapshot(const std::string& filepath, S32 image_width, S32 image_height, bool show_ui, bool show_hud, bool do_rebuild, bool show_balance, LLSnapshotModel::ESnapshotLayerType type, LLSnapshotModel::ESnapshotFormat format)  {      LL_INFOS() << "Saving snapshot to: " << filepath << LL_ENDL;      LLPointer<LLImageRaw> raw = new LLImageRaw; -    bool success = rawSnapshot(raw, image_width, image_height, true, false, show_ui, show_hud, do_rebuild); +    bool success = rawSnapshot(raw, image_width, image_height, true, false, show_ui, show_hud, do_rebuild, show_balance);      if (success)      { @@ -4926,14 +4926,14 @@ void LLViewerWindow::resetSnapshotLoc() const  bool LLViewerWindow::thumbnailSnapshot(LLImageRaw *raw, S32 preview_width, S32 preview_height, bool show_ui, bool show_hud, bool do_rebuild, bool no_post, LLSnapshotModel::ESnapshotLayerType type)  { -    return rawSnapshot(raw, preview_width, preview_height, false, false, show_ui, show_hud, do_rebuild, no_post, type); +    return rawSnapshot(raw, preview_width, preview_height, false, false, show_ui, show_hud, do_rebuild, no_post, gSavedSettings.getBOOL("RenderBalanceInSnapshot"), type);  }  // Saves the image from the screen to a raw image  // Since the required size might be bigger than the available screen, this method rerenders the scene in parts (called subimages) and copy  // the results over to the final raw image.  bool LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, -    bool keep_window_aspect, bool is_texture, bool show_ui, bool show_hud, bool do_rebuild, bool no_post, LLSnapshotModel::ESnapshotLayerType type, S32 max_size) +    bool keep_window_aspect, bool is_texture, bool show_ui, bool show_hud, bool do_rebuild, bool no_post, bool show_balance, LLSnapshotModel::ESnapshotLayerType type, S32 max_size)  {      if (!raw)      { @@ -4991,6 +4991,8 @@ bool LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei          // If the user wants the UI, limit the output size to the available screen size          image_width  = llmin(image_width, window_width);          image_height = llmin(image_height, window_height); + +        setBalanceVisible(show_balance);      }      S32 original_width = 0; @@ -5068,11 +5070,13 @@ bool LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei      }      else      { +        setBalanceVisible(true);          return false;      }      if (raw->isBufferInvalid())      { +        setBalanceVisible(true);          return false;      } @@ -5248,6 +5252,7 @@ bool LLViewerWindow::rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_hei      {          send_agent_resume();      } +    setBalanceVisible(true);      return ret;  } @@ -5713,6 +5718,14 @@ void LLViewerWindow::setProgressCancelButtonVisible( bool b, const std::string&      }  } +void LLViewerWindow::setBalanceVisible(bool visible) +{ +    if (gStatusBar) +    { +        gStatusBar->setBalanceVisible(visible); +    } +} +  LLProgressView *LLViewerWindow::getProgressView() const  {      return mProgressView; diff --git a/indra/newview/llviewerwindow.h b/indra/newview/llviewerwindow.h index ac0dfa3fe4..d55c2d3817 100644 --- a/indra/newview/llviewerwindow.h +++ b/indra/newview/llviewerwindow.h @@ -364,9 +364,11 @@ public:      // snapshot functionality.      // perhaps some of this should move to llfloatershapshot?  -MG -    bool            saveSnapshot(const std::string&  filename, S32 image_width, S32 image_height, bool show_ui = true, bool show_hud = true, bool do_rebuild = false, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::ESnapshotFormat format = LLSnapshotModel::SNAPSHOT_FORMAT_BMP); -    bool            rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, bool keep_window_aspect = true, bool is_texture = false, -        bool show_ui = true, bool show_hud = true, bool do_rebuild = false, bool no_post = false, LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE); +    bool saveSnapshot(const std::string&  filename, S32 image_width, S32 image_height, bool show_ui = true, bool show_hud = true, bool do_rebuild = false, bool show_balance = true, +                     LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, LLSnapshotModel::ESnapshotFormat format = LLSnapshotModel::SNAPSHOT_FORMAT_BMP); +    bool rawSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, bool keep_window_aspect = true, bool is_texture = false, +                     bool show_ui = true, bool show_hud = true, bool do_rebuild = false, bool no_post = false, bool show_balance = true, +                     LLSnapshotModel::ESnapshotLayerType type = LLSnapshotModel::SNAPSHOT_TYPE_COLOR, S32 max_size = MAX_SNAPSHOT_IMAGE_SIZE);      bool            simpleSnapshot(LLImageRaw *raw, S32 image_width, S32 image_height, const int num_render_passes); @@ -462,6 +464,8 @@ public:      void            calcDisplayScale();      static LLRect   calcScaledRect(const LLRect & rect, const LLVector2& display_scale); +    void setBalanceVisible(bool visible); +      static std::string getLastSnapshotDir();      LLView* getFloaterSnapRegion() { return mFloaterSnapRegion; } diff --git a/indra/newview/llviewerwindowlistener.cpp b/indra/newview/llviewerwindowlistener.cpp index da7e18af5c..3119c31613 100644 --- a/indra/newview/llviewerwindowlistener.cpp +++ b/indra/newview/llviewerwindowlistener.cpp @@ -100,7 +100,7 @@ void LLViewerWindowListener::saveSnapshot(const LLSD& event) const          }          type = found->second;      } -    bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, showhud, rebuild, type); +    bool ok = mViewerWindow->saveSnapshot(event["filename"], width, height, showui, showhud, rebuild, true /*L$ Balance*/, type);      sendReply(LLSDMap("ok", ok), event);  } diff --git a/indra/newview/llvoavatar.cpp b/indra/newview/llvoavatar.cpp index 40312b7f4e..3306289f51 100644 --- a/indra/newview/llvoavatar.cpp +++ b/indra/newview/llvoavatar.cpp @@ -122,8 +122,8 @@ extern F32 ANIM_SPEED_MAX;  extern F32 ANIM_SPEED_MIN;  extern U32 JOINT_COUNT_REQUIRED_FOR_FULLRIG; -const F32 MAX_HOVER_Z = 2.0; -const F32 MIN_HOVER_Z = -2.0; +const F32 MAX_HOVER_Z = 3.0; +const F32 MIN_HOVER_Z = -3.0;  const F32 MIN_ATTACHMENT_COMPLEXITY = 0.f;  const F32 DEFAULT_MAX_ATTACHMENT_COMPLEXITY = 1.0e6f; @@ -10963,8 +10963,7 @@ void LLVOAvatar::idleUpdateRenderComplexity()      bool autotune = LLPerfStats::tunables.userAutoTuneEnabled && !mIsControlAvatar && !isSelf();      if (autotune && !isDead())      { -        static LLCachedControl<F32> render_far_clip(gSavedSettings, "RenderFarClip", 64); -        F32 radius = render_far_clip * render_far_clip; +        F32 radius = sRenderDistance * sRenderDistance;          bool is_nearby = true;          if ((dist_vec_squared(getPositionGlobal(), gAgent.getPositionGlobal()) > radius) && @@ -10996,8 +10995,7 @@ void LLVOAvatar::updateNearbyAvatarCount()      if (agent_update_timer.getElapsedTimeF32() > 1.0f)      {          S32 avs_nearby = 0; -        static LLCachedControl<F32> render_far_clip(gSavedSettings, "RenderFarClip", 64); -        F32 radius = render_far_clip * render_far_clip; +        F32 radius = sRenderDistance * sRenderDistance;          for (LLCharacter* character : LLCharacter::sInstances)          {              LLVOAvatar* avatar = (LLVOAvatar*)character; diff --git a/indra/newview/llvosurfacepatch.cpp b/indra/newview/llvosurfacepatch.cpp index 294d36b0a9..bc326a74a8 100644 --- a/indra/newview/llvosurfacepatch.cpp +++ b/indra/newview/llvosurfacepatch.cpp @@ -245,6 +245,7 @@ bool LLVOSurfacePatch::updateLOD()  void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,                                                LLStrider<LLVector3> &normalsp, +                                              LLStrider<LLVector2> &texCoords0p,                                                LLStrider<LLVector2> &texCoords1p,                                                LLStrider<U16> &indicesp)  { @@ -259,18 +260,21 @@ void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,      updateMainGeometry(facep,                      verticesp,                      normalsp, +                    texCoords0p,                      texCoords1p,                      indicesp,                      index_offset);      updateNorthGeometry(facep,                          verticesp,                          normalsp, +                        texCoords0p,                          texCoords1p,                          indicesp,                          index_offset);      updateEastGeometry(facep,                          verticesp,                          normalsp, +                        texCoords0p,                          texCoords1p,                          indicesp,                          index_offset); @@ -279,6 +283,7 @@ void LLVOSurfacePatch::getTerrainGeometry(LLStrider<LLVector3> &verticesp,  void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,                                          LLStrider<LLVector3> &verticesp,                                          LLStrider<LLVector3> &normalsp, +                                        LLStrider<LLVector2> &texCoords0p,                                          LLStrider<LLVector2> &texCoords1p,                                          LLStrider<U16> &indicesp,                                          U32 &index_offset) @@ -317,9 +322,10 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,              {                  x = i * render_stride;                  y = j * render_stride; -                mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +                mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());                  verticesp++;                  normalsp++; +                texCoords0p++;                  texCoords1p++;              }          } @@ -381,6 +387,7 @@ void LLVOSurfacePatch::updateMainGeometry(LLFace *facep,  void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,                                          LLStrider<LLVector3> &verticesp,                                          LLStrider<LLVector3> &normalsp, +                                        LLStrider<LLVector2> &texCoords0p,                                          LLStrider<LLVector2> &texCoords1p,                                          LLStrider<U16> &indicesp,                                          U32 &index_offset) @@ -414,9 +421,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,              x = i * render_stride;              y = 16 - render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          } @@ -425,9 +433,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,          {              x = i * render_stride;              y = 16; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          } @@ -460,9 +469,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,              x = i * render_stride;              y = 16 - render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          } @@ -472,9 +482,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,              x = i * render_stride;              y = 16; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          } @@ -514,9 +525,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,              x = i * north_stride;              y = 16 - render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          } @@ -526,9 +538,10 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,              x = i * north_stride;              y = 16; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          } @@ -564,6 +577,7 @@ void LLVOSurfacePatch::updateNorthGeometry(LLFace *facep,  void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,                                            LLStrider<LLVector3> &verticesp,                                            LLStrider<LLVector3> &normalsp, +                                          LLStrider<LLVector2> &texCoords0p,                                            LLStrider<LLVector2> &texCoords1p,                                            LLStrider<U16> &indicesp,                                            U32 &index_offset) @@ -592,9 +606,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,              x = 16 - render_stride;              y = i * render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          } @@ -603,9 +618,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,          {              x = 16;              y = i * render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          } @@ -638,9 +654,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,              x = 16 - render_stride;              y = i * render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          }          // Iterate through the east patch's points @@ -649,9 +666,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,              x = 16;              y = i * render_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          } @@ -690,9 +708,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,              x = 16 - render_stride;              y = i * east_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          }          // Iterate through the east patch's points @@ -701,9 +720,10 @@ void LLVOSurfacePatch::updateEastGeometry(LLFace *facep,              x = 16;              y = i * east_stride; -            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords1p.get()); +            mPatchp->eval(x, y, render_stride, verticesp.get(), normalsp.get(), texCoords0p.get(), texCoords1p.get());              verticesp++;              normalsp++; +            texCoords0p++;              texCoords1p++;          } @@ -1022,12 +1042,14 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)      LLStrider<LLVector3> vertices_start;      LLStrider<LLVector3> normals_start;      LLStrider<LLVector4a> tangents_start; +    LLStrider<LLVector2> texcoords0_start; // ownership overlay      LLStrider<LLVector2> texcoords2_start;      LLStrider<U16> indices_start;      llassert_always(buffer->getVertexStrider(vertices_start));      llassert_always(buffer->getNormalStrider(normals_start));      llassert_always(buffer->getTangentStrider(tangents_start)); +    llassert_always(buffer->getTexCoord0Strider(texcoords0_start));      llassert_always(buffer->getTexCoord1Strider(texcoords2_start));      llassert_always(buffer->getIndexStrider(indices_start)); @@ -1037,6 +1059,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)      {          LLStrider<LLVector3> vertices = vertices_start;          LLStrider<LLVector3> normals = normals_start; +        LLStrider<LLVector2> texcoords0 = texcoords0_start;          LLStrider<LLVector2> texcoords2 = texcoords2_start;          LLStrider<U16> indices = indices_start; @@ -1049,7 +1072,7 @@ void LLTerrainPartition::getGeometry(LLSpatialGroup* group)              facep->setVertexBuffer(buffer);              LLVOSurfacePatch* patchp = (LLVOSurfacePatch*) facep->getViewerObject(); -            patchp->getTerrainGeometry(vertices, normals, texcoords2, indices); +            patchp->getTerrainGeometry(vertices, normals, texcoords0, texcoords2, indices);              indices_index += facep->getIndicesCount();              index_offset += facep->getGeomCount(); diff --git a/indra/newview/llvosurfacepatch.h b/indra/newview/llvosurfacepatch.h index af5f05774b..c93a58d2d9 100644 --- a/indra/newview/llvosurfacepatch.h +++ b/indra/newview/llvosurfacepatch.h @@ -57,6 +57,7 @@ public:      /*virtual*/ void        updateFaceSize(S32 idx);      void getTerrainGeometry(LLStrider<LLVector3> &verticesp,                                  LLStrider<LLVector3> &normalsp, +                                LLStrider<LLVector2> &texCoords0p,                                  LLStrider<LLVector2> &texCoords1p,                                  LLStrider<U16> &indicesp); @@ -109,18 +110,21 @@ protected:      void updateMainGeometry(LLFace *facep,                         LLStrider<LLVector3> &verticesp,                         LLStrider<LLVector3> &normalsp, +                       LLStrider<LLVector2> &texCoords0p,                         LLStrider<LLVector2> &texCoords1p,                         LLStrider<U16> &indicesp,                         U32 &index_offset);      void updateNorthGeometry(LLFace *facep,                         LLStrider<LLVector3> &verticesp,                         LLStrider<LLVector3> &normalsp, +                       LLStrider<LLVector2> &texCoords0p,                         LLStrider<LLVector2> &texCoords1p,                         LLStrider<U16> &indicesp,                         U32 &index_offset);      void updateEastGeometry(LLFace *facep,                         LLStrider<LLVector3> &verticesp,                         LLStrider<LLVector3> &normalsp, +                       LLStrider<LLVector2> &texCoords0p,                         LLStrider<LLVector2> &texCoords1p,                         LLStrider<U16> &indicesp,                         U32 &index_offset); diff --git a/indra/newview/llwearableitemslist.cpp b/indra/newview/llwearableitemslist.cpp index 8ce1a745c3..c708e804b2 100644 --- a/indra/newview/llwearableitemslist.cpp +++ b/indra/newview/llwearableitemslist.cpp @@ -33,7 +33,6 @@  #include "llagentwearables.h"  #include "llappearancemgr.h" -#include "llinventoryfunctions.h"  #include "llinventoryicon.h"  #include "llgesturemgr.h"  #include "lltransutil.h" @@ -41,15 +40,6 @@  #include "llviewermenu.h"  #include "llvoavatarself.h" -class LLFindOutfitItems : public LLInventoryCollectFunctor -{ -public: -    LLFindOutfitItems() {} -    virtual ~LLFindOutfitItems() {} -    virtual bool operator()(LLInventoryCategory* cat, -                            LLInventoryItem* item); -}; -  bool LLFindOutfitItems::operator()(LLInventoryCategory* cat,                                     LLInventoryItem* item)  { diff --git a/indra/newview/llwearableitemslist.h b/indra/newview/llwearableitemslist.h index 3fe1059176..7a5f29020e 100644 --- a/indra/newview/llwearableitemslist.h +++ b/indra/newview/llwearableitemslist.h @@ -32,6 +32,7 @@  #include "llsingleton.h"  // newview +#include "llinventoryfunctions.h"  #include "llinventoryitemslist.h"  #include "llinventorylistitem.h"  #include "lllistcontextmenu.h" @@ -507,4 +508,12 @@ protected:      LLWearableType::EType mMenuWearableType;  }; +class LLFindOutfitItems : public LLInventoryCollectFunctor +{ +public: +    LLFindOutfitItems() {} +    virtual ~LLFindOutfitItems() {} +    virtual bool operator()(LLInventoryCategory* cat, LLInventoryItem* item); +}; +  #endif //LL_LLWEARABLEITEMSLIST_H diff --git a/indra/newview/llworld.cpp b/indra/newview/llworld.cpp index 899733ccc3..47e1815bc2 100644 --- a/indra/newview/llworld.cpp +++ b/indra/newview/llworld.cpp @@ -1372,10 +1372,8 @@ void LLWorld::getAvatars(uuid_vec_t* avatar_ids, std::vector<LLVector3d>* positi  F32 LLWorld::getNearbyAvatarsAndMaxGPUTime(std::vector<LLVOAvatar*> &valid_nearby_avs)  { -    static LLCachedControl<F32> render_far_clip(gSavedSettings, "RenderFarClip", 64); -      F32 nearby_max_complexity = 0; -    F32 radius = render_far_clip * render_far_clip; +    F32 radius = LLVOAvatar::sRenderDistance * LLVOAvatar::sRenderDistance;      for (LLCharacter* character : LLCharacter::sInstances)      { diff --git a/indra/newview/skins/default/xui/da/floater_about.xml b/indra/newview/skins/default/xui/da/floater_about.xml index 604eb7c58f..4ea34975e1 100644 --- a/indra/newview/skins/default/xui/da/floater_about.xml +++ b/indra/newview/skins/default/xui/da/floater_about.xml @@ -5,7 +5,7 @@  [[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]]  	</floater.string>  	<floater.string name="AboutPosition"> -		Du er ved [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] i regionen [REGION] lokaliseret ved <nolink>[HOSTNAME]</nolink> ([HOSTIP]) +		Du er ved [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] i regionen [REGION] lokaliseret ved <nolink>[HOSTNAME]</nolink>  [SERVER_VERSION]  [SERVER_RELEASE_NOTES_URL]  	</floater.string> diff --git a/indra/newview/skins/default/xui/de/strings.xml b/indra/newview/skins/default/xui/de/strings.xml index 1a3f00a29e..e9ed7f4949 100644 --- a/indra/newview/skins/default/xui/de/strings.xml +++ b/indra/newview/skins/default/xui/de/strings.xml @@ -12,7 +12,7 @@  	<string name="StartupRequireDriverUpdate">Grafikinitialisierung fehlgeschlagen. Bitte aktualisieren Sie Ihren Grafiktreiber.</string>  	<string name="AboutHeader">[CHANNEL] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([ADDRESS_SIZE]Bit) [[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]]</string>  	<string name="BuildConfig">Build-Konfiguration [BUILD_CONFIG]</string> -	<string name="AboutPosition">Sie befinden sich an [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] in [REGION] auf <nolink>[HOSTNAME]</nolink> ([HOSTIP]) +	<string name="AboutPosition">Sie befinden sich an [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] in [REGION] auf <nolink>[HOSTNAME]</nolink>  SLURL: <nolink>[SLURL]</nolink>  (globale Koordinaten [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1])  [SERVER_VERSION] diff --git a/indra/newview/skins/default/xui/en/floater_snapshot.xml b/indra/newview/skins/default/xui/en/floater_snapshot.xml index e6b780728c..acdccdc03a 100644 --- a/indra/newview/skins/default/xui/en/floater_snapshot.xml +++ b/indra/newview/skins/default/xui/en/floater_snapshot.xml @@ -167,8 +167,19 @@           left="30"  		 height="16"           top_pad="8" -         width="180" +         width="80" +         control_name="RenderUIInSnapshot"           name="ui_check" /> +       <check_box +         label="L$ Balance" +         layout="topleft" +         left_pad="16" +         height="16" +         top_delta="0" +         width="80" +         control_name="RenderBalanceInSnapshot" +         enabled_control="RenderUIInSnapshot" +         name="balance_check" />          <check_box           label="HUDs"           layout="topleft" @@ -176,6 +187,7 @@           left="30"           top_pad="1"           width="180" +         control_name="RenderHUDInSnapshot"           name="hud_check" />          <check_box           label="Freeze frame (fullscreen)" diff --git a/indra/newview/skins/default/xui/en/menu_inventory.xml b/indra/newview/skins/default/xui/en/menu_inventory.xml index e57e3b0750..d8c7de0e55 100644 --- a/indra/newview/skins/default/xui/en/menu_inventory.xml +++ b/indra/newview/skins/default/xui/en/menu_inventory.xml @@ -152,6 +152,14 @@           parameter="category" />      </menu_item_call>      <menu_item_call +     label="New Folder" +     layout="topleft" +     name="New Outfit Folder"> +        <menu_item_call.on_click +         function="Inventory.DoCreate" +         parameter="category" /> +    </menu_item_call> +    <menu_item_call       label="New Outfit"       layout="topleft"       name="New Outfit"> diff --git a/indra/newview/skins/default/xui/en/panel_settings_water.xml b/indra/newview/skins/default/xui/en/panel_settings_water.xml index 5e65b0e8a2..e062f1710b 100644 --- a/indra/newview/skins/default/xui/en/panel_settings_water.xml +++ b/indra/newview/skins/default/xui/en/panel_settings_water.xml @@ -378,7 +378,7 @@                              initial_value="0"                              layout="topleft"                              left_delta="5" -                            min_val="-0.5" +                            min_val="0"                              max_val="0.5"                              name="water_blur_multip"                              top_pad="5" diff --git a/indra/newview/skins/default/xui/en/panel_tools_texture.xml b/indra/newview/skins/default/xui/en/panel_tools_texture.xml index 9a19d06432..af6a9b94d9 100644 --- a/indra/newview/skins/default/xui/en/panel_tools_texture.xml +++ b/indra/newview/skins/default/xui/en/panel_tools_texture.xml @@ -729,8 +729,8 @@               label_width="205"               layout="topleft"               left="10" -             min_val="-100" -             max_val="100" +             min_val="-10000" +             max_val="10000"               name="TexScaleU"               top_pad="5"               width="265" /> @@ -742,8 +742,8 @@               label_width="205"               layout="topleft"               left="10" -             min_val="-100" -             max_val="100" +             min_val="-10000" +             max_val="10000"               name="TexScaleV"               width="265" />              <spinner @@ -805,8 +805,8 @@               label_width="205"               layout="topleft"               left="10" -             min_val="-100" -             max_val="100" +             min_val="-10000" +             max_val="10000"               name="bumpyScaleU"               top_delta="-115"               width="265" /> @@ -818,8 +818,8 @@               label_width="205"               layout="topleft"               left="10" -             min_val="-100" -             max_val="100" +             min_val="-10000" +             max_val="10000"               name="bumpyScaleV"               width="265" />             <spinner @@ -869,8 +869,8 @@               label_width="205"               layout="topleft"               left="10" -             min_val="-100" -             max_val="100" +             min_val="-10000" +             max_val="10000"               name="shinyScaleU"               top_delta="-115"               width="265" /> @@ -882,8 +882,8 @@               label_width="205"               layout="topleft"               left="10" -             min_val="-100" -             max_val="100" +             min_val="-10000" +             max_val="10000"               name="shinyScaleV"               width="265" />             <spinner diff --git a/indra/newview/skins/default/xui/en/strings.xml b/indra/newview/skins/default/xui/en/strings.xml index 9102a30e1d..faa751bbf1 100644 --- a/indra/newview/skins/default/xui/en/strings.xml +++ b/indra/newview/skins/default/xui/en/strings.xml @@ -13,7 +13,6 @@  	<string name="SUPPORT_SITE">Second Life Support Portal</string>  	<!-- starting up --> -	<string name="StartupDetectingHardware">Detecting hardware...</string>  	<string name="StartupLoading">Loading [APP_NAME]...</string>  	<string name="StartupClearingCache">Clearing cache...</string>  	<string name="StartupInitializingTextureCache">Initializing texture cache...</string> @@ -259,6 +258,7 @@ If you feel this is an error, please contact support@secondlife.com</string>  	<string name="TooltipOutboxMixedStock">All items in a stock folder must have the same type and permission</string>  	<string name="TooltipOutfitNotInInventory">You can only put items or outfits from your personal inventory into "My outfits"</string>  	<string name="TooltipCantCreateOutfit">One or more items can't be used inside "My outfits"</string> +    <string name="TooltipCantMoveOutfitIntoOutfit">Can not move an outfit into another outfit</string>  	<string name="TooltipDragOntoOwnChild">You can't move a folder into its child</string>  	<string name="TooltipDragOntoSelf">You can't move a folder into itself</string> diff --git a/indra/newview/skins/default/xui/es/strings.xml b/indra/newview/skins/default/xui/es/strings.xml index 97e86e994c..93b34e3cca 100644 --- a/indra/newview/skins/default/xui/es/strings.xml +++ b/indra/newview/skins/default/xui/es/strings.xml @@ -10,7 +10,7 @@  	<string name="AboutHeader">[CHANNEL] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([ADDRESS_SIZE]bit)   [[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]]</string>  	<string name="BuildConfig">Configuración de constitución [BUILD_CONFIG]</string> -	<string name="AboutPosition">Estás en la posición [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1], de [REGION], alojada en <nolink>[HOSTNAME]</nolink> ([HOSTIP]) +	<string name="AboutPosition">Estás en la posición [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1], de [REGION], alojada en <nolink>[HOSTNAME]</nolink>  SLURL: <nolink>[SLURL]</nolink>  (coordenadas globales [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1])  [SERVER_VERSION] diff --git a/indra/newview/skins/default/xui/fr/strings.xml b/indra/newview/skins/default/xui/fr/strings.xml index 60916ef92b..c929226c43 100644 --- a/indra/newview/skins/default/xui/fr/strings.xml +++ b/indra/newview/skins/default/xui/fr/strings.xml @@ -13,7 +13,7 @@  	<string name="AboutHeader">[CHANNEL] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([ADDRESS_SIZE]bit)   [[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]]</string>  	<string name="BuildConfig">Configuration de la construction [BUILD_CONFIG]</string> -	<string name="AboutPosition">Vous êtes à [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] dans [REGION], se trouvant à <nolink>[HOSTNAME]</nolink> ([HOSTIP]) +	<string name="AboutPosition">Vous êtes à [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] dans [REGION], se trouvant à <nolink>[HOSTNAME]</nolink>  SLURL : <nolink>[SLURL]</nolink>  (coordonnées globales [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1])  [SERVER_VERSION] diff --git a/indra/newview/skins/default/xui/it/strings.xml b/indra/newview/skins/default/xui/it/strings.xml index 88708a2b4d..d279f62d12 100644 --- a/indra/newview/skins/default/xui/it/strings.xml +++ b/indra/newview/skins/default/xui/it/strings.xml @@ -12,7 +12,7 @@  	<string name="AboutHeader">[CHANNEL] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([ADDRESS_SIZE]bit)   [[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]]</string>  	<string name="BuildConfig">Configurazione struttura [BUILD_CONFIG]</string> -	<string name="AboutPosition">Tu sei a [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] in [REGION] che si trova a <nolink>[HOSTNAME]</nolink> ([HOSTIP]) +	<string name="AboutPosition">Tu sei a [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] in [REGION] che si trova a <nolink>[HOSTNAME]</nolink>  SLURL: <nolink>[SLURL]</nolink>  (coordinate globali [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1])  [SERVER_VERSION] diff --git a/indra/newview/skins/default/xui/ja/panel_settings_water.xml b/indra/newview/skins/default/xui/ja/panel_settings_water.xml index ead1ca9b2f..2510523897 100644 --- a/indra/newview/skins/default/xui/ja/panel_settings_water.xml +++ b/indra/newview/skins/default/xui/ja/panel_settings_water.xml @@ -63,7 +63,7 @@  					<text follows="left|top|right" font="SansSerif" height="16" layout="topleft" left_delta="-5" top_pad="5" width="215">  						ブラー乗数  					</text> -					<slider control_name="water_blur_multip" follows="left|top" height="16" increment="0.001" initial_value="0" layout="topleft" left_delta="5" min_val="-0.5" max_val="0.5" name="water_blur_multip" top_pad="5" width="200" can_edit_text="true"/> +					<slider control_name="water_blur_multip" follows="left|top" height="16" increment="0.001" initial_value="0" layout="topleft" left_delta="5" min_val="0" max_val="0.5" name="water_blur_multip" top_pad="5" width="200" can_edit_text="true"/>  				</layout_panel>  			</layout_stack>  		</layout_panel> diff --git a/indra/newview/skins/default/xui/ja/strings.xml b/indra/newview/skins/default/xui/ja/strings.xml index abc5932943..7d1cf9d146 100644 --- a/indra/newview/skins/default/xui/ja/strings.xml +++ b/indra/newview/skins/default/xui/ja/strings.xml @@ -39,7 +39,7 @@  	</string>  	<string name="AboutPosition">  		あなたは、現在[REGION]の[POSITION_LOCAL_0,number,1],[POSITION_LOCAL_1,number,1],[POSITION_LOCAL_2,number,1]にいます。 -位置は、<nolink>[HOSTNAME]</nolink>です。([HOSTIP]) +位置は、<nolink>[HOSTNAME]</nolink>です。  SLURL:<nolink>[SLURL]</nolink>  (グローバル座標は、[POSITION_0,number,1],[POSITION_1,number,1],[POSITION_2,number,1]です。)  [SERVER_VERSION] diff --git a/indra/newview/skins/default/xui/pt/strings.xml b/indra/newview/skins/default/xui/pt/strings.xml index 9e66777b5a..ccd0336ed1 100644 --- a/indra/newview/skins/default/xui/pt/strings.xml +++ b/indra/newview/skins/default/xui/pt/strings.xml @@ -10,7 +10,7 @@  	<string name="AboutHeader">[CHANNEL] [VIEWER_VERSION_0].[VIEWER_VERSION_1].[VIEWER_VERSION_2].[VIEWER_VERSION_3] ([ADDRESS_SIZE]bit)   [[VIEWER_RELEASE_NOTES_URL] [ReleaseNotes]]</string>  	<string name="BuildConfig">Configuração do corpo [BUILD_CONFIG]</string> -	<string name="AboutPosition">Você está em [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] em [REGION] localizado em <nolink>[HOSTNAME]</nolink> ([HOSTIP]) +	<string name="AboutPosition">Você está em [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] em [REGION] localizado em <nolink>[HOSTNAME]</nolink>  SLURL: <nolink>[SLURL]</nolink>  (coordenadas globais [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1])  [SERVER_VERSION] diff --git a/indra/newview/skins/default/xui/ru/strings.xml b/indra/newview/skins/default/xui/ru/strings.xml index 174999ea36..e542f7c4ef 100644 --- a/indra/newview/skins/default/xui/ru/strings.xml +++ b/indra/newview/skins/default/xui/ru/strings.xml @@ -42,7 +42,7 @@  		Конфигурация построения [BUILD_CONFIG]  	</string>  	<string name="AboutPosition"> -		Вы в точке [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] в регионе «[REGION]», расположенном на <nolink>[HOSTNAME]</nolink> ([HOSTIP]) +		Вы в точке [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] в регионе «[REGION]», расположенном на <nolink>[HOSTNAME]</nolink>  SLURL: <nolink>[SLURL]</nolink>  (глобальные координаты [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1])  [SERVER_VERSION] diff --git a/indra/newview/skins/default/xui/tr/strings.xml b/indra/newview/skins/default/xui/tr/strings.xml index 6c1f6506a2..67df275895 100644 --- a/indra/newview/skins/default/xui/tr/strings.xml +++ b/indra/newview/skins/default/xui/tr/strings.xml @@ -42,7 +42,7 @@  		Yapı Konfigürasyonu [BUILD_CONFIG]  	</string>  	<string name="AboutPosition"> -		<nolink>[HOSTNAME]</nolink> ([HOSTIP]) üzerinde bulunan [REGION] içerisinde [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] konumundasınız +		<nolink>[HOSTNAME]</nolink> üzerinde bulunan [REGION] içerisinde [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1] konumundasınız  SLURL: <nolink>[SLURL]</nolink>  (küresel koordinatlar [POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1])  [SERVER_VERSION] diff --git a/indra/newview/skins/default/xui/zh/strings.xml b/indra/newview/skins/default/xui/zh/strings.xml index 59ba2a7e19..dee48b3d58 100644 --- a/indra/newview/skins/default/xui/zh/strings.xml +++ b/indra/newview/skins/default/xui/zh/strings.xml @@ -42,7 +42,7 @@  		建製設置 [BUILD_CONFIG]  	</string>  	<string name="AboutPosition"> -		你的方位是 [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1],地區名:[REGION],主機:<nolink>[HOSTNAME]</nolink> ([HOSTIP]) +		你的方位是 [POSITION_LOCAL_0,number,1], [POSITION_LOCAL_1,number,1], [POSITION_LOCAL_2,number,1],地區名:[REGION],主機:<nolink>[HOSTNAME]</nolink>  第二人生URL:<nolink>[SLURL]</nolink>  (全域坐標:[POSITION_0,number,1], [POSITION_1,number,1], [POSITION_2,number,1])  [SERVER_VERSION] | 
